Import VBCC source snapshot (29/04/2022)
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..28dca08
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,309 @@
+
+# used to create vbcc, vc and ucpp
+CC = gcc -std=c9x -g -DHAVE_AOS4 #-fsanitize=address #-DHAVE_ECPP -DHAVE_MISRA
+LDFLAGS = -lm
+
+# native version; used to create dtgen
+NCC = $(CC)
+NLDFLAGS = $(LDFLAGS)
+
+all: bin/vc bin/vprof bin/vbcc$(TARGET) #bin/vcpp
+
+vbccs: bin/vbccs$(TARGET)
+
+bin/vc: frontend/vc.c
+ $(CC) frontend/vc.c -o bin/vc $(LDFLAGS)
+
+bin/vprof: vprof/vprof.c
+ $(CC) vprof/vprof.c -o bin/vprof $(LDFLAGS)
+
+doc/vbcc.pdf:
+ texi2dvi --pdf doc/vbcc.texi
+ rm -f vbcc.cp vbcc.fn vbcc.vr vbcc.tp vbcc.ky vbcc.pg vbcc.toc \
+ vbcc.aux vbcc.log
+
+doc/vbcc.html:
+ (cd doc;texi2html -split=chapter -nosec_nav -frames vbcc.texi)
+ sed -e s/vbcc_13/vbcc_1/ <doc/vbcc_frame.html >doc/vbcc.html
+
+vcppobjs = vcpp/cpp.o vcpp/eval.o vcpp/getopt.o vcpp/hideset.o vcpp/include.o \
+ vcpp/lex.o vcpp/macro.o vcpp/nlist.o vcpp/tokens.o vcpp/unix.o
+
+_vbcc.tar.gz:
+ -(cd ..;tar zcvf vbcc.tar.gz --exclude=*/dt.c --exclude=*/dt.h vbcc/Makefile vbcc/bin/.dummy vbcc/*.[ch] vbcc/datatypes/*.[ch] vbcc/doc/*.texi vbcc/frontend/vc.c vbcc/machines/*/*.[ch] vbcc/machines/*/machine.dt vbcc/machines/*/schedule.[ch] vbcc/machines/*/compress.[ch] vbcc/ucpp/*.[ch] vbcc/ucpp/README vbcc/vprof/vprof.c vbcc/vsc/vsc.[ch] vbcc/vcpr/vcpr.[ch])
+
+bin/osekrm: osekrm.c
+ $(CC) osekrm.c -o bin/osekrm
+
+dist: bin/osekrm
+ mv supp.h t1
+ mv supp.c t2
+ mv main.c t3
+ mv machines/ppc/machine.c t4
+ mv declaration.c t5
+ mv flow.c t6
+ mv ic.c t7
+ mv parse_expr.c t8
+ mv statements.c t9
+ mv rd.c t10
+ mv type_expr.c t11
+ bin/osekrm <t1 >supp.h
+ bin/osekrm <t2 >supp.c
+ bin/osekrm <t3 >main.c
+ bin/osekrm <t4 >machines/ppc/machine.c
+ bin/osekrm <t5 >declaration.c
+ bin/osekrm <t6 >flow.c
+ bin/osekrm <t7 >ic.c
+ bin/osekrm <t8 >parse_expr.c
+ bin/osekrm <t9 >statements.c
+ bin/osekrm <t10 >rd.c
+ bin/osekrm <t11 >type_expr.c
+ make _vbcc.tar.gz
+ mv t1 supp.h
+ mv t2 supp.c
+ mv t3 main.c
+ mv t4 machines/ppc/machine.c
+ mv t5 declaration.c
+ mv t6 flow.c
+ mv t7 ic.c
+ mv t8 parse_expr.c
+ mv t9 statements.c
+ mv t10 rd.c
+ mv t11 type_expr.c
+
+bin/vcpp: $(vcppobjs)
+ $(CC) $(LDFLAGS) $(vcppobjs) -o bin/vcpp
+
+vcpp/cpp.o: vcpp/cpp.c vcpp/cpp.h
+ $(CC) -c -Ivcpp vcpp/cpp.c -o vcpp/cpp.o
+
+vcpp/eval.o: vcpp/eval.c vcpp/cpp.h
+ $(CC) -c -Ivcpp vcpp/eval.c -o vcpp/eval.o
+
+vcpp/getopt.o: vcpp/getopt.c
+ $(CC) -c -Ivcpp vcpp/getopt.c -o vcpp/getopt.o
+
+vcpp/hideset.o: vcpp/hideset.c vcpp/cpp.h
+ $(CC) -c -Ivcpp vcpp/hideset.c -o vcpp/hideset.o
+
+vcpp/include.o: vcpp/include.c vcpp/cpp.h
+ $(CC) -c -Ivcpp vcpp/include.c -o vcpp/include.o
+
+vcpp/lex.o: vcpp/lex.c vcpp/cpp.h
+ $(CC) -c -Ivcpp vcpp/lex.c -o vcpp/lex.o
+
+vcpp/macro.o: vcpp/macro.c vcpp/cpp.h
+ $(CC) -c -Ivcpp vcpp/macro.c -o vcpp/macro.o
+
+vcpp/nlist.o: vcpp/nlist.c vcpp/cpp.h
+ $(CC) -c -Ivcpp vcpp/nlist.c -o vcpp/nlist.o
+
+vcpp/tokens.o: vcpp/tokens.c vcpp/cpp.h
+ $(CC) -c -Ivcpp vcpp/tokens.c -o vcpp/tokens.o
+
+vcpp/unix.o: vcpp/unix.c vcpp/cpp.h
+ $(CC) -c -Ivcpp vcpp/unix.c -o vcpp/unix.o
+
+TRGDIR = machines/$(TARGET)
+
+bobjects = $(TRGDIR)/main.o $(TRGDIR)/vars.o $(TRGDIR)/declaration.o \
+ $(TRGDIR)/parse_expr.o $(TRGDIR)/type_expr.o $(TRGDIR)/ic.o \
+ $(TRGDIR)/machine.o $(TRGDIR)/statements.o \
+ $(TRGDIR)/supp.o $(TRGDIR)/dt.o \
+ $(TRGDIR)/assert.o $(TRGDIR)/cpp.o $(TRGDIR)/hash.o \
+ $(TRGDIR)/lexer.o $(TRGDIR)/macro.o $(TRGDIR)/mem.o \
+ $(TRGDIR)/eval.o
+# $(TRGDIR)/AdjList.o $(TRGDIR)/DUChain.o \
+# $(TRGDIR)/ICodeInsertion.o $(TRGDIR)/NodeList.o \
+# $(TRGDIR)/RAllocMain.o $(TRGDIR)/Web.o
+
+fobjects = $(TRGDIR)/opt.o $(TRGDIR)/av.o $(TRGDIR)/rd.o $(TRGDIR)/regs.o \
+ $(TRGDIR)/flow.o $(TRGDIR)/cse.o $(TRGDIR)/cp.o $(TRGDIR)/loop.o \
+ $(TRGDIR)/alias.o $(TRGDIR)/range.o $(bobjects)
+
+sobjects = $(TRGDIR)/opts.o $(TRGDIR)/regss.o $(bobjects)
+
+tasm = $(TRGDIR)/supp.o $(TRGDIR)/tasm.o $(TRGDIR)/dt.o \
+ $(TRGDIR)/opt.o $(TRGDIR)/av.o $(TRGDIR)/rd.o $(TRGDIR)/regs.o \
+ $(TRGDIR)/flow.o $(TRGDIR)/cse.o $(TRGDIR)/cp.o $(TRGDIR)/loop.o \
+ $(TRGDIR)/alias.o $(TRGDIR)/machine.o
+
+mbasic = $(TRGDIR)/supp.o $(TRGDIR)/mbasic.o $(TRGDIR)/dt.o \
+ $(TRGDIR)/opt.o $(TRGDIR)/av.o $(TRGDIR)/rd.o $(TRGDIR)/regs.o \
+ $(TRGDIR)/flow.o $(TRGDIR)/cse.o $(TRGDIR)/cp.o $(TRGDIR)/loop.o \
+ $(TRGDIR)/alias.o $(TRGDIR)/machine.o
+
+minicomp = $(TRGDIR)/supp.o $(TRGDIR)/minicompg.tab.o $(TRGDIR)/minicomp.o $(TRGDIR)/dt.o \
+ $(TRGDIR)/opt.o $(TRGDIR)/av.o $(TRGDIR)/rd.o $(TRGDIR)/regs.o \
+ $(TRGDIR)/flow.o $(TRGDIR)/cse.o $(TRGDIR)/cp.o $(TRGDIR)/loop.o \
+ $(TRGDIR)/alias.o $(TRGDIR)/machine.o
+
+vscobjects = $(TRGDIR)/vsc.o $(TRGDIR)/schedule.o
+
+vcprobjects = $(TRGDIR)/vcpr.o $(TRGDIR)/compress.o
+
+bin/vbcc$(TARGET): $(fobjects)
+ $(CC) $(LDFLAGS) $(fobjects) -o bin/vbcc$(TARGET)
+
+bin/vbccs$(TARGET): $(sobjects)
+ $(CC) $(LDFLAGS) $(sobjects) -o bin/vbccs$(TARGET)
+
+bin/vsc$(TARGET): $(vscobjects)
+ $(CC) $(LDFLAGS) $(vscobjects) -o bin/vsc$(TARGET)
+
+bin/vcpr$(TARGET): $(vcprobjects)
+ $(CC) $(LDFLAGS) $(vcprobjects) -o bin/vcpr$(TARGET)
+
+bin/tasm$(TARGET): $(tasm)
+ $(CC) $(LDFLAGS) $(tasm) -o bin/tasm$(TARGET)
+
+bin/mbasic$(TARGET): $(mbasic)
+ $(CC) $(LDFLAGS) $(mbasic) -o bin/mbasic$(TARGET)
+
+bin/minicomp$(TARGET): $(minicomp)
+ $(CC) $(LDFLAGS) $(minicomp) -o bin/minicomp$(TARGET)
+
+bin/dtgen: datatypes/dtgen.c datatypes/datatypes.h datatypes/dtconv.h
+ $(NCC) datatypes/dtgen.c -o bin/dtgen -Idatatypes $(NLDFLAGS)
+
+$(TRGDIR)/dt.h: bin/dtgen $(TRGDIR)/machine.dt
+ bin/dtgen $(TRGDIR)/machine.dt $(TRGDIR)/dt.h $(TRGDIR)/dt.c
+
+$(TRGDIR)/dt.c: bin/dtgen $(TRGDIR)/machine.dt
+ bin/dtgen $(TRGDIR)/machine.dt $(TRGDIR)/dt.h $(TRGDIR)/dt.c
+
+$(TRGDIR)/dt.o: $(TRGDIR)/dt.h $(TRGDIR)/dt.c
+ $(CC) -c $(TRGDIR)/dt.c -o $(TRGDIR)/dt.o -I$(TRGDIR) -Idatatypes
+
+$(TRGDIR)/tasm.o: tasm.c supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c tasm.c -o $(TRGDIR)/tasm.o -I$(TRGDIR)
+
+$(TRGDIR)/mbasic.o: mbasic.c supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c mbasic.c -o $(TRGDIR)/mbasic.o -I$(TRGDIR)
+
+$(TRGDIR)/minicomp.o: minicomp.c minicomp.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c minicomp.c -o $(TRGDIR)/minicomp.o -I$(TRGDIR)
+
+$(TRGDIR)/minicompg.tab.o: minicompg.y minicomplexer.c minicomp.h supp.h
+ bison minicompg.y
+ $(CC) -c minicompg.tab.c -o $(TRGDIR)/minicompg.tab.o -I$(TRGDIR)
+
+$(TRGDIR)/supp.o: supp.c supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c supp.c -o $(TRGDIR)/supp.o -I$(TRGDIR)
+
+$(TRGDIR)/main.o: main.c vbc.h supp.h vbcc_cpp.h ucpp/cpp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c main.c -o $(TRGDIR)/main.o -I$(TRGDIR)
+
+$(TRGDIR)/vars.o: vars.c vbc.h supp.h $(TRGDIR)/machine.h errors.h $(TRGDIR)/dt.h
+ $(CC) -c vars.c -o $(TRGDIR)/vars.o -I$(TRGDIR)
+
+$(TRGDIR)/declaration.o: declaration.c vbc.h supp.h vbcc_cpp.h ucpp/cpp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c declaration.c -o $(TRGDIR)/declaration.o -I$(TRGDIR)
+
+$(TRGDIR)/parse_expr.o: parse_expr.c vbc.h supp.h vbcc_cpp.h ucpp/cpp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c parse_expr.c -o $(TRGDIR)/parse_expr.o -I$(TRGDIR)
+
+$(TRGDIR)/type_expr.o: type_expr.c vbc.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c type_expr.c -o $(TRGDIR)/type_expr.o -I$(TRGDIR)
+
+$(TRGDIR)/ic.o: ic.c vbc.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c ic.c -o $(TRGDIR)/ic.o -I$(TRGDIR)
+
+$(TRGDIR)/statements.o: statements.c vbc.h supp.h vbcc_cpp.h ucpp/cpp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c statements.c -o $(TRGDIR)/statements.o -I$(TRGDIR)
+
+$(TRGDIR)/opt.o: opt.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c opt.c -o $(TRGDIR)/opt.o -I$(TRGDIR)
+
+$(TRGDIR)/av.o: av.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c av.c -o $(TRGDIR)/av.o -I$(TRGDIR)
+
+$(TRGDIR)/rd.o: rd.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c rd.c -o $(TRGDIR)/rd.o -I$(TRGDIR)
+
+$(TRGDIR)/regs.o: regs.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c regs.c -o $(TRGDIR)/regs.o -I$(TRGDIR)
+
+$(TRGDIR)/flow.o: flow.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c flow.c -o $(TRGDIR)/flow.o -I$(TRGDIR)
+
+$(TRGDIR)/cse.o: cse.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c cse.c -o $(TRGDIR)/cse.o -I$(TRGDIR)
+
+$(TRGDIR)/cp.o: cp.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c cp.c -o $(TRGDIR)/cp.o -I$(TRGDIR)
+
+$(TRGDIR)/loop.o: loop.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c loop.c -o $(TRGDIR)/loop.o -I$(TRGDIR)
+
+$(TRGDIR)/alias.o: alias.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c alias.c -o $(TRGDIR)/alias.o -I$(TRGDIR)
+
+$(TRGDIR)/range.o: range.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c range.c -o $(TRGDIR)/range.o -I$(TRGDIR)
+
+$(TRGDIR)/preproc.o: preproc.c vbpp.h supp.h vbc.h $(TRGDIR)/dt.h
+ $(CC) -c preproc.c -o $(TRGDIR)/preproc.o -I$(TRGDIR)
+
+$(TRGDIR)/assert.o: ucpp/assert.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+ $(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/assert.c -o $(TRGDIR)/assert.o -I$(TRGDIR)
+
+$(TRGDIR)/cpp.o: ucpp/cpp.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+ $(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/cpp.c -o $(TRGDIR)/cpp.o -I$(TRGDIR)
+
+$(TRGDIR)/hash.o: ucpp/hash.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+ $(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/hash.c -o $(TRGDIR)/hash.o -I$(TRGDIR)
+
+$(TRGDIR)/lexer.o: ucpp/lexer.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+ $(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/lexer.c -o $(TRGDIR)/lexer.o -I$(TRGDIR)
+
+$(TRGDIR)/macro.o: ucpp/macro.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+ $(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/macro.c -o $(TRGDIR)/macro.o -I$(TRGDIR)
+
+$(TRGDIR)/mem.o: ucpp/mem.c ucpp/cpp.h ucpp/mem.h ucpp/hash.h ucpp/tune.h $(TRGDIR)/dt.h
+ $(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/mem.c -o $(TRGDIR)/mem.o -I$(TRGDIR)
+
+$(TRGDIR)/eval.o: ucpp/eval.c ucpp/cpp.h ucpp/mem.h ucpp/tune.h $(TRGDIR)/dt.h
+ $(CC) -DNO_UCPP_ERROR_FUNCTIONS -c ucpp/eval.c -o $(TRGDIR)/eval.o -I$(TRGDIR)
+
+$(TRGDIR)/machine.o: $(TRGDIR)/machine.c supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h dwarf2.c
+ $(CC) -c $(TRGDIR)/machine.c -o $(TRGDIR)/machine.o -I$(TRGDIR) -I.
+
+$(TRGDIR)/opts.o: opt.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c -DNO_OPTIMIZER opt.c -o $(TRGDIR)/opts.o -I$(TRGDIR)
+
+$(TRGDIR)/regss.o: regs.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c -DNO_OPTIMIZER regs.c -o $(TRGDIR)/regss.o -I$(TRGDIR)
+
+$(TRGDIR)/vsc.o: vsc/vsc.h vsc/vsc.c $(TRGDIR)/schedule.h
+ $(CC) -c vsc/vsc.c -o $(TRGDIR)/vsc.o -I$(TRGDIR)
+
+$(TRGDIR)/schedule.o: vsc/vsc.h $(TRGDIR)/schedule.h $(TRGDIR)/schedule.c
+ $(CC) -c $(TRGDIR)/schedule.c -o $(TRGDIR)/schedule.o -I$(TRGDIR) -Ivsc
+
+$(TRGDIR)/vcpr.o: vcpr/vcpr.h vcpr/vcpr.c
+ $(CC) -c vcpr/vcpr.c -o $(TRGDIR)/vcpr.o -I$(TRGDIR)
+
+$(TRGDIR)/compress.o: vcpr/vcpr.h $(TRGDIR)/compress.c
+ $(CC) -c $(TRGDIR)/compress.c -o $(TRGDIR)/compress.o -I$(TRGDIR) -Ivcpr
+
+
+
+# Graph coloring register allocator by Alex
+$(TRGDIR)/AdjList.o: GCRegAlloc/AdjList.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c GCRegAlloc/AdjList.c -o $(TRGDIR)/AdjList.o -IGCRegAlloc -I$(TRGDIR)
+
+$(TRGDIR)/DUChain.o: GCRegAlloc/DUChain.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c GCRegAlloc/DUChain.c -o $(TRGDIR)/DUChain.o -IGCRegAlloc -I$(TRGDIR)
+
+$(TRGDIR)/ICodeInsertion.o: GCRegAlloc/ICodeInsertion.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c GCRegAlloc/ICodeInsertion.c -o $(TRGDIR)/ICodeInsertion.o -IGCRegAlloc -I$(TRGDIR)
+
+$(TRGDIR)/NodeList.o: GCRegAlloc/NodeList.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c GCRegAlloc/NodeList.c -o $(TRGDIR)/NodeList.o -IGCRegAlloc -I$(TRGDIR)
+
+$(TRGDIR)/RAllocMain.o: GCRegAlloc/RAllocMain.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c GCRegAlloc/RAllocMain.c -o $(TRGDIR)/RAllocMain.o -IGCRegAlloc -I$(TRGDIR)
+
+$(TRGDIR)/Web.o: GCRegAlloc/Web.c opt.h supp.h $(TRGDIR)/machine.h $(TRGDIR)/dt.h
+ $(CC) -c GCRegAlloc/Web.c -o $(TRGDIR)/Web.o -IGCRegAlloc -I$(TRGDIR)
diff --git a/alias.c b/alias.c
new file mode 100644
index 0000000..f0a942e
--- /dev/null
+++ b/alias.c
@@ -0,0 +1,822 @@
+/* $VER: vbcc (alias.c) $Revision: 1.6 $ */
+/* Listen benutzter/veraenderter Variablen und Behandlung von Decknamen. */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+static bvtype **gpt;
+
+static unsigned long ptsize;
+
+#define is_restrict(i) ((i)<=vcount-rcount&&(vilist[i]->vtyp->flags&RESTRICT))
+
+/* sets points-to-info for var i to undefined */
+void undef_pt(bvtype **pt,int i)
+{
+ if(i<0||i>=vcount) ierror(0);
+ if(pt[i]) ptsize-=vsize;
+ free(pt[i]);
+ pt[i]=0;
+ if(i<rcount){
+ i+=vcount-rcount;
+ if(pt[i]) ptsize-=vsize;
+ free(pt[i]);
+ pt[i]=0;
+ }
+}
+
+/* walks through a clist and sets the corresponding bit in bv
+ for every variable whose address is contained in the clist */
+void add_clist_refs(bvtype *bv,type *t,const_list *cl)
+{
+ /*FIXME: bei Aufrufen auch auf locale, nicht USEDASDEST|USEDASADDR */
+ int i;zmax sz;
+ if(ISARRAY(t->flags)){
+ for(sz=l2zm(0L);!zmleq(t->size,sz)&&cl;sz=zmadd(sz,l2zm(1L)),cl=cl->next){
+ if(!cl->other){ierror(0);return;}
+ add_clist_refs(bv,t->next,cl->other);
+ }
+ return;
+ }
+ if(ISUNION(t->flags)){
+ add_clist_refs(bv,(*t->exact->sl)[0].styp,cl);
+ return;
+ }
+ if(ISSTRUCT(t->flags)){
+ type *st;
+ for(i=0;i<t->exact->count&&cl;i++){
+ if(!cl->other){ierror(0);return;}
+ st=(*t->exact->sl)[i].styp;
+ if(!(*t->exact->sl)[i].identifier) ierror(0);
+ if((*t->exact->sl)[i].identifier[0]){
+ add_clist_refs(bv,st,cl->other);
+ cl=cl->next;
+ }
+ }
+ return;
+ }
+ if(cl->tree&&(cl->tree->o.flags&VARADR)){
+ /* careful: variable might not have a valid index if it is not
+ used within the function optimized */
+ i=cl->tree->o.v->index;
+ if(i>=0&&i<vcount-rcount&&vilist[i]==cl->tree->o.v){
+ /*printf("add %s\n",vilist[i]->identifier);*/
+ BSET(bv,i);
+ }
+ }
+}
+
+/* copies points-to-info for one var to another */
+void copy_pt(bvtype **pt,int to,int from)
+{
+ if(to<0||to>=vcount) ierror(0);
+ if(from<0||from>=vcount) ierror(0);
+ if(!pt[from]){
+ if(from>=vcount-rcount&&pt[from-(vcount-rcount)]){
+ /* if dref check, whether from only points to initialized const */
+ int i;bvtype *new;
+ for(i=0;i<vcount;i++){
+ if(BTST(pt[from-(vcount-rcount)],i)){
+ Var *v=vilist[i];
+ if(!is_const(v->vtyp)||!v->clist||(v->storage_class!=STATIC&&v->storage_class!=EXTERN))
+ break;
+ }
+ }
+ if(i==vcount){
+ /* yes, take the points-to-info from clist */
+ if(!pt[to]||to+vcount-rcount==from){
+ new=mymalloc(vsize);
+ ptsize+=vsize;
+ }else
+ new=pt[to];
+ memset(new,0,vsize);
+ for(i=0;i<vcount;i++){
+ if(BTST(pt[from-(vcount-rcount)],i))
+ add_clist_refs(new,vilist[i]->vtyp,vilist[i]->clist);
+ }
+ if(to+vcount-rcount==from){
+ ptsize-=vsize;
+ free(pt[to]);
+ }
+ pt[to]=new;
+ return;
+ }
+ }
+ undef_pt(pt,to);
+ }else{
+ if(!pt[to]){
+ pt[to]=mymalloc(vsize);
+ ptsize+=vsize;
+ }
+ memcpy(pt[to],pt[from],vsize);
+ }
+}
+
+/* set var i points only to j in points-to-info */
+void set_pt(bvtype **pt,int i,int j)
+{
+ if(i<0||i>=vcount) ierror(0);
+ if(j<0||j>=vcount) ierror(0);
+ if(!pt[i]){
+ pt[i]=mymalloc(vsize);
+ ptsize+=vsize;
+ }
+ memset(pt[i],0,vsize);
+ BSET(pt[i],j);
+}
+
+void print_single_pt(bvtype *pt)
+{
+ int j;
+ if(pt){
+ for(j=0;j<vcount;j++){
+ if(BTST(pt,j))
+ printf(" %s<%s>(%p)\n",(j>=vcount-rcount)?"*":"",vilist[j]->identifier,(void*)vilist[j]);
+ }
+ }else{
+ printf(" (undefined)\n");
+ }
+}
+
+void print_pt(bvtype **pt)
+{
+ int i,j;
+ if(!pt) return;
+ printf("points-to:\n");
+ for(i=0;i<vcount;i++){
+ printf("%s<%s>(%p):\n",(i>=vcount-rcount)?"*":"",vilist[i]->identifier,(void*)vilist[i]);
+ print_single_pt(pt[i]);
+ }
+}
+
+/* creates new points-to-info; every var set to undefined */
+bvtype **new_pt(void)
+{
+ bvtype **pt;
+ int i;
+ pt=mymalloc(vcount*sizeof(*pt));
+ ptsize+=vcount*sizeof(*pt);
+ for(i=0;i<vcount;i++){
+ if(i<rcount&&(vilist[i]->vtyp->flags&RESTRICT)){
+ pt[i]=mymalloc(vsize);
+ ptsize+=vsize;
+ memset(pt[i],0,vsize);
+ BSET(pt[i],i+vcount-rcount);
+ }else
+ pt[i]=0;
+ }
+ return pt;
+}
+
+void free_pt(bvtype **pt)
+{
+ int i;
+ if(pt){
+ for(i=0;i<vcount;i++){
+ if(pt[i]) ptsize-=vsize;
+ free(pt[i]);
+ }
+ ptsize-=vcount*sizeof(*pt);
+ free(pt);
+ }
+}
+
+/* set points-to-info of *v to union of points-to of all vars in the
+ points-to-info of v */
+void dref_pt(bvtype **pt,int i)
+{
+ int j,d;
+ if(i<0||i>=rcount) ierror(0);
+ d=i+vcount-rcount;
+ if(!pt[i]){
+ undef_pt(pt,d);
+ return;
+ }
+ if(!pt[d]){
+ pt[d]=mymalloc(vsize);
+ ptsize+=vsize;
+ }
+ memset(pt[d],0,vsize);
+ for(j=0;j<vcount;j++){
+ if(BTST(pt[i],j)){
+ Var *v=vilist[j];
+ if(v->clist&&is_const(v->vtyp)&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+ add_clist_refs(pt[d],v->vtyp,v->clist);
+ }else if(!pt[j]){
+ undef_pt(pt,d);
+ return;
+ }else
+ bvunite(pt[d],pt[j],vsize);
+ }
+ }
+}
+
+void trans_pt(bvtype **pt,IC *p)
+{
+ int i,j,newset=-1,sv,cp;
+ if((p->code==ADDI2P||p->code==SUBIFP)&&!compare_objs(&p->q1,&p->z,ztyp(p)))
+ return;
+ if((p->z.flags&VAR)&&ISSCALAR(p->z.v->vtyp->flags)){
+ i=p->z.v->index;
+ if(i<0||i>=vcount) ierror(0);
+ if(p->z.flags&DREFOBJ){
+ if(i>=rcount) ierror(0);
+ i+=vcount-rcount;
+ }
+ if(!is_restrict(i)){
+ if(p->code==ASSIGN){
+ newset=i;sv=-1;cp=-1;
+ if(p->q1.flags&VARADR){
+ sv=p->q1.v->index;
+ set_pt(pt,i,p->q1.v->index);
+ }else if(p->q1.flags&VAR){
+ j=p->q1.v->index;
+ if(j<0||j>=vcount) ierror(0);
+ if(p->q1.flags&DREFOBJ){
+ if(j>=rcount) ierror(0);
+ j+=vcount-rcount;
+ }
+ cp=j;
+ copy_pt(pt,i,j);
+ }else{
+ if(!pt[i]){
+ pt[i]=mymalloc(vsize);
+ ptsize+=vsize;
+ }
+ memset(pt[i],0,vsize);
+ }
+ }
+ if(p->code==ADDRESS){
+ newset=i;sv=p->q1.v->index;cp=-1;
+ set_pt(pt,i,p->q1.v->index);
+ }
+ if((p->code==ADDI2P||p->code==SUBIFP)&&(p->q1.flags&VAR)){
+ newset=i;sv=-1;cp=-1;
+ if(p->q1.flags&VARADR){
+ sv=p->q1.v->index;
+ set_pt(pt,i,p->q1.v->index);
+ }else{
+ j=p->q1.v->index;
+ if(j<0||j>=vcount) ierror(0);
+ if(p->q1.flags&DREFOBJ){
+ if(j>=rcount) ierror(0);
+ j+=vcount-rcount;
+ }
+ cp=j;
+ copy_pt(pt,i,j);
+ }
+ }
+ }
+ }
+ if(newset>=0&&newset<rcount){
+ if(newset<0) ierror(0);
+ dref_pt(pt,newset);
+ }
+ for(i=0;i<p->change_cnt;i++){
+ j=p->change_list[i].v->index;
+ if(j<0||j>=vcount) ierror(0);
+ if(p->change_list[i].flags&DREFOBJ){
+ if(j>=rcount) ierror(0);
+ j+=vcount-rcount;
+ }
+ if(j!=newset&&!is_restrict(j)){
+ if(newset>=0&&pt[j]){
+ if(sv>=0){
+ if(sv>=vcount) ierror(0);
+ BSET(pt[j],sv);
+ }
+ if(cp>=0&&pt[cp]){
+ if(cp<0||cp>=vcount) ierror(0);
+ bvunite(pt[j],pt[cp],vsize);
+ }
+ }else
+ undef_pt(pt,j);
+ }
+ }
+}
+
+bvtype **clone_pt(bvtype **pt)
+{
+ int i;
+ bvtype **new;
+ if(!pt)
+ return new_pt();
+ new=mymalloc(vcount*sizeof(*new));
+ ptsize+=vcount*sizeof(*new);
+ for(i=0;i<vcount;i++){
+ if(pt[i]){
+ new[i]=mymalloc(vsize);
+ ptsize+=vsize;
+ memcpy(new[i],pt[i],vsize);
+ }else
+ new[i]=0;
+ }
+ return new;
+}
+
+/* tests if two points-to-infos are identical */
+int equal_pt(bvtype **pt1,bvtype **pt2)
+{
+ int i;
+ if(!pt1&&!pt2)
+ return 1;
+ if(!pt1||!pt2)
+ return 0;
+ for(i=0;i<vcount;i++){
+ if(!pt1[i]&&!pt2[i])
+ continue;
+ if(!pt1[i]||!pt2[i])
+ return 0;
+ if(memcmp(pt1[i],pt2[i],vsize))
+ return 0;
+ }
+ return 1;
+}
+#if 0
+void calc_pt(flowgraph *fg)
+{
+ flowgraph *g;
+ flowlist *in;
+ IC *p;
+ bvtype **pt,**ppt;
+ int i,all_preds,changed;
+
+ changed=1;
+ while(changed){
+ if(DEBUG&1024) printf("calc_pt pass\n");
+ changed=0;
+ for(g=fg;g;g=g->normalout){
+ /* do all predecessors already have points-to-info? */
+ all_preds=1;
+ for(in=g->in;in;in=in->next){
+ if(!in->graph->pt){
+ all_preds=0;
+ break;
+ }
+ }
+ if(all_preds&&g->in){
+ /* calc union of all predecessors */
+ pt=clone_pt(g->in->graph->pt);
+ for(in=g->in->next;in;in=in->next){
+ ppt=in->graph->pt;
+ for(i=0;i<vcount;i++){
+ if(pt[i]){
+ if(!ppt[i])
+ undef_pt(pt,i);
+ else
+ bvunite(pt[i],ppt[i],vsize);
+ }
+ }
+ }
+ }else
+ pt=new_pt();
+ for(p=g->start;p;p=p->next){
+ trans_pt(pt,p);
+ if(p==g->end)
+ break;
+ }
+ if(pt==g->pt) ierror(0);
+ if(!changed){
+ if(!equal_pt(pt,g->pt)){
+ changed=1;
+ free_pt(g->pt);
+ g->pt=pt;
+ }else{
+ free_pt(pt);
+ }
+ }else{
+ free_pt(g->pt);
+ g->pt=pt;
+ }
+ }
+ }
+}
+#endif
+int p_typ(Var *v)
+/* Liefert den Typ, auf den Variable zeigen kann. Falls nicht eindeutig */
+/* wird CHAR zurueckgegeben, da ein char * auf alles zeigen kann. */
+{
+ type *t=v->vtyp;int f;
+ /* Kein Zeiger? Dann moeglicherweise Struktur, die verschiedene Zeiger */
+ /* enthalten koennte. Koennte man evtl. noch genauer pruefen. */
+ if(!ISPOINTER(t->flags)||!t->next||(v->flags&DNOTTYPESAFE)) return CHAR;
+ f=t->next->flags&NQ;
+ if(f==VOID) f=CHAR;
+ return f;
+}
+
+/* propagates information if a variable whose address may have been taken
+ is modified */
+static void propagate_pointers(bvtype *set,Var *v,int t,int i)
+{
+ int j,t2;
+ if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+ if(noaliasopt){
+ bvunite(set,av_drefs,vsize);
+ }else{
+ for(j=0;j<rcount;j++){
+ t2=p_typ(vilist[j]);
+ if(t==t2||t2==CHAR||!ISSCALAR(t)||!ISSCALAR(t2)){
+ if(!gpt||!gpt[j]||(i>=0&&BTST(gpt[j],i)))
+ BSET(set,j+vcount-rcount);
+ }
+ }
+ }
+ }
+}
+void alias_propagate(bvtype *set,int i,int t,int wr)
+{
+ int j,t2;
+ Var *v;
+ if(i<0||i>=vcount) ierror(0);
+ t&=NQ;
+ BSET(set,i);
+ if(wr&&i<rcount) BSET(set,i+vcount-rcount);
+ if(i>=vcount-rcount){
+ /* DREFOBJ */
+ if(noaliasopt||t==CHAR||!ISSCALAR(t)){
+ bvunite(set,av_drefs,vsize);
+ bvunite(set,av_address,vsize);
+ bvunite(set,av_globals,vsize);
+ }else{
+ for(j=0;j<vcount-rcount;j++){
+ v=vilist[j];
+ if(!gpt||!gpt[i-(vcount-rcount)]||BTST(gpt[i-(vcount-rcount)],j)){
+ v=vilist[j];
+ if(!v) ierror(0);
+ if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+ type *tp=v->vtyp;
+ if(!v->vtyp) ierror(0);
+ do{
+ t2=tp->flags&NQ;
+ tp=tp->next;
+ }while(ISARRAY(t2));
+ if(t==t2||!ISSCALAR(t2)){
+ BSET(set,j);
+ if(wr&&j<rcount) {BSET(set,j+vcount-rcount);continue;}
+ }
+ }
+ }
+ if(j<rcount){
+ if(i<(vcount-rcount)) ierror(0);
+ if(!gpt||
+ (!gpt[i-(vcount-rcount)]&&!is_restrict(j))||
+ (!gpt[j]&&!is_restrict(i-(vcount-rcount)))||
+ (gpt[j]&&gpt[i-(vcount-rcount)]&&bvdointersect(gpt[i-(vcount-rcount)],gpt[j],vsize))){
+ t2=p_typ(v);
+ if(t==t2||t2==CHAR||!ISSCALAR(t2))
+ BSET(set,j+vcount-rcount);
+ }
+ }
+ }
+ }
+ }else{
+ v=vilist[i];
+ propagate_pointers(set,v,t,i);
+ }
+}
+
+void ic_changes(IC *p,bvtype *result)
+/* Initialisiert den Bitvektor result mit allen Variablen, die durch das */
+/* IC p geaendert werden koennten. */
+{
+ int i,j,t,t2;Var *v;
+ memset(result,0,vsize);
+ t=(ztyp(p)&NQ);
+ if(p->z.flags&VAR){
+ v=p->z.v;
+ i=v->index;
+ /* Hilfsvariable, die waehrend diesem cse-Durchlauf eingefuehrt */
+ /* wurde. */
+ if(i<0) return;
+ if(i>=vcount) ierror(0);
+ if(p->z.flags&DREFOBJ){
+ if(i>=rcount) ierror(0);
+ alias_propagate(result,i+vcount-rcount,t,1);
+ }else{
+ alias_propagate(result,i,t,1);
+ if(i<rcount) BSET(result,i+vcount-rcount);
+ }
+ }
+ if(p->code==CALL){
+ function_info *fi;
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&(fi=p->q1.v->fi)&&(fi->flags&ALL_MODS)&&!(disable&65536)){
+ /* we can get the set from the function_info */
+ for(i=0;i<fi->change_cnt;i++){
+ if(v=fi->change_list[i].v){
+ if(v->inr==inr&&v->index>=0){
+ if(v->index>=vcount) ierror(0);
+ alias_propagate(result,v->index,v->vtyp->flags&NQ,1);
+ }else
+ propagate_pointers(result,v,v->vtyp->flags&NQ,-1);
+ }else{
+ for(j=0;j<vcount-rcount;j++){
+ v=vilist[j];
+ if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+ t=v->vtyp->flags&NQ;
+ if(t==(fi->change_list[i].flags&NQ)||!ISSCALAR(t)){
+ BSET(result,j);
+ if(j<rcount) BSET(result,j+vcount-rcount);
+ }
+ }
+ if(j<rcount){
+ t=p_typ(vilist[j]);
+ if(t==CHAR||!ISSCALAR(t)||t==fi->change_list[i].flags)
+ BSET(result,j+vcount-rcount);
+ }
+ }
+ }
+ }
+ }else{
+ bvunite(result,av_drefs,vsize);
+ bvunite(result,av_address,vsize);
+ bvunite(result,av_globals,vsize);
+ bvunite(result,av_statics,vsize);
+ }
+ }
+ if((p->z.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ bvunite(result,av_drefs,vsize);
+ }
+}
+void ic_uses(IC *p,bvtype *result)
+/* Initialisiert den Bitvektor result mit allen Variablen, die durch das */
+/* IC p benutzt werden koennten. */
+{
+ int i,j,t,t2,c;Var *v;type *tp;
+ memset(result,0,vsize);
+ c=p->code;
+ if(c!=ADDRESS){
+ if((p->q1.flags&(VAR|VARADR))==VAR&&c!=ADDRESS&&(c!=CALL||(p->q1.flags&DREFOBJ))){
+ v=p->q1.v;
+ i=v->index;
+ if(i<0||i>=vcount) ierror(0);
+ t=q1typ(p);
+ if(p->q1.flags&DREFOBJ){
+ if(i>=rcount) ierror(0);
+ alias_propagate(result,i+vcount-rcount,t,0);
+ }
+ alias_propagate(result,i,t,0);
+ }
+ if((p->q2.flags&(VAR|VARADR))==VAR){
+ v=p->q2.v;
+ i=v->index;
+ if(i<0||i>=vcount) ierror(0);
+ t=q2typ(p);
+ if(p->q2.flags&DREFOBJ){
+ if(i>=rcount) ierror(0);
+ alias_propagate(result,i+vcount-rcount,t,0);
+ }
+ alias_propagate(result,i,t,0);
+ }
+ }
+ if((p->z.flags&(VAR|VARADR|DREFOBJ))==(VAR|DREFOBJ)){
+ v=p->z.v;
+ i=v->index;
+ if(i>=vcount) {pric2(stdout,p);ierror(0);}
+ t=(ztyp(p)&NQ);
+ alias_propagate(result,i,t,0);
+ }
+ if(p->code==CALL){
+ function_info *fi;
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&(fi=p->q1.v->fi)&&(fi->flags&ALL_USES)&&!(disable&65536)){
+ /* we can get the set from the function_info */
+ for(i=0;i<fi->use_cnt;i++){
+ if(v=fi->use_list[i].v){
+ if(v->inr==inr&&v->index>=0)
+ alias_propagate(result,v->index,v->vtyp->flags&NQ,0);
+ else
+ propagate_pointers(result,v,v->vtyp->flags&NQ,-1);
+ }else{
+ for(j=0;j<vcount-rcount;j++){
+ v=vilist[j];
+ if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+ t=v->vtyp->flags&NQ;
+ if(t==(fi->use_list[i].flags&NQ)||!ISSCALAR(t))
+ BSET(result,j);
+ }
+ if(j<rcount){
+ t=p_typ(vilist[j]);
+ if(t==CHAR||!ISSCALAR(t)||t==fi->use_list[i].flags)
+ BSET(result,j+vcount-rcount);
+ }
+ }
+ }
+ }
+ }else{
+ bvunite(result,av_drefs,vsize);
+ bvunite(result,av_address,vsize);
+ bvunite(result,av_globals,vsize);
+ bvunite(result,av_statics,vsize);
+ }
+ }
+ if((p->q1.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ bvunite(result,av_drefs,vsize);
+ }
+ if((p->q2.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+ bvunite(result,av_drefs,vsize);
+ }
+}
+void free_alias(flowgraph *fg)
+/* Gibt alle use/change-Listen der ICs im Flussgraphen frei. */
+{
+ IC *p;flowgraph *g;
+ if(DEBUG&1024) printf("freeing alias info\n");
+ for(g=fg;g;g=g->normalout){
+ for(p=g->start;p;p=p->next){
+ if(p->code==LABEL&&(p->use_cnt>0||p->change_cnt>0)) ierror(0);
+ if(p->use_cnt>0) {free(p->use_list);p->use_cnt=0;}
+ if(p->change_cnt>0) {free(p->change_list);p->change_cnt=0;}
+ if(p==g->end) break;
+ }
+ }
+ have_alias=0;
+}
+void create_alias(flowgraph *fg)
+/* Initialisiert jedes IC mit einer Liste aller Variablen, die dadurch */
+/* benutzt und veraendert werden koennten. Z.Z. wird bis auf Typ-basierte */
+/* Optimierungen der worst-case angenommen. */
+{
+ bvtype *vars=mymalloc(vsize);
+ IC *p;flowgraph *g;
+ flowlist *in;
+ bvtype **ppt;
+ int i,cnt,all_preds,changed;
+ unsigned long heapsize;
+ if(DEBUG&1024) printf("creating alias info\n");
+
+ ptsize=0;
+
+ changed=1;
+ while(changed){
+ if(DEBUG&1024) printf("create_alias pass\n");
+ changed=0;
+ if(have_alias)
+ free_alias(fg);
+ heapsize=0;
+ for(g=fg;g;g=g->normalout){
+ if((optflags&1024)&&!noaliasopt){
+ /* do all predecessors already have points-to-info? */
+ all_preds=1;
+ for(in=g->in;in;in=in->next){
+ if(!in->graph->pt){
+ all_preds=0;
+ break;
+ }
+ }
+ if(/*all_preds&&*/g->in){
+ /* calc union of all predecessors */
+ gpt=clone_pt(g->in->graph->pt);
+ for(in=g->in->next;in;in=in->next){
+ ppt=in->graph->pt;
+ if(!ppt)
+ continue;
+ for(i=0;i<vcount;i++){
+ if(gpt[i]){
+ if(!ppt[i])
+ undef_pt(gpt,i);
+ else
+ bvunite(gpt[i],ppt[i],vsize);
+ }
+ }
+ }
+ }else
+ gpt=new_pt();
+ }else{
+ gpt=0;
+ }
+ for(p=g->start;p;p=p->next){
+ int da; /* always consider a direct write, even if variable is const-qualified */
+ ic_uses(p,vars);
+ for(i=0,cnt=0;i<vcount;i++)
+ if(BTST(vars,i)) cnt++;
+ p->use_cnt=cnt;
+ if(cnt==0){
+ p->use_list=0;
+ }else{
+ p->use_list=mymalloc(cnt*VLS);
+ heapsize+=cnt*VLS;
+ for(cnt=0,i=0;i<vcount;i++){
+ if(BTST(vars,i)){
+ p->use_list[cnt].v=vilist[i];
+ if(i>=vcount-rcount) p->use_list[cnt].flags=DREFOBJ;
+ else p->use_list[cnt].flags=0;
+ cnt++;
+ }
+ }
+ }
+ ic_changes(p,vars);
+ if((p->z.flags&(VAR|DREFOBJ))==VAR)
+ da=p->z.v->index;
+ else
+ da=0;
+ for(i=0,cnt=0;i<vcount;i++)
+ if(BTST(vars,i)&&(i>=vcount-rcount||i==da||!is_const(vilist[i]->vtyp))) cnt++;
+ p->change_cnt=cnt;
+ if(cnt==0){
+ p->change_list=0;
+ }else{
+ p->change_list=mymalloc(cnt*VLS);
+ heapsize+=cnt*VLS;
+ for(cnt=0,i=0;i<vcount;i++){
+ if(BTST(vars,i)&&(i>=vcount-rcount||i==da||!is_const(vilist[i]->vtyp))){
+ p->change_list[cnt].v=vilist[i];
+ if(i>=vcount-rcount) p->change_list[cnt].flags=DREFOBJ;
+ else p->change_list[cnt].flags=0;
+ cnt++;
+ }
+ }
+ }
+
+ if(p->code==CALL){
+ if((p->q1.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+ int i=p->q1.v->index;
+ if(i<0||i>=vcount) ierror(0);
+ if(gpt&&gpt[i]){
+ int j,cnt;
+ for(cnt=0,j=0;j<vcount-rcount;j++){
+ if(BTST(gpt[i],j)&&ISFUNC(vilist[j]->vtyp->flags))
+ cnt++;
+ }
+ if(cnt){
+ if(p->call_cnt) free(p->call_list);
+ p->call_cnt=cnt;
+ p->call_list=mymalloc(sizeof(*p->call_list)*cnt);
+ for(cnt=0,j=0;j<vcount-rcount;j++){
+ if(BTST(gpt[i],j)&&ISFUNC(vilist[j]->vtyp->flags)){
+ p->call_list[cnt].v=vilist[j];
+ p->call_list[cnt].flags=0;
+ cnt++;
+ }
+ }
+ if(cnt==1&&all_preds){
+ if(DEBUG&1024) {printf("replacing indirect call by single target:\n");pric2(stdout,p);}
+ p->q1.flags=VAR;
+ p->q1.val.vmax=l2zm(0L);
+ p->q1.v=p->call_list[0].v;
+ }
+ }
+ }
+ }
+ }
+
+ if((optflags&1024)&&!noaliasopt)
+ trans_pt(gpt,p);
+ if(p==g->end) break;
+ }
+ if((optflags&1024)&&!noaliasopt){
+ if(!changed){
+ if(!equal_pt(gpt,g->pt)){
+ changed=1;
+ free_pt(g->pt);
+ g->pt=gpt;
+ }else{
+ free_pt(gpt);
+ }
+ }else{
+ free_pt(g->pt);
+ g->pt=gpt;
+ }
+ }
+ }
+ if(DEBUG&16384) printf("create_alias heapsize=%lu\n",heapsize);
+ have_alias=1;
+ }
+ if(DEBUG&16384) printf("points-to heapsize=%lu\n",ptsize);
+ if((optflags&1024)&&!noaliasopt){
+ for(g=fg;g;g=g->normalout){
+ free_pt(g->pt);
+ g->pt=0;
+ }
+ }
+ free(vars);
+}
+#if 1
+void update_alias(Var *old,Var *new)
+/* Aendert alle use/changes von (old) auf (new). Wird aufgerufen, wenn */
+/* copy-propagation eine Variable neu zu einem DREFOBJ macht. */
+{
+ IC *p;int i;
+ if(DEBUG&1024) printf("update-alias\n");
+ for(p=first_ic;p;p=p->next){
+ for(i=0;i<p->use_cnt;i++){
+ if(p->use_list[i].v==old&&(p->use_list[i].flags&DREFOBJ)){
+ p->use_cnt++;
+ p->use_list=myrealloc(p->use_list,p->use_cnt*VLS);
+ p->use_list[p->use_cnt-1].v=new;
+ p->use_list[p->use_cnt-1].flags=DREFOBJ;
+ break;
+ }
+ }
+ for(i=0;i<p->change_cnt;i++){
+ if(p->change_list[i].v==new||(p->change_list[i].v==old&&(p->change_list[i].flags&DREFOBJ))){
+ p->change_cnt++;
+ p->change_list=myrealloc(p->change_list,p->change_cnt*VLS);
+ p->change_list[p->change_cnt-1].v=new;
+ p->change_list[p->change_cnt-1].flags=DREFOBJ;
+ break;
+ }
+ }
+ }
+}
+#endif
diff --git a/av.c b/av.c
new file mode 100644
index 0000000..627fedd
--- /dev/null
+++ b/av.c
@@ -0,0 +1,557 @@
+/* $VER: vbcc (av.c) $Revision: 1.9 $ */
+/* aktive Variablen und Elimination unnoetiger Anweisungen */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+/* fuer aktive Variablen */
+Var **vilist;
+unsigned int vcount; /* 0..vcount-rcount-1: vars, vcount-rcount..vcount: DREFOBJs */
+unsigned int rcount;
+size_t vsize;
+bvtype *av_globals,*av_address,*av_statics,*av_drefs;
+int report_dead_statements;
+
+void print_av(bvtype *bitvector)
+/* druckt Variablen in einem Bitvektor */
+{
+ int i;
+ if(!bitvector) {printf("active variables not available\n");return;}
+ for(i=0;i<vcount-rcount;i++)
+ if(BTST(bitvector,i)) printf("%3d: %s,%ld\n",i,vilist[i]->identifier,zm2l(vilist[i]->offset));
+ for(i=vcount-rcount;i<vcount;i++)
+ if(BTST(bitvector,i)) printf("%3d: (%s),%ld\n",i,vilist[i]->identifier,zm2l(vilist[i]->offset));
+}
+
+static int clcnt;
+
+/* walks through a clist and numbers variables whose addresses are
+ contained; if pass==-1, index is set to -1, if pass==0, index is set,
+ otherwise vilist
+ clcnt is used as index-counter in pass 0 */
+void num_clist_refs(int pass,type *t,const_list *cl)
+{
+ /*FIXME: bei Aufrufen auch auf locale, nicht USEDASDEST|USEDASADDR */
+ int i;zmax sz;
+ if(ISARRAY(t->flags)){
+ for(sz=l2zm(0L);!zmleq(t->size,sz)&&cl;sz=zmadd(sz,l2zm(1L)),cl=cl->next){
+ if(!cl->other)
+ return;
+ num_clist_refs(pass,t->next,cl->other);
+ }
+ return;
+ }
+ if(ISUNION(t->flags)){
+ num_clist_refs(pass,(*t->exact->sl)[0].styp,cl);
+ return;
+ }
+ if(ISSTRUCT(t->flags)&&!cl->tree){
+ type *st;
+ for(i=0;i<t->exact->count&&cl;i++){
+ st=(*t->exact->sl)[i].styp;
+ if(!(*t->exact->sl)[i].identifier) ierror(0);
+ if((*t->exact->sl)[i].identifier[0]){
+ if(cl->other)
+ num_clist_refs(pass,st,cl->other);
+ cl=cl->next;
+ }
+ }
+ return;
+ }
+ if(cl->tree&&(cl->tree->o.flags&VARADR)){
+ Var *v=cl->tree->o.v;
+ if(pass==-1){
+ v->index=-1;
+ }else if(pass==0){
+ if(v->index<0) {v->index=clcnt++;v->inr=inr;}
+ }else{
+ if(v->index<0||v->index>=vcount-rcount)
+ ierror(0);
+ vilist[v->index]=v;
+ }
+ }
+}
+
+int inr;
+
+void num_vars(void)
+/* Numeriert Variablen und erzeugt Indexliste */
+{
+ unsigned int i,j,done;IC *p;Var *v,*a[4],*vp;
+ unsigned long heapsize=0;
+ if(DEBUG&1024) printf("numerating variables loop1\n");
+ inr++;
+ /* alle Indizes auf -1 */
+ a[0]=vl0;
+ a[1]=vl1;
+ a[2]=vl2;
+ a[3]=vl3;
+#if 1
+ for(j=0;j<4;j++){
+ v=a[j];
+ while(v){
+ v->index=-1;
+ /* Variablen von inline-Funktionen */
+ if(j==0&&v->fi&&v->fi->first_ic){
+ for(vp=v->fi->vars;vp;vp=vp->next) vp->index=-1;
+ }
+ v=v->next;
+ }
+ }
+ /* variables that may be referenced in inter-proc. dflow-info */
+ for(p=first_ic;p;p=p->next){
+ if(p->code==CALL&&(p->q1.flags&VAR)&&p->q1.v->fi){
+ function_info *fi=p->q1.v->fi;
+ if(fi->flags&ALL_USES){
+ for(i=0;i<fi->use_cnt;i++){
+ if(v=fi->use_list[i].v) fi->use_list[i].v->index=-1;
+ }
+ }
+ if(fi->flags&ALL_MODS){
+ for(i=0;i<fi->change_cnt;i++){
+ if(v=fi->change_list[i].v) fi->change_list[i].v->index=-1;
+ }
+ }
+ }
+ /* const-lists */
+ if((p->q1.flags&VAR))
+ if(p->q1.v->clist&&is_const(p->q1.v->vtyp)) num_clist_refs(-1,p->q1.v->vtyp,p->q1.v->clist);
+ if((p->q2.flags&VAR))
+ if(p->q2.v->clist&&is_const(p->q2.v->vtyp)) num_clist_refs(-1,p->q2.v->vtyp,p->q2.v->clist);
+ if((p->z.flags&VAR))
+ if(p->z.v->clist&&is_const(p->z.v->vtyp)) num_clist_refs(-1,p->z.v->vtyp,p->z.v->clist);
+ }
+#endif
+ /* Do we need this? */
+ for(p=first_ic;p;p=p->next){
+ if(p->q1.flags&VAR) {p->q1.v->index=-1;p->q1.v->flags&=~USEDASADR;}
+ if(p->q2.flags&VAR) {p->q2.v->index=-1;p->q2.v->flags&=~USEDASADR;}
+ if(p->z.flags&VAR) {p->z.v->index=-1;p->z.v->flags&=~USEDASADR;}
+ }
+ /* erst alle Variablen, die als DREFOBJ benutzt werden */
+ if(DEBUG&1024) printf("numerating variables loop2\n");
+ i=0;
+ do{
+ done=1;
+ if(DEBUG&1024) printf("pass\n");
+ for(p=first_ic;p;p=p->next){
+ if(p->code<LABEL||p->code>BRA){
+ int c=p->code;
+ /* mark variables ad USEDASADR */
+ if(c==ADDRESS) p->q1.v->flags|=USEDASADR;
+ if(p->q1.flags&VARADR) p->q1.v->flags|=USEDASADR;
+ if(p->q2.flags&VARADR) p->q2.v->flags|=USEDASADR;
+ if(p->z.flags&VARADR) p->z.v->flags|=USEDASADR;
+ j=(q1typ(p)&NQ);
+ if((p->q1.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+ v=p->q1.v;
+ if(!v->vtyp->next||(v->vtyp->next->flags&NQ)!=j) v->flags|=DNOTTYPESAFE;
+ if(v->index<0) {v->index=i++;v->inr=inr;done=0;}
+ }
+ j=(q2typ(p)&NQ);
+ if((p->q2.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+ v=p->q2.v;
+ if(!v->vtyp->next||(v->vtyp->next->flags&NQ)!=j) v->flags|=DNOTTYPESAFE;
+ if(v->index<0) {v->index=i++;v->inr=inr;done=0;}
+ }
+ j=(ztyp(p)&NQ);
+ if((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+ v=p->z.v;
+ if(!v->vtyp->next||(v->vtyp->next->flags&NQ)!=j) v->flags|=DNOTTYPESAFE;
+ if(v->index<0) {v->index=i++;v->inr=inr;done=0;}
+ }
+ /* mark copies from DREFs also as DREFs (necessary?) (check z for !DREFOBJ?) */
+ if((c==ASSIGN||c==ADDI2P||c==SUBIFP)&&(p->q1.flags&VAR)&&p->q1.v->index>=0&&(p->z.flags&VAR)&&p->z.v->index<0){
+ if(!(p->z.flags&VAR)) ierror(0);
+ p->z.v->index=i++;p->z.v->inr=inr;done=0;
+ }
+ /* mark copies to DREFs as DREFs (because of copy-propagation */
+ /* and post-op reordering */
+ if((c==ASSIGN||c==ADDI2P||c==SUBIFP)&&(p->z.flags&VAR)&&p->z.v->index>=0&&(p->q1.flags&VAR)&&p->q1.v->index<0){
+ p->q1.v->index=i++;p->q1.v->inr=inr;done=0;
+ }
+ }
+ }
+ }while(!done);
+ if(DEBUG&1024) printf("numerating variables loop3\n");
+ rcount=i; /* Anzahl der DREFOBJ-Variablen */
+ /* jetzt den Rest */
+ for(p=first_ic;p;p=p->next){
+ int c=p->code;
+ if(1/*p->code<LABEL||p->code>BRA*/){
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR){
+ j=(q1typ(p)&NQ);
+ v=p->q1.v;
+ if((v->vtyp->flags&NQ)!=j) v->flags|=NOTTYPESAFE;
+ if(v->index<0) {v->index=i++;v->inr=inr;}
+ }
+ if((p->q2.flags&(VAR|DREFOBJ))==VAR){
+ j=(q2typ(p)&NQ);
+ v=p->q2.v;
+ if((v->vtyp->flags&NQ)!=j) v->flags|=NOTTYPESAFE;
+ if(v->index<0) {v->index=i++;v->inr=inr;}
+ }
+ if((p->z.flags&(VAR|DREFOBJ))==VAR){
+ j=(ztyp(p)&NQ);
+ v=p->z.v;
+ if((v->vtyp->flags&NQ)!=j) v->flags|=NOTTYPESAFE;
+ if(v->index<0) {v->index=i++;v->inr=inr;}
+ }
+ }
+ /* const-lists */
+ if((p->q1.flags&VAR))
+ if(p->q1.v->clist&&is_const(p->q1.v->vtyp)) {clcnt=i;num_clist_refs(0,p->q1.v->vtyp,p->q1.v->clist);i=clcnt;}
+ if((p->q2.flags&VAR))
+ if(p->q2.v->clist&&is_const(p->q2.v->vtyp)) {clcnt=i;num_clist_refs(0,p->q2.v->vtyp,p->q2.v->clist);i=clcnt;}
+ if((p->z.flags&VAR))
+ if(p->z.v->clist&&is_const(p->z.v->vtyp)) {clcnt=i;num_clist_refs(0,p->z.v->vtyp,p->z.v->clist);i=clcnt;}
+ }
+ if(DEBUG&1024) printf("numerating variables loop4\n");
+ vcount=i+rcount; /* alle benutzten Variablen+Anzahl der DREFOBJs */
+ vilist=mymalloc(vcount*sizeof(Var *));
+ heapsize+=vcount*sizeof(Var *);
+#if 0
+ for(j=0;j<4;j++){
+ int i;
+ v=a[j];
+ while(v){
+ i=v->index;
+/* printf("%s has index %d\n",v->identifier,i);*/
+ if(i>=0){
+ if(i>=vcount-rcount) ierror(0);
+ vilist[i]=v;
+ if(i<rcount) vilist[i+vcount-rcount]=v;
+ }
+ /* Variablen von inline-Funktionen */
+ if(j==0&&v->fi&&v->fi->first_ic){
+ for(vp=v->fi->vars;vp;vp=vp->next){
+ i=vp->index;
+ if(i>=0){
+ if(i>=vcount-rcount) ierror(0);
+ vilist[i]=vp;
+ if(i<rcount) vilist[i+vcount-rcount]=vp;
+ }
+ }
+ }
+ v=v->next;
+ }
+ }
+#endif
+
+ for(p=first_ic;p;p=p->next){
+ Var *v;
+ if(p->q1.flags&VAR){
+ i=p->q1.v->index;
+ vilist[i]=v=p->q1.v;
+ if(v->clist&&is_const(v->vtyp)) num_clist_refs(1,v->vtyp,v->clist);
+ }
+ if(p->q2.flags&VAR){
+ i=p->q2.v->index;
+ vilist[i]=v=p->q2.v;
+ if(v->clist&&is_const(v->vtyp)) num_clist_refs(1,v->vtyp,v->clist);
+
+ }
+ if(p->z.flags&VAR){
+ i=p->z.v->index;
+ vilist[i]=v=p->z.v;
+ if(v->clist&&is_const(v->vtyp)) num_clist_refs(1,v->vtyp,v->clist);
+ }
+ }
+ for(i=0;i<rcount;i++)
+ vilist[i+vcount-rcount]=vilist[i];
+
+ /*vsize=(vcount+CHAR_BIT-1)/CHAR_BIT;*/
+ vsize=BVSIZE(vcount);
+ if(DEBUG&(16384|1024)) printf("%lu variables (%lu DREFOBJs), vsize=%lu\n",(unsigned long)vcount,(unsigned long)rcount,(unsigned long)vsize);
+
+ av_drefs=mymalloc(vsize);
+ memset(av_drefs,0,vsize);
+ /* alle DREFOBJs */
+ for(i=vcount-rcount;i<vcount;i++) BSET(av_drefs,i);
+
+ /* av_globals enthaelt alle globalen Variablen und av_address */
+ /* zusaetzlich noch alle Variablen, deren Adressen genommen wurden */
+ av_globals=mymalloc(vsize);
+ memset(av_globals,0,vsize);
+ av_statics=mymalloc(vsize);
+ memset(av_statics,0,vsize);
+ av_address=mymalloc(vsize);
+ memcpy(av_address,av_globals,vsize);
+ heapsize+=4*vsize;
+ for(i=0;i<vcount-rcount;i++){
+ if(vilist[i]->nesting==0||vilist[i]->storage_class==EXTERN) BSET(av_globals,i);
+ if(vilist[i]->flags&USEDASADR) BSET(av_address,i);
+ if(vilist[i]->storage_class==STATIC) BSET(av_statics,i);
+ if(i<rcount){
+/* if(!ISPOINTER(vilist[i]->vtyp->flags)){ printf("%s(%ld)\n",vilist[i]->identifier,zm2l(vilist[i]->offset));ierror(0);}*/
+ BSET(av_address,i+vcount-rcount);
+ BSET(av_globals,i+vcount-rcount);
+ }
+ }
+ if(DEBUG&16384) printf("num_vars heapsize=%lu\n",heapsize);
+}
+void print_vi(void)
+/* Druckt vilist und testet Konsistenz */
+{
+ int i;
+ printf("\nprint_vi()\n");
+ for(i=0;i<vcount;i++){
+ if(!vilist[i]||(i<rcount&&vilist[i]->index!=i)) ierror(0);
+ printf("%3d: %s\n",i,vilist[i]->identifier);
+ }
+}
+void av_change(IC *p,bvtype *use,bvtype *def)
+/* Berechnet die Aenderungen, die sich durch IC p an use und def ergeben. */
+{
+ int i,j,n=-1;
+ int g1,g2;
+
+ /* Wenn eine Quelle==Ziel, dann wird dadurch kein neuer use erzeugt, */
+ /* um z.B. unbenutzte Induktionsvariablen in Schleifen zu eliminieren. */
+ g1=compare_objs(&p->q1,&p->z,p->typf);
+ g2=compare_objs(&p->q2,&p->z,p->typf);
+ if(!g1&&(p->q1.flags&(VAR|DREFOBJ))==VAR) n=p->q1.v->index;
+ if(!g2&&(p->q2.flags&(VAR|DREFOBJ))==VAR) n=p->q2.v->index;
+
+ for(j=0;j<p->use_cnt;j++){
+ i=p->use_list[j].v->index;
+ if(p->use_list[j].flags&DREFOBJ) i+=vcount-rcount;
+ if(i>=vcount) continue;
+ if(i!=n&&!BTST(def,i)) BSET(use,i);
+ }
+
+ /* Ein Wert wird nicht zerstoert, wenn es kein elementarer Typ ist und */
+ /* die Groesse kleiner als die Variable (steht in alle solchen ICs in */
+ /* q2.val.max. */
+ if((p->z.flags&(VAR|DREFOBJ))==VAR&&(ISSCALAR(p->z.v->vtyp->flags)||p->z.v->vtyp->flags==0||zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp)))){
+ i=p->z.v->index;
+ if(i>=vcount) ierror(0);
+ if(g1&&g2&&!BTST(use,i)) BSET(def,i);
+ /* Wenn p geaendert wird, wird auch *p geaendert */
+ if(i<rcount&&!BTST(def,i+vcount-rcount)) BSET(use,i+vcount-rcount);
+ }
+ if((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&g1&&g2&&!(p->z.v->flags&DNOTTYPESAFE)){
+ i=p->z.v->index+vcount-rcount;
+ if(i>=vcount) ierror(0);
+ if(!BTST(use,i)) BSET(def,i);
+ }
+}
+void active_vars(flowgraph *fg)
+/* analysiert aktive Variablen im Flussgraphen, nomain==0, wenn zu */
+/* optimierende Funktion main() ist */
+{
+ IC *p;
+ int changed,pass;flowgraph *g;
+ unsigned long heapsize=0;
+
+ if(DEBUG&1024){printf("analysing active variables\n");/*scanf("%d",&i);*/}
+ tmp=mymalloc(vsize);
+ heapsize+=vsize;
+ /* av_gen und av_kill fuer jeden Basic Block berechnen */
+ if(DEBUG&1024){printf("active_vars(): loop1\n");/*scanf("%d",&i);*/}
+ g=fg;
+ while(g){
+ g->av_gen=mymalloc(vsize);
+ memset(g->av_gen,0,vsize);
+ g->av_kill=mymalloc(vsize);
+ memset(g->av_kill,0,vsize);
+ g->av_in=mymalloc(vsize);
+ memset(g->av_in,0,vsize);
+ g->av_out=mymalloc(vsize);
+ memset(g->av_out,0,vsize);
+ heapsize+=4*vsize;
+ for(p=g->start;p;p=p->next){
+ av_change(p,g->av_gen,g->av_kill);
+ if(p==g->end) break;
+ }
+ g=g->normalout;
+ }
+
+ /* av_in und av_out fuer alle Bloecke berechnen */
+ if(DEBUG&1024){printf("active_vars(): loop2\npass: ");/*scanf("%d",&i);*/}
+ pass=0;
+ do{
+ if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
+ changed=0;
+ g=fg;
+ while(g){
+ /* out(B)=U in(C) ueber alle Nachfolger C von B */
+ memset(g->av_out,0,vsize); /* noetig? */
+ if(g->branchout) bvunite(g->av_out,g->branchout->av_in,vsize);
+ if((!g->end||g->end->code!=BRA)&&g->normalout) bvunite(g->av_out,g->normalout->av_in,vsize);
+ /* Am Ende muessen alle globalen Variablen bekannt sein */
+ if(!g->normalout){
+ bvunite(g->av_out,av_globals,vsize);
+ /*if(!nocall)*/ bvunite(g->av_out,av_statics,vsize);
+ }
+ /* in(B)=use(B)U(out(B)-def(B)) */
+ memcpy(tmp,g->av_out,vsize);
+ bvdiff(tmp,g->av_kill,vsize);
+ bvunite(tmp,g->av_gen,vsize);
+
+ if(!bvcmp(tmp,g->av_in,vsize)){changed=1;memcpy(g->av_in,tmp,vsize);}
+ g=g->normalout;
+ }
+ }while(changed);
+ if(DEBUG&1024) printf("\n");
+ free(tmp);
+ if(DEBUG&16384) printf("av heapsize=%lu\n",heapsize);
+}
+void av_update(IC *p,bvtype *isused)
+{
+ int i,j;
+ if((p->z.flags&(VKONST|VAR))==VAR){
+ i=p->z.v->index;
+ if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+ if(i<0||i>=vcount){
+ printf("i=%d\n",i);pric2(stdout,p); ierror(0);
+ }
+ if(p->z.flags&DREFOBJ){
+ if(!(p->z.v->flags&DNOTTYPESAFE))
+ BCLR(isused,i);
+ }else{
+ if(ISSCALAR(p->z.v->vtyp->flags)||(p->code==ASSIGN&&zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp))))
+ BCLR(isused,i);
+ }
+ /* bei Zuweisung an p wird *p aktiv */
+ if(i<rcount) BSET(isused,i+vcount-rcount);
+ }
+ for(j=0;j<p->use_cnt;j++){
+ i=p->use_list[j].v->index;
+ if(p->use_list[j].flags&DREFOBJ) i+=vcount-rcount;
+ if(i<0||i>=vcount) continue;
+ BSET(isused,i);
+ }
+}
+/* tests, if IC p uses or modifies var v */
+static int var_conflicts(Var *v,IC *p)
+{
+ int i;
+ for(i=0;i<p->use_cnt;i++)
+ if(p->use_list[i].v==v&&!(p->use_list[i].flags&DREFOBJ))
+ return 1;
+ for(i=0;i<p->change_cnt;i++)
+ if(p->change_list[i].v==v&&!(p->change_list[i].flags&DREFOBJ))
+ return 1;
+ return 0;
+}
+int dead_assignments(flowgraph *fg)
+/* Findet Zuweisungen, die unnoetig sind, da die Variable nie mehr */
+/* benutzt werden kann. */
+{
+ int changed=0;IC *p;bvtype *isused;
+ int i,j;
+ if(DEBUG&1024) printf("searching for dead assignments\n");
+ isused=mymalloc(vsize);
+ while(fg){
+ memcpy(isused,fg->av_out,vsize);
+ p=fg->end;
+ while(p){
+ if(p->z.flags&VAR){
+ i=p->z.v->index;
+ if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+ if(!BTST(isused,i)&&!is_volatile_ic(p)&&!(disable&1)){
+ if(DEBUG&1024){printf("dead assignment deleted:\n");pric2(stdout,p);}
+ if(*p->z.v->identifier&&p->code!=ASSIGN){ err_ic=p;error(170,i>=vcount-rcount?"*":"",p->z.v->identifier);err_ic=0;}
+ /*if(p->code!=GETRETURN)*/ changed=1;
+ if(p==fg->start){remove_IC_fg(fg,p);break;}
+ p=p->prev;remove_IC_fg(fg,p->next);
+ continue;
+ }
+ }
+ if(p->code!=SETRETURN&&p->code!=TEST&&p->code!=COMPARE&&(p->q1.flags&VAR)&&!BTST(isused,p->q1.v->index)&&(!(p->z.flags&VAR)||!p->z.v->reg||p->z.v->identifier)){
+ IC *m,*a;int f=p->q1.flags,dt=p->q1.dtyp;
+ p->q1.flags&=~DREFOBJ;
+ a=p->prev;if(a) m=a->prev; else m=0;
+ if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->q1,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
+ if(DEBUG&1024){
+ printf("reorder post-op(q1):\n");
+ pric2(stdout,m);pric2(stdout,a);pric(stdout,p);
+ }
+ p->q1=a->q1;
+ m->next=p;p->prev=m;
+ if(p->next) p->next->prev=a;
+ a->next=p->next;
+ a->prev=p;p->next=a;
+ if(fg->end==p) fg->end=a;
+ if(p==last_ic) last_ic=a;
+ remove_IC_fg(fg,m);
+ av_update(a,isused);
+ p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
+ memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
+ p->use_cnt+=a->use_cnt;
+ changed=1;
+ if((f&DREFOBJ)&&p->q1.v->index>=rcount)
+ ierror(0);
+ }
+ p->q1.flags=f;
+ p->q1.dtyp=dt;
+ }
+ if(p->code!=TEST&&p->code!=COMPARE&&(p->q2.flags&VAR)&&!BTST(isused,p->q2.v->index)&&(!(p->z.flags&VAR)||!p->z.v->reg||p->z.v->identifier)){
+ IC *m,*a;int f=p->q2.flags,dt=p->q2.dtyp;
+ p->q2.flags&=~DREFOBJ;
+ a=p->prev;if(a) m=a->prev; else m=0;
+ if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->q2,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
+ if(DEBUG&1024){
+ printf("reorder post-op(q2):\n");
+ pric2(stdout,m);pric2(stdout,a);pric(stdout,p);
+ }
+ p->q2=a->q1;
+ m->next=p;p->prev=m;
+ if(p->next) p->next->prev=a;
+ a->next=p->next;
+ a->prev=p;p->next=a;
+ if(fg->end==p) fg->end=a;
+ if(p==last_ic) last_ic=a;
+ remove_IC_fg(fg,m);
+ av_update(a,isused);
+ p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
+ memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
+ p->use_cnt+=a->use_cnt;
+ changed=1;
+ if((f&DREFOBJ)&&p->q2.v->index>=rcount)
+ ierror(0);
+ }
+ p->q2.flags=f;
+ p->q2.dtyp=dt;
+ }
+ if(p->code!=TEST&&p->code!=COMPARE&&(p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&!BTST(isused,p->z.v->index)){
+ IC *m,*a;int f=p->z.flags,dt=p->z.dtyp;
+ p->z.flags&=~DREFOBJ;
+ a=p->prev;if(a) m=a->prev; else m=0;
+ if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->z,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
+ if(DEBUG&1024){
+ printf("reorder post-op(z):\n");
+ pric2(stdout,m);pric2(stdout,a);pric2(stdout,p);
+ printf("--");
+ }
+ p->z=a->q1;
+ m->next=p;p->prev=m;
+ if(p->next) p->next->prev=a;
+ a->next=p->next;
+ a->prev=p;p->next=a;
+ if(fg->end==p) fg->end=a;
+ if(p==last_ic) last_ic=a;
+ remove_IC_fg(fg,m);
+ av_update(a,isused);
+ p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
+ memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
+ p->use_cnt+=a->use_cnt;
+ changed=1;
+ if((f&DREFOBJ)&&p->z.v->index>=rcount)
+ ierror(0);
+ }
+ p->z.flags=f;
+ p->z.dtyp=dt;
+ }
+ av_update(p,isused);
+ if(p==fg->start) break;
+ p=p->prev;
+ }
+ fg=fg->normalout;
+ }
+ free(isused);
+ return(changed);
+}
+
diff --git a/bin/.dummy b/bin/.dummy
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/bin/.dummy
diff --git a/bug.c b/bug.c
new file mode 100755
index 0000000..975ff3d
--- /dev/null
+++ b/bug.c
@@ -0,0 +1,130 @@
+/* $VER: vbcc (loop.c) V0.8 */
+/* schleifenorientierte Optimierungen */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+#define MOVE_IC 1
+#define MOVE_COMP 2
+
+/* Liste, in die ICs eingetragen werden, die aus Schleifen */
+/* gezogen werden sollen. */
+struct movlist{
+ struct movlist *next;
+ struct IC *IC;
+ struct flowgraph *target_fg;
+ int flags;
+};
+
+struct movlist *first_mov,*last_mov;
+
+int report_weird_code,report_suspicious_loops;
+
+/* Bitvektoren fuer schleifeninvariante ICs */
+bvtype *invariant,*inloop,*moved,*moved_completely;
+bvtype *fg_tmp;
+bvtype *not_movable;
+size_t bsize;
+
+
+/* Liste, in die ICs fuer strength-reduction eingetragen */
+/* werden. */
+struct srlist{
+ struct srlist *next;
+ struct IC *ind_var;
+ struct IC *IC;
+ struct flowgraph *target_fg;
+ /* Hilfsvariable, falls eine aequivalente Operation schon reduziert */
+ /* wurde. */
+ struct Var *hv;
+};
+
+struct srlist *first_sr,*last_sr;
+
+/* Liste, in die Daten fuer loop-unrolling eingetragen werden. */
+struct urlist{
+ int flags;
+ long total,unroll;
+ struct IC *cmp,*branch,*ind;
+ struct flowgraph *start,*head;
+ struct urlist *next;
+} *first_ur;
+
+#define UNROLL_COMPLETELY 1
+#define UNROLL_MODULO 2
+#define UNROLL_INVARIANT 4
+#define UNROLL_REVERSE 8
+#define IND_ONLY_COUNTS 16
+#define MULTIPLE_EXITS 32
+
+/* Hier werden Induktionsvariablen vermerkt */
+struct IC **ind_vars;
+
+static struct flowgraph *first_fg;
+
+
+void calc_movable(struct flowgraph *start,struct flowgraph *end)
+/* Berechnet, welche Definitionen nicht aus der Schleife start-end */
+/* verschoben werden duerfen. Eine Def. p von z darf nur verschoben */
+/* werden, wenn keine andere Def. von p existiert und alle */
+/* Verwendungen von z nur von p erreicht werden. */
+/* Benutzt rd_defs. */
+{
+ struct flowgraph *g;struct IC *p;
+ int i,j,k,d;
+ bvtype *changed_vars;
+ if(DEBUG&1024) printf("calculating not_movable for blocks %d to %d\n",start->index,end->index);
+ if(0/*!(optflags&1024)*/){
+ memset(not_movable,UCHAR_MAX,dsize);
+ return;
+ }
+ memset(not_movable,0,dsize);
+ changed_vars=mymalloc(vsize);
+ memset(changed_vars,0,vsize);
+ for(i=0;i<vcount-rcount;i++){
+ if(vilist[i]->vtyp->flags&VOLATILE) BSET(changed_vars,i);
+ if(i<rcount){
+ if(!vilist[i]->vtyp->next||(vilist[i]->vtyp->next->flags&VOLATILE)) BSET(changed_vars,i+vcount-rcount);
+ }
+ }
+ for(g=start;g;g=g->normalout){
+ if(!g->rd_in) ierror(0);
+ memcpy(rd_defs,g->rd_in,dsize);
+ for(p=g->start;p;p=p->next){
+ for(j=0;j<p->change_cnt;j++){
+ i=p->change_list[j].v->index;
+ if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+ if(i>=vcount) continue;
+ if(BTST(changed_vars,i)||(q1typ(p)&VOLATILE)||(q2typ(p)&VOLATILE)||(ztyp(p)&VOLATILE)){
+ bvunite(not_movable,var_defs[i],dsize);
+ }else{
+ BSET(changed_vars,i);
+ }
+ }
+ for(k=0;k<p->use_cnt;k++){
+ i=p->use_list[k].v->index;
+ if(p->use_list[k].flags&DREFOBJ) i+=vcount-rcount;
+ if(i>=vcount) continue;
+ for(d=-1,j=1;j<=dcount;j++){
+ if(BTST(rd_defs,j)&&BTST(var_defs[i],j)){
+ if(d>=0){ /* mehr als eine Def. */
+ bvunite(not_movable,var_defs[i],dsize);
+ d=-1;break;
+ }else d=j;
+ }
+ if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],UNDEF(j))){
+ bvunite(not_movable,var_defs[i],dsize);
+ d=-1;break;
+ }
+ }
+ }
+ /* Das hier, um rd_defs zu aktualisieren. */
+ rd_change(p);
+ if(p==g->end) break;
+ }
+ if(g==end) break;
+ }
+ free(changed_vars);
+}
+
diff --git a/cp.c b/cp.c
new file mode 100644
index 0000000..8e21ef2
--- /dev/null
+++ b/cp.c
@@ -0,0 +1,357 @@
+/* $VER: vbcc (cp.c) $Revision: 1.5 $ */
+/* verfuegbare Kopien und copy propagation */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+/* fuer verfuegbare Kopien */
+unsigned int ccount;
+size_t csize;
+IC **clist;
+
+/* alle Assignments, globaler oder Adr. fuer propagation etc. */
+bvtype *cp_globals,*cp_address,*cp_statics,*cp_drefs,*cp_act,*cp_dest;
+/* alle Kopieranweisungen, die eine best. Variable als Quelle haben */
+bvtype **copies;
+
+static bvtype *cp_matrix;
+
+void available_copies(flowgraph *fg)
+/* berechnet die verfuegbaren Kopien fuer jeden Block */
+{
+ flowgraph *g;IC *p;bvtype *tmp;
+ int changed,pass,i,j;
+ unsigned heapsize=0;
+ /* cp_gen und cp_kill fuer jeden Block berechnen */
+ if(DEBUG&1024) printf("analysing available copies\n");
+ tmp=mymalloc(csize);
+ heapsize+=csize;
+ for(g=fg;g;g=g->normalout){
+ g->cp_in=mymalloc(csize);
+ memset(g->cp_in,0,csize);
+ g->cp_out=mymalloc(csize);
+ memset(g->cp_out,0,csize);
+ g->cp_gen=mymalloc(csize);
+ memset(g->cp_gen,0,csize);
+ g->cp_kill=mymalloc(csize);
+ memset(g->cp_kill,0,csize);
+ heapsize+=4*csize;
+ for(p=g->end;p;p=p->prev){
+ memset(tmp,0,csize);
+ for(j=0;j<p->change_cnt;j++){
+ i=p->change_list[j].v->index;
+ if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+ if(i>=vcount) continue;
+ bvunite(tmp,copies[i],csize);
+ }
+ i=p->copyindex;
+ if(i>=0&&!BTST(g->cp_kill,i)) BSET(g->cp_gen,i);
+ bvdiff(tmp,g->cp_gen,csize);
+ bvunite(g->cp_kill,tmp,csize);
+
+ if(p==g->start) break;
+ }
+ if(g==fg){
+ memset(g->cp_in,0,csize);
+ memcpy(g->cp_out,g->cp_gen,csize);
+ }else{
+ memset(g->cp_out,UCHAR_MAX,csize);
+ bvdiff(g->cp_out,g->cp_kill,csize);
+ }
+ }
+ /* cp_in und cp_out fuer jeden Block berechnen */
+ /* out(b)=U-gen(B) vorinitialisiert und */
+ /* in(B0)=0, out(B0)=gen(B0) */
+ if(DEBUG&1024) {printf("pass:");pass=0;}
+ do{
+ if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
+ changed=0;
+ g=fg->normalout; /* in B0 aendert sich nichts */
+ while(g){
+ flowlist *lp;
+ /* in(B)=Schnitt out(P) mit P Vorgaenger von B */
+ lp=g->in;
+ i=0; /* Flag fuer ersten Vorgaenger */
+ while(lp){
+ if(!lp->graph) ierror(0);
+ if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA){
+ if(i){
+ bvintersect(g->cp_in,lp->graph->cp_out,csize);
+ }else{
+ memcpy(g->cp_in,lp->graph->cp_out,csize);i=1;
+ }
+ }
+ lp=lp->next;
+ }
+ /* out(b)=gen(B) U (in(B)-kill(B) */
+ memcpy(tmp,g->cp_in,csize);
+ bvdiff(tmp,g->cp_kill,csize);
+ bvunite(tmp,g->cp_gen,csize);
+ if(!bvcmp(tmp,g->cp_out,csize)){changed=1;memcpy(g->cp_out,tmp,csize);}
+ g=g->normalout;
+ }
+ }while(changed);
+ if(DEBUG&1024) printf("\n");
+ if(DEBUG&16384) printf("available copies heapsize=%lu\n",(unsigned long)heapsize);
+ free(tmp);
+}
+
+int compare_cp(const void *a1,const void *a2)
+/* Stub fuer compare_objs, damit als Vergleichsfunktion fuer qsort geht */
+{
+ IC *p1,*p2;int i1,i2;
+ p1=*((IC **)a1);p2=*((IC **)a2);
+ if(!p1||!p2) ierror(0);
+ i1=p1->typf; i2=p2->typf;
+ if(i1<i2) return -1;
+ if(i1>i2) return 1;
+ i1=compare_objs(&p1->q1,&p2->q1,p1->typf);
+ if(i1) return i1;
+ i1=compare_objs(&p1->z,&p2->z,p1->typf);
+ return i1;
+}
+
+void num_copies(void)
+/* numeriert alle einfachen Kopieranweisungen */
+{
+ IC *p;Var *v;int i,n,c;
+ bvtype *bp;
+ unsigned long heapsize=0;
+ if(DEBUG&1024) printf("numerating copies loop1\n");
+ ccount=0;
+ for(p=first_ic;p;p=p->next){
+ if(p->code==ASSIGN&&(p->q1.flags&(VAR/*|VARADR*/))==VAR&&(p->z.flags&VAR)) p->copyindex=ccount++;
+ else p->copyindex=-1;
+ }
+ /*csize=(ccount+CHAR_BIT-1)/CHAR_BIT;*/
+ csize=BVSIZE(ccount);
+ if(DEBUG&(16384|1024)) printf("ccount=%lu, csize=%lu\n",(unsigned long)ccount,(unsigned long)csize);
+ clist=mymalloc(ccount*sizeof(IC *));
+ heapsize+=ccount*sizeof(IC *);
+ cp_globals=mymalloc(csize);
+ memset(cp_globals,0,csize);
+ cp_statics=mymalloc(csize);
+ memset(cp_statics,0,csize);
+ cp_address=mymalloc(csize);
+ memset(cp_address,0,csize);
+ cp_drefs=mymalloc(csize);
+ memset(cp_drefs,0,csize);
+ heapsize+=4*csize;
+ copies=mymalloc(vcount*sizeof(bvtype *));
+ heapsize+=vcount*sizeof(bvtype *);
+ if(DEBUG&1024){ printf("num_copies loop2\n");}
+ for(p=first_ic;p;p=p->next){
+ if(p->copyindex>=0){
+ clist[p->copyindex]=p;
+ }
+ }
+ if(DEBUG&1024){ printf("sorting copies\n");}
+ if(ccount>1) vqsort(clist,ccount,sizeof(IC *),compare_cp);
+ if(DEBUG&1024){ printf("renumbering copies\nnum_copies loop3\n");}
+ if(ccount>0){ /* Aufpassen, da ccount unsigned! */
+ for(c=0;c<ccount-1;c++){
+ if(!compare_cp(&clist[c],&clist[c+1]))
+ clist[c+1]->copyindex=clist[c]->copyindex;
+ }
+ }
+ if(DEBUG&1024) printf("re-sorting copies\n");
+ /* wieder in die richtige Reihenfolge bringen */
+ for(p=first_ic;p;p=p->next)
+ if(p->copyindex>=0) clist[p->copyindex]=p;
+
+ cp_matrix=bp=mymalloc(vcount*csize);
+ heapsize+=vcount*csize;
+ memset(cp_matrix,0,vcount*csize);
+
+ for(i=0;i<vcount;i++){
+ copies[i]=bp;
+ bp+=csize/sizeof(bvtype);
+ }
+
+ if(DEBUG&1024) printf("numerating copies loop4\n");
+ for(p=first_ic;p;p=p->next){
+ i=p->copyindex;
+ if(i>=0){
+/* clist[i]=p;*/
+ v=p->z.v;
+ n=v->index;
+ if(p->z.flags&DREFOBJ) n+=vcount-rcount;
+ if(n<0||n>=vcount)
+ ierror(0);
+ BSET(copies[n],i);
+ if(v->nesting==0||v->storage_class==EXTERN) BSET(cp_globals,i);
+ if(p->z.flags&DREFOBJ) BSET(cp_drefs,i);
+ if(v->storage_class==STATIC) BSET(cp_statics,i);
+ if(v->flags&USEDASADR) BSET(cp_address,i);
+ v=p->q1.v;
+ n=v->index;
+ if(p->q1.flags&DREFOBJ) n+=vcount-rcount;
+ if(n<0||n>=vcount){pric2(stdout,p);printf("n=%d\n",n); ierror(0);}
+ BSET(copies[n],i);
+ if(v->nesting==0||v->storage_class==EXTERN) BSET(cp_globals,i);
+ if(p->q1.flags&DREFOBJ) BSET(cp_drefs,i);
+ if(v->storage_class==STATIC) BSET(cp_statics,i);
+ if(v->flags&USEDASADR) BSET(cp_address,i);
+
+ }
+ }
+ if(DEBUG&2048){
+ printf("copy instructions:\n");
+ for(i=0;i<ccount;i++){
+ printf("%3d: ",i);pric2(stdout,clist[i]);
+ /*if(clist[i]->copyindex!=i) ierror(0);*/
+ }
+ }
+ if(DEBUG&16384) printf("num_cp heapsize=%lu\n",heapsize);
+}
+void print_cp(bvtype *cp)
+{
+ int i;
+ if(!cp) {printf("available copies not available\n");return;}
+ for(i=0;i<ccount;i++)
+ if(BTST(cp,i)){printf("%3d: ",i);pric2(stdout,clist[i]);}
+}
+int cprop(obj *o,int target,zmax size)
+/* ersetzt gegebenenfalls Kopien, noch aendern, so dass Pointer in DREFOBJS ersetzt werden wie bei target */
+{
+ IC *p,*f=0;int i;Var *old;
+ old=o->v;
+ i=old->index;
+ if(!target&&(o->flags&DREFOBJ)) i+=vcount-rcount;
+ if(i<0||i>=vcount) ierror(0);
+ memcpy(tmp,cp_act,csize);
+ bvintersect(tmp,copies[i],csize);
+ /* waehrend diesem Durchlauf geaenderte Kopieranweisungen lieber nicht */
+ /* beachten */
+ bvdiff(tmp,cp_dest,csize);
+ for(i=0;i<ccount;i++){
+ if(BTST(tmp,i)){
+ p=clist[i];
+ if(p->z.v==o->v
+ &&(zmeqto(size,l2zm(0L))||zmeqto(size,p->q2.val.vmax))
+ &&p->q1.v!=o->v&&zmeqto(p->z.val.vmax,o->val.vmax)
+ &&(ISSCALAR(o->v->vtyp->flags)||(p->typf&NQ)==(o->v->vtyp->flags&NQ))
+ &&!must_convert(p->typf,o->v->vtyp->flags,0)
+ &&!is_volatile_ic(p)
+ ){
+ if(((o->flags&DREFOBJ)&&!(p->q1.flags&DREFOBJ))||!(p->q1.flags&DREFOBJ)&&(!static_cse||!((p->q1.flags&(VAR|VARADR))==VAR)||(p->q1.v->storage_class!=EXTERN&&p->q1.v->storage_class!=STATIC))){
+ int mdtyp;
+ if(DEBUG&1024){ printf("can replace <%s> by copy:\n",o->v->identifier);pric2(stdout,clist[i]);}
+ p->q1.flags&=~SCRATCH;
+ mdtyp=o->dtyp;
+ /* Maybe it would be more precise to recalculate all (D)NOTTYPESAFE
+ info afterwards */
+ if(o->v->flags&NOTTYPESAFE){
+ if((p->q1.flags&(VAR|VARADR))==VAR)
+ p->q1.v->flags|=NOTTYPESAFE;
+ }
+ if(o->v->flags&DNOTTYPESAFE){
+ if((p->q1.flags&(VAR|VARADR))==VAR)
+ p->q1.v->flags|=DNOTTYPESAFE;
+ }
+ *o=p->q1;
+ if(target){
+ o->flags|=DREFOBJ;
+ o->dtyp=mdtyp;
+ if((o->flags&(VARADR|DREFOBJ))==(VARADR|DREFOBJ))
+ o->flags&=~(VARADR|DREFOBJ);
+ update_alias(old,o->v);
+ /* Wenn eine Variable, dadurch zu einer DREF-Variable */
+ /* wird, muss num_vars spaeter erneut gemacht werden */
+ if(o->v->index>=rcount){
+ ierror(0);
+#if 0
+ update_alias(old,o->v);
+ return 2;
+#endif
+ }
+ }
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+int copy_propagation(flowgraph *fg,int global)
+/* gibt Kopien weiter */
+{
+ flowgraph *g; obj old;int or;
+ IC *p;Var *v;int i,changed,r,j;
+ if(DEBUG&1024) printf("searching copies\n");
+ cp_act=mymalloc(csize);
+ cp_dest=mymalloc(csize);
+ memset(cp_dest,0,csize);
+ tmp=mymalloc(csize);
+ g=fg;changed=0;
+ while(g){
+ if(!global) memset(cp_act,0,csize); else memcpy(cp_act,g->cp_in,csize);
+ p=g->start;
+ while(p){
+ zmax size;
+ if(p->code==ASSIGN||p->code==PUSH) size=p->q2.val.vmax;
+ else size=l2zm(0L);
+/* print_cp(cp_act); pric2(stdout,p);*/
+ r=0;
+ if(p->code!=ADDRESS&&p->code!=NOP){
+ if((p->q1.flags&(VAR|VARADR))==VAR){
+ r|=cprop(&p->q1,0,size);
+ if(p->q1.flags&DREFOBJ) r|=cprop(&p->q1,1,0);
+ }
+ if((p->q2.flags&(VAR|VARADR))==VAR){
+ /* passt auf, dass USEQ2ASZ nicht verletzt wird, ist dabei */
+ /* aber nicht sehr effizient (evtl. koennte kommutiert */
+ /* werden, o.ae.) */
+ if(!USEQ2ASZ){ old=p->q2;or=r;}
+ r|=cprop(&p->q2,0,size);
+ if(p->q2.flags&DREFOBJ) r|=cprop(&p->q2,1,0);
+ if(!USEQ2ASZ&&!compare_objs(&p->q2,&p->z,p->typf)){
+ if(DEBUG&1024) printf("copy propagation taken back, because of USEQ2ASZ\n");
+ p->q2=old;
+ r=or;
+ }
+ }
+ if((p->z.flags&(VAR|VARADR|DREFOBJ))==(VAR|DREFOBJ)){
+ /* passt auf, dass USEQ2ASZ nicht verletzt wird, ist dabei */
+ /* aber nicht sehr effizient (evtl. koennte kommutiert */
+ /* werden, o.ae. */
+ if(!USEQ2ASZ){ old=p->z;or=r;}
+ r|=cprop(&p->z,1,0);
+ if(!USEQ2ASZ&&!compare_objs(&p->q2,&p->z,p->typf)){
+ if(DEBUG&1024) printf("copy propagation taken back, because of USEQ2ASZ\n");
+ p->z=old;
+ r=or;
+ }
+ }
+ }
+ if(r&&p->copyindex>=0) BSET(cp_dest,p->copyindex);
+ changed|=r;
+
+ for(j=0;j<p->change_cnt;j++){
+ i=p->change_list[j].v->index;
+ if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+ if(i>=vcount) continue;
+ bvdiff(cp_act,copies[i],csize);
+ }
+ if(p->copyindex>=0) BSET(cp_act,p->copyindex);
+
+ if(p==g->end) break;
+ p=p->next;
+ }
+ g=g->normalout;
+ }
+ free(cp_act);
+ free(cp_dest);
+ free(tmp);
+ free(clist);
+ free(cp_globals);
+ free(cp_statics);
+ free(cp_address);
+ free(cp_drefs);
+ free(cp_matrix);
+ free(copies);
+ gchanged|=changed;
+ return changed;
+}
+
diff --git a/cse.c b/cse.c
new file mode 100644
index 0000000..e180d3d
--- /dev/null
+++ b/cse.c
@@ -0,0 +1,411 @@
+/* $VER: vbcc (cse.c) $Revision: 1.11 $ */
+/* verfuegbare Ausdruecke und common subexpression elimination */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+/* fuer verfuegbare Ausdruecke */
+IC **elist;
+unsigned int ecount;
+size_t esize;
+bvtype *ae_globals,*ae_statics,*ae_address,*ae_drefs;
+bvtype **ae_kills;
+
+static bvtype *cse_matrix;
+
+void available_expressions(flowgraph *fg)
+/* berechnet die verfuegbaren Ausdruecke fuer jeden Block */
+{
+ flowgraph *g;IC *p;bvtype *tmp;
+ int changed,pass,i,j;
+ unsigned long heapsize=0;
+ /* ae_gen und ae_kill fuer jeden Block berechnen */
+ if(DEBUG&1024) printf("analysing available expressions\n");
+ tmp=mymalloc(esize);
+ heapsize+=esize;
+ g=fg;
+ while(g){
+ g->ae_in=mymalloc(esize);
+ memset(g->ae_in,0,esize);
+ g->ae_out=mymalloc(esize);
+ memset(g->ae_out,0,esize);
+ g->ae_gen=mymalloc(esize);
+ memset(g->ae_gen,0,esize);
+ g->ae_kill=mymalloc(esize);
+ memset(g->ae_kill,0,esize);
+ heapsize+=4*esize;
+ p=g->end;
+ while(p){
+ memset(tmp,0,esize);
+ for(j=0;j<p->change_cnt;j++){
+ i=p->change_list[j].v->index;
+ if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+ if(i>=vcount) continue;
+ bvunite(tmp,ae_kills[i],esize);
+ }
+ bvdiff(tmp,g->ae_gen,esize);
+ bvunite(g->ae_kill,tmp,esize);
+ i=p->expindex;
+ if(i>=0&&!BTST(g->ae_kill,i)) BSET(g->ae_gen,i);
+
+ if(p==g->start) break;
+ p=p->prev;
+ }
+ if(g==fg){
+ memset(g->ae_in,0,esize);
+ memcpy(g->ae_out,g->ae_gen,esize);
+ }else{
+ memset(g->ae_out,UCHAR_MAX,esize);
+ bvdiff(g->ae_out,g->ae_kill,esize);
+ }
+ g=g->normalout;
+ }
+
+ /* ae_in und ae_out fuer jeden Block berechnen */
+ /* out(b)=U-gen(B) vorinitialisiert und */
+ /* in(B0)=0, out(B0)=gen(B0) */
+ if(DEBUG&1024) {printf("pass:");pass=0;}
+ do{
+ if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
+ changed=0;
+ g=fg->normalout; /* in B0 aendert sich nichts */
+ while(g){
+ flowlist *lp;
+ /* in(B)=Schnitt out(P) mit P Vorgaenger von B */
+ lp=g->in;
+ i=0; /* Flag fuer ersten Vorgaenger */
+ while(lp){
+ if(!lp->graph) ierror(0);
+ if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA){
+ if(i){
+ bvintersect(g->ae_in,lp->graph->ae_out,esize);
+ }else{
+ memcpy(g->ae_in,lp->graph->ae_out,esize);i=1;
+ }
+ }
+ lp=lp->next;
+ }
+ /* out(b)=gen(B) U (in(B)-kill(B) */
+ memcpy(tmp,g->ae_in,esize);
+ bvdiff(tmp,g->ae_kill,esize);
+ bvunite(tmp,g->ae_gen,esize);
+ if(!bvcmp(tmp,g->ae_out,esize)){changed=1;memcpy(g->ae_out,tmp,esize);}
+ g=g->normalout;
+ }
+ }while(changed);
+ if(DEBUG&1024) printf("\n");
+ if(DEBUG&16384) printf("available expressions heapsize=%lu\n",heapsize);
+ free(tmp);
+}
+
+int compare_objs(obj *o1,obj *o2,int t)
+/* Vergleicht die beiden Objekte; liefert 0, wenn sie gleich sind, sonst */
+/* 1 oder -1, um eine Ordnung darauf zu definieren */
+{
+ int i1,i2;
+ i1=o1->flags&~SCRATCH;i2=o2->flags&~SCRATCH;
+ if(i1<i2) return -1;
+ if(i1>i2) return 1;
+ if(i1&DREFOBJ){
+ if(o1->dtyp<o2->dtyp) return -1;
+ if(o1->dtyp>o2->dtyp) return 1;
+ }
+ if(i1&KONST) return(compare_const(&o1->val,&o2->val,t));
+ if(i1&VAR){
+ i1=o1->v->index; i2=o2->v->index;
+ if(i1<i2) return -1;
+ if(i1>i2) return 1;
+ if(!zmeqto(o1->val.vmax,o2->val.vmax)){
+ if(zmleq(o1->val.vmax,o2->val.vmax))
+ return -1;
+ else
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int compare_exp(const void *a1,const void *a2)
+/* Stub fuer compare_objs, damit als Vergleichsfunktion fuer qsort geht */
+{
+ IC *p1,*p2;int i1,i2;
+ p1=*((IC **)a1);p2=*((IC **)a2);
+ if(!p1||!p2) ierror(0);
+ i1=p1->code; i2=p2->code;
+ if(i1<i2) return -1;
+ if(i1>i2) return 1;
+ i1=p1->typf&(NU|VOLATILE|SIGNED_CHARACTER); i2=p2->typf&(NU|VOLATILE|SIGNED_CHARACTER);
+ if(i1<i2) return -1;
+ if(i1>i2) return 1;
+ i1=compare_objs(&p1->q1,&p2->q1,q1typ(p1));
+ if(i1) return i1;
+ i1=compare_objs(&p1->q2,&p2->q2,q2typ(p1));
+ return i1;
+}
+
+void print_ae(bvtype *exp)
+{
+ int i;
+ if(!exp){ printf("available expressions not available\n"); return;}
+ for(i=0;i<ecount;i++)
+ if(BTST(exp,i))
+ {printf("%3d,%3d: ",elist[i]->expindex,i);pric2(stdout,elist[i]);}
+}
+void num_exp(void)
+/* numeriert die Ausdruecke so, dass gleiche Ausdruecke die gleiche */
+/* nummer erhalten */
+{
+ IC *p;int c,i;
+ bvtype *bp;
+ unsigned long heapsize=0;
+ if(DEBUG&1024) printf("numerating expressions\n");
+ ecount=0;
+ if(DEBUG&1024){ printf("num_exp loop1\n");}
+ for(p=first_ic;p;p=p->next){
+ c=p->code;
+ if(p->z.flags&&p->q1.flags&&(c!=ASSIGN||(p->q1.flags&DREFOBJ)||(static_cse&&(p->q1.flags&(VAR|VARADR))==VAR&&ISSCALAR(p->q1.v->vtyp->flags)&&(p->q1.v->storage_class==EXTERN||p->q1.v->storage_class==STATIC)))&&c!=MOVETOREG&&c!=MOVEFROMREG){
+ p->expindex=ecount++;
+ if(c==ADD||c==MULT||(c>=OR&&c<=AND)){
+ if(p->q2.flags&&compare_objs(&p->q1,&p->q2,p->typf)<0&&(USEQ2ASZ||compare_objs(&p->q1,&p->z,p->typf))){
+ obj o;
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ }
+ }
+ }else p->expindex=-1;
+ }
+ elist=mymalloc(ecount*sizeof(IC *));
+ heapsize+=ecount*sizeof(IC *);
+ if(DEBUG&1024){ printf("num_exp loop2\n");}
+ for(p=first_ic;p;p=p->next){
+ if(p->expindex>=0){
+ elist[p->expindex]=p;
+ }
+ }
+ /*esize=(ecount+CHAR_BIT-1)/CHAR_BIT;*/
+ esize=BVSIZE(ecount);
+ if(DEBUG&(16384|1024)){ printf("%lu expressions, esize=%lu\nsorting expressions\n",(unsigned long)ecount,(unsigned long)esize);}
+ if(ecount>1) vqsort(elist,ecount,sizeof(IC *),compare_exp);
+ if(DEBUG&1024){ printf("renumbering expressions\nnum_exp loop3\n");}
+ if(ecount>0){ /* Aufpassen, da ecount unsigned! */
+ for(c=0;c<ecount-1;c++){
+ if(!compare_exp(&elist[c],&elist[c+1]))
+ elist[c+1]->expindex=elist[c]->expindex;
+ }
+ }
+ if(DEBUG&1024) printf("re-sorting expressions\n");
+ /* wieder in die richtige Reihenfolge bringen */
+ for(p=first_ic;p;p=p->next)
+ if(p->expindex>=0) elist[p->expindex]=p;
+ ae_globals=mymalloc(esize);
+ memset(ae_globals,0,esize);
+ ae_statics=mymalloc(esize);
+ memset(ae_statics,0,esize);
+ ae_address=mymalloc(esize);
+ memset(ae_address,0,esize);
+ ae_drefs=mymalloc(esize);
+ memset(ae_drefs,0,esize);
+ heapsize+=esize;
+ if(DEBUG&1024){ printf("num_exp loop4\n");}
+ ae_kills=mymalloc(vcount*sizeof(bvtype *));
+ heapsize+=vcount*sizeof(bvtype *);
+ cse_matrix=bp=mymalloc(vcount*esize);
+ heapsize+=vcount*esize;
+ memset(bp,0,vcount*esize);
+ for(c=0;c<vcount;c++){
+ ae_kills[c]=bp;
+ bp+=esize/sizeof(bvtype);
+ }
+ if(DEBUG&1024){ printf("num_exp loop5\n");}
+ for(c=0;c<ecount;c++){
+ Var *v;
+/* if(c<ecount-1&&elist[c]==elist[c+1]) continue;*/ /* gleiche ueberspringen */
+ p=elist[c];
+ if(p->code==ADDRESS) continue;
+ if((p->q1.flags&(VAR|VARADR))==VAR){
+ v=p->q1.v;
+ i=v->index;
+ BSET(ae_kills[i],c);
+ if(p->q1.flags&DREFOBJ){ BSET(ae_kills[i+vcount-rcount],c);BSET(ae_drefs,c);}
+ if(v->nesting==0||v->storage_class==EXTERN) BSET(ae_globals,c);
+ if(v->storage_class==STATIC) BSET(ae_statics,c);
+ if(v->flags&USEDASADR) BSET(ae_address,c);
+ }
+ if((p->q2.flags&(VAR|VARADR))==VAR){
+ v=p->q2.v;
+ i=v->index;
+ BSET(ae_kills[i],c);
+ if(p->q2.flags&DREFOBJ){ BSET(ae_kills[i+vcount-rcount],c);BSET(ae_drefs,c);}
+ if(v->nesting==0||v->storage_class==EXTERN) BSET(ae_globals,c);
+ if(v->storage_class==STATIC) BSET(ae_statics,c);
+ if(v->flags&USEDASADR) BSET(ae_address,c);
+ }
+ }
+ if(DEBUG&16384) printf("num_exp heapsize=%lu\n",heapsize);
+}
+void cse_replace(flowgraph *g,IC *p,IC *o,Var *v)
+/* ersetzt die cse bei o zu p mit Variable v */
+{
+ IC *n;
+ /* Kopieranweisung erzeugen */
+ if(DEBUG&1024) printf("cse_replace\n");
+ n=new_IC();
+ n->line=o->line;
+ n->file=o->file;
+ n->code=ASSIGN;
+ n->typf=p->typf;
+ n->expindex=n->defindex=-1;
+ n->q2.flags=0;
+ n->q2.val.vmax=szof(v->vtyp);
+ n->q1.flags=VAR;
+ n->q1.v=v;
+ n->q1.val.vmax=l2zm(0L);
+ n->z=o->z;
+
+ /* Die Kopieranweisung benutzt hoechstens, was die urspruengliche */
+ /* Operation benutzt hat+die Hilfsvariable und aendert nur, was */
+ /* die urspruengliche vorher geaendert hat. */
+ if(have_alias){
+ n->use_cnt=o->use_cnt+1;
+ n->use_list=mymalloc(n->use_cnt*VLS);
+ n->use_list[0].v=v;
+ n->use_list[0].flags=0;
+ memcpy(&n->use_list[1],o->use_list,o->use_cnt*VLS);
+ n->change_cnt=o->change_cnt;
+ n->change_list=o->change_list;
+ }
+ /* evtl. FLussgraph korrigieren */
+ if(g->end==o) g->end=n;
+ /* einfuegen */
+ insert_IC(o,n);
+ /* Operation auf Hilfsvariable umlenken */
+ o->z=n->q1;
+ /* Operation aendert nun nur Hilfsvariable. */
+ if(have_alias){
+ /* Liste nicht freigeben, da sie umgebogen wird. */
+ o->change_cnt=1;
+ o->change_list=mymalloc(VLS);
+ o->change_list[0].v=v;
+ o->change_list[0].flags=0;
+ }
+}
+void cse_search(flowgraph *g,IC *p,IC *o,Var *v,int global,bvtype *bmk)
+/* sucht die Quelle(n) fuer common subexpression und ersetzt sie */
+/* bmk ist Buffer, um zu merken, welche Bloecke schon besucht sind */
+{
+ flowlist *lp;
+ /* Letzte Berechnung des Ausdrucks suchen, beginnend bei o */
+ /* bei global kann o auch 0 sein! */
+/* if(DEBUG&1024) printf("cse_search\n");*/
+ if(global){
+ if(BTST(bmk,g->index)) return;
+ }
+ while(o&&o->expindex!=p->expindex){
+ if(o==g->start) break;
+ o=o->prev;
+ }
+ if(!o&&!global) ierror(0);
+ if(o&&o->expindex==p->expindex){
+ if(!(o->z.flags&VAR)||o->z.v!=v)
+ cse_replace(g,p,o,v);
+ return;
+ }
+ if(!global) ierror(0);
+ /* Block als besucht markieren, wenn er durchsucht wurde. Der */
+ /* erste Block bei globaler Suche muss beachtet werden und */
+ /* Endlosschleifen vermieden werden. */
+ if(o||!g->end) BSET(bmk,g->index);
+ lp=g->in;
+ while(lp){
+ if(!lp->graph) ierror(0);
+ if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA){
+ cse_search(lp->graph,p,lp->graph->end,v,global,bmk);
+ }
+ lp=lp->next;
+ }
+}
+
+int cse(flowgraph *fg,int global)
+/* common-subexpression-elimination; wenn global==0 werden nur einzelne */
+/* Bloecke betrachtet */
+{
+ flowgraph *g;IC *p,*o;int changed,i,j;
+ bvtype *ae,*done;Var *v;type *new;
+ if(DEBUG&1024) printf("common-subexpression-elimination\n");
+ changed=0;
+ ae=mymalloc(esize);
+ if(global){
+ done=mymalloc(esize);
+ memset(done,0,esize);
+ }else
+ done=0;
+ for(g=fg;g;g=g->normalout){
+ if(!global) memset(ae,0,esize); else memcpy(ae,g->ae_in,esize);
+ p=g->start;
+ while(p){
+ i=p->expindex;
+ /* TODO: correctly handle KONST|DREFOBJ in change_list and enable KONST|DREFOBJ */
+ if(i>=0&&!is_volatile_ic(p)&&(p->q1.flags&(KONST|DREFOBJ))!=(KONST|DREFOBJ)&&(p->q2.flags&(KONST|DREFOBJ))!=(KONST|DREFOBJ)){
+ if(!global||!BTST(done,i)){
+ int t=ztyp(p);
+ if(i>=ecount) ierror(0);
+ if(p->code==ASSIGN&&!zmeqto(p->q2.val.vmax,sizetab[t&NQ])) t=ARRAY; /* no memcpy ICs */
+ if(BTST(ae,i)&&ISSCALAR(t)&&!(elist[i]->flags&EFF_IC)){
+ if(DEBUG&1024){ printf("can eliminate common subexpression:\n");pric2(stdout,p);}
+ /* Hilfsvariable erzeugen */
+ new=new_typ();
+ new->flags=t;
+ if(p->code==COMPARE||p->code==TEST) new->flags=0;
+ if(ISPOINTER(new->flags)){
+ new->next=new_typ();
+ new->next->flags=VOID;
+ }
+ v=add_tmp_var(new);
+ v->index=-1;
+ /* Operation durch assign Hilfsvariable ersetzen */
+ p->code=ASSIGN;
+ p->typf=new->flags;
+ p->q1.flags=VAR;
+ p->q1.v=v;
+ p->q1.val.vmax=l2zm(0L);
+ p->q2.flags=0;
+ p->q2.val.vmax=szof(new);
+ if(global){
+ bvtype *bmk;size_t bsize;
+ /*bsize=(basic_blocks+CHAR_BIT)/CHAR_BIT;*/
+ bsize=BVSIZE(basic_blocks+1);
+ bmk=mymalloc(bsize);
+ memset(bmk,0,bsize);
+ cse_search(g,p,0,v,global,bmk);
+ free(bmk);
+ BSET(done,i);
+ }else
+ cse_search(g,p,p->prev,v,global,0);
+ changed=1;
+ gchanged|=1;
+ }else BSET(ae,i);
+ }
+ }
+ for(j=0;j<p->change_cnt;j++){
+ i=p->change_list[j].v->index;
+ if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+ if(i>=vcount) continue;
+ bvdiff(ae,ae_kills[i],esize);
+ }
+ if(p==g->end) break;
+ p=p->next;
+ }
+ }
+
+ free(done);
+ free(ae);
+ free(cse_matrix);
+ free(ae_kills);
+ free(ae_globals);
+ free(ae_statics);
+ free(ae_address);
+ free(ae_drefs);
+ free(elist);
+
+ return changed;
+}
diff --git a/datatypes/datatypes.h b/datatypes/datatypes.h
new file mode 100755
index 0000000..75cf5a3
--- /dev/null
+++ b/datatypes/datatypes.h
@@ -0,0 +1,36 @@
+/* elementary data types currently known to vbcc */
+
+/* unsigned 8bit byte */
+"S8BU", "standard unsigned 8bit byte",
+
+/* signed 8bit byte */
+"S8BS", "standard 2-complement 8bit byte",
+
+/* typical unsigned integers, big-endian */
+"S16BUBE", "standard 8bit-byte-based unsigned 16bit word, big-endian",
+"S32BUBE", "standard 8bit-byte-based unsigned 32bit word, big-endian",
+"S64BUBE", "standard 8bit-byte-based unsigned 64bit byte, big-endian",
+
+/* typical unsigned integers, little-endian */
+"S16BULE", "standard 8bit-byte-based unsigned 16bit word, little-endian",
+"S32BULE", "standard 8bit-byte-based unsigned 32bit word, little-endian",
+"S64BULE", "standard 8bit-byte-based unsigned 64bit byte, little-endian",
+
+/* typical signed integers, big-endian */
+"S16BSBE", "standard 8bit-byte-based 2-complement 16bit word, big-endian",
+"S32BSBE", "standard 8bit-byte-based 2-complement 32bit word, big-endian",
+"S64BSBE", "standard 8bit-byte-based 2-complement 64bit word, big-endian",
+
+/* typical signed integers, little-endian */
+"S16BSLE", "standard 8bit-byte-based 2-complement 16bit word, little-endian",
+"S32BSLE", "standard 8bit-byte-based 2-complement 32bit word, little-endian",
+"S64BSLE", "standard 8bit-byte-based 2-complement 64bit word, little-endian",
+
+/* typical IEEE-floats, big-endian */
+"S32BIEEEBE", "standard 8bit-byte-based 32bit IEEE floating-point, big-endian",
+"S64BIEEEBE", "standard 8bit-byte-based 64bit IEEE floating-point, big-endian",
+
+/* typical IEEE-floats, little-endian */
+"S32BIEEELE", "standard 8bit-byte-based 32bit IEEE floating-point, little-endian",
+"S64BIEEELE", "standard 8bit-byte-based 64bit IEEE floating-point, little-endian",
+
diff --git a/datatypes/dtconv.h b/datatypes/dtconv.h
new file mode 100755
index 0000000..7fe6cd8
--- /dev/null
+++ b/datatypes/dtconv.h
@@ -0,0 +1,20 @@
+"S16BSBE","S16BSLE","dtswap16f.c","dtswap16t.c",2,
+"S16BUBE","S16BULE","dtswap16f.c","dtswap16t.c",2,
+"S32BSBE","S32BSLE","dtswap32f.c","dtswap32t.c",4,
+"S32BUBE","S32BULE","dtswap32f.c","dtswap32t.c",4,
+"S64BSBE","S64BSLE","dtswap64f.c","dtswap64t.c",8,
+"S64BUBE","S64BULE","dtswap64f.c","dtswap64t.c",8,
+"S32BIEEEBE","S32BIEEELE","dtswap32f.c","dtswap32t.c",4,
+"S64BIEEEBE","S64BIEEELE","dtswap64f.c","dtswap64t.c",8,
+"S16BSLE","S16BSBE","dtswap16f.c","dtswap16t.c",2,
+"S16BULE","S16BUBE","dtswap16f.c","dtswap16t.c",2,
+"S32BSLE","S32BSBE","dtswap32f.c","dtswap32t.c",4,
+"S32BULE","S32BUBE","dtswap32f.c","dtswap32t.c",4,
+"S64BSLE","S64BSBE","dtswap64f.c","dtswap64t.c",8,
+"S64BULE","S64BUBE","dtswap64f.c","dtswap64t.c",8,
+"S32BIEEELE","S32BIEEEBE","dtswap32f.c","dtswap32t.c",4,
+"S64BIEEELE","S64BIEEEBE","dtswap64f.c","dtswap64t.c",8,
+
+#include "dtwidths.h"
+
+
diff --git a/datatypes/dtf.c b/datatypes/dtf.c
new file mode 100644
index 0000000..be36f46
--- /dev/null
+++ b/datatypes/dtf.c
@@ -0,0 +1,11 @@
+from)
+{
+ DTTTYPE to=0;
+ int i,j=0;
+ for(i=sizeof(from.a)-1;i>=0;i--)
+ to=(to<<8)|(from.a[i]&255);
+
+ to<<=(sizeof(to)*8)-BITSIZE;
+ to>>=(sizeof(to)*8)-BITSIZE;
+ return to;
+}
diff --git a/datatypes/dtgen.c b/datatypes/dtgen.c
new file mode 100755
index 0000000..513d20c
--- /dev/null
+++ b/datatypes/dtgen.c
@@ -0,0 +1,397 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+
+#ifndef __STDC_VERSION__
+#ifdef __GNUC__
+#define __STDC_VERSION__ 199901L
+#endif
+#endif
+
+struct dtlist {char *spec,*descr;} dts[]={
+#include "datatypes.h"
+};
+
+struct dtconvlist {char *from,*to,*filef,*filet;int size;} cnvs[]={
+#include "dtconv.h"
+};
+
+int dtcnt=sizeof(dts)/sizeof(dts[0]);
+int cnvcnt=sizeof(cnvs)/sizeof(cnvs[0]);
+
+signed char *have;
+
+#define CHAR 1
+#define UCHAR 2
+#define SHORT 3
+#define USHORT 4
+#define INT 5
+#define UINT 6
+#define LONG 7
+#define ULONG 8
+#define LLONG 9
+#define ULLONG 10
+#define FLOAT 11
+#define DOUBLE 12
+#define LDOUBLE 13
+#define POINTER 14
+
+#define TYPECNT POINTER
+
+char *typen[TYPECNT+1]={"error","char","uchar","short","ushort","int","uint",
+ "long","ulong","llong","ullong","float","double","ldouble",
+ "pointer"};
+char *ftypen[TYPECNT+1]={"error","char","unsigned char","short","unsigned short",
+ "int","unsigned int","long","unsigned long",
+ "long long","unsigned long long",
+ "float","double","long double",
+ "char *"};
+
+int dt[TYPECNT+1],cnv[TYPECNT+1];
+char *nt[TYPECNT+1];
+FILE *fin,*cout,*hout;
+int crosscompiler;
+
+void *mymalloc(size_t size)
+{
+ void *p=malloc(size);
+ if(!p){
+ printf("Out of memory!\n");
+ exit(EXIT_FAILURE);
+ }
+ return p;
+}
+
+#define TESTTYPE(type,VALA,VALB) \
+ if(sizeof(type)*CHAR_BIT==bits){\
+ type tst=VALA;\
+ if(islittle&&*((unsigned char *)&tst)==VALB)\
+ return yn?"y":#type;\
+ if(isbig&&*(((unsigned char *)(&tst+1))-1)==VALB)\
+ return yn?"y":#type;\
+ }\
+
+
+char *yndefault(char *spec,int yn)
+{
+ int isieee=0,isunsigned=0,issigned,islittle=0,isbig=0,bits=0;
+ char *none;
+ if(yn) none="n"; else none="";
+ if(*spec++!='S') return none;
+ while(isdigit(*(unsigned char *)spec))
+ bits=bits*10+*spec++-'0';
+ if(*spec++!='B') return none;
+ if(!strncmp(spec,"IEEE",4))
+ {isieee=1;spec+=4;}
+ else if(*spec=='U')
+ {isunsigned=1;spec++;}
+ else if(*spec=='S')
+ {issigned=1;spec++;}
+ else
+ return none;
+ if(spec[0]=='B'&&spec[1]=='E')
+ {isbig=1;spec++;}
+ else if(spec[0]=='L'&&spec[1]=='E')
+ {islittle=1;spec++;}
+ else
+ islittle=isbig=1;
+ if(isieee){
+ TESTTYPE(float,1.0,0);
+ TESTTYPE(double,1.0,0);
+ TESTTYPE(long double,1.0,0);
+ return none;
+ }
+ if(isunsigned){
+ TESTTYPE(unsigned char,123,123);
+ TESTTYPE(unsigned short,123,123);
+ TESTTYPE(unsigned int,123,123);
+ TESTTYPE(unsigned long,123,123);
+#if __STDC_VERSION__==199901L
+ TESTTYPE(unsigned long long,123,123);
+#endif
+ return none;
+ }
+ if(issigned){
+ TESTTYPE(signed char,123,123);
+ TESTTYPE(signed short,123,123);
+ TESTTYPE(signed int,123,123);
+ TESTTYPE(signed long,123,123);
+#if __STDC_VERSION__==199901L
+ TESTTYPE(signed long long,123,123);
+#endif
+ return none;
+ }
+ return none;
+}
+
+
+int askyn(char *def)
+{
+ char in[8];
+ do{
+ printf("Type y or n [%s]: ",def);
+ fflush(stdout);
+ fgets(in,sizeof(in),stdin);
+ if(*in=='\n') strcpy(in,def);
+ }while(*in!='y'&&*in!='n');
+ return *in=='y';
+}
+
+char *asktype(char *def)
+{
+ char *in=mymalloc(128);
+ printf("Enter that type[%s]: ",def);
+ fflush(stdout);
+ fgets(in,127,stdin);
+ if(in[strlen(in)-1]=='\n') in[strlen(in)-1]=0;
+ if(!*in) strcpy(in,def);
+ return in;
+}
+
+int tst(int type,char *spec)
+{
+ int i,j;
+ for(i=0;i<dtcnt;i++){
+ if(strstr(spec,dts[i].spec)){
+ if(have[i]==-2) continue;
+ if(have[i]>=0){
+/* printf("auto: %s == %s\n",dts[i].spec,nt[have[i]]); */
+ dt[type]=i;
+ nt[type]=nt[have[i]];
+ cnv[type]=-1;
+ return 1;
+ }else{
+ printf("Does your system/compiler support a type implemented as\n%s?\n",dts[i].descr);
+ if(askyn(yndefault(dts[i].spec,1))){
+ dt[type]=i;
+ nt[type]=asktype(yndefault(dts[i].spec,0));
+ have[i]=type;
+ cnv[type]=-1;
+ return 1;
+ }else{
+ have[i]=-2;
+ }
+ }
+ }
+ }
+ for(j=0;j<cnvcnt;j++){
+ char *s=0;
+ if(strstr(spec,cnvs[j].from)) s=cnvs[j].to;
+/* if(strstr(spec,cnvs[j].to)) s=cnvs[j].from; */
+ if(s){
+ for(i=0;i<dtcnt;i++){
+ if(!strcmp(s,dts[i].spec)){
+ if(have[i]==-2) continue;
+ if(have[i]>=0){
+ dt[type]=i;
+ nt[type]=nt[have[i]];
+ cnv[type]=j;
+ return 2;
+ }else{
+ printf("Does your system/compiler support a type implemented as\n%s?\n",dts[i].descr);
+ if(askyn(yndefault(dts[i].spec,1))){
+ dt[type]=i;
+ nt[type]=asktype(yndefault(dts[i].spec,0));
+ have[i]=type;
+ cnv[type]=j;
+ return 2;
+ }else{
+ have[i]=-2;
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+char *castfrom(int type)
+{
+ if(cnv[type]>=0){
+ char *s=mymalloc(16);
+ sprintf(s,"dtcnv%df",type);
+ return s;
+ }else{
+ return "";
+ }
+}
+char *castto(int type)
+{
+ if(cnv[type]>=0){
+ char *s=mymalloc(16);
+ sprintf(s,"dtcnv%dt",type);
+ return s;
+ }else{
+ return "";
+ }
+}
+void gen_cast(char *name,int from,int to)
+{
+ fprintf(hout,"#define %s(x) %s((%s)%s(x))\n",name,castto(to),nt[to],castfrom(from));
+}
+void gen_2op(char *name,char *op,int type)
+{
+ fprintf(hout,"#define %s(a,b) %s(%s(a)%s%s(b))\n",name,castto(type),castfrom(type),op,castfrom(type));
+}
+void gen_1op(char *name,char *op,int type)
+{
+ fprintf(hout,"#define %s(a) %s(%s%s(a))\n",name,castto(type),op,castfrom(type));
+}
+void gen_cmp(char *name,char *op,int type)
+{
+ fprintf(hout,"#define %s(a,b) (%s(a)%s%s(b))\n",name,castfrom(type),op,castfrom(type));
+}
+int main(int argc,char **argv)
+{
+ char type[128],spec[128];
+ int i,r;
+ if(argc!=4){ printf("Usage: dtgen <config-file> <output-file.h> <output-file.c>\n");exit(EXIT_FAILURE);}
+/* printf("%d datatypes, %d conversions\n",dtcnt,cnvcnt); */
+ have=mymalloc(dtcnt*sizeof(*have));
+ memset(have,-1,sizeof(*have)*dtcnt);
+ fin=fopen(argv[1],"r");
+ if(!fin){ printf("Could not open <%s> for input!\n",argv[1]);exit(EXIT_FAILURE);}
+ hout=fopen(argv[2],"w");
+ if(!hout){ printf("Could not open <%s> for output!\n",argv[2]);exit(EXIT_FAILURE);}
+ cout=fopen(argv[3],"w");
+ if(!hout){ printf("Could not open <%s> for output!\n",argv[3]);exit(EXIT_FAILURE);}
+ printf("Are you building a cross-compiler?\n");
+ crosscompiler=askyn("y");
+ for(i=1;i<=TYPECNT;i++){
+ fgets(spec,127,fin);
+/* printf("Specs for z%s:\n%s\n",typen[i],spec); */
+ if(!crosscompiler){
+ dt[i]=i;
+ nt[i]=ftypen[i];
+ have[i]=i;
+ cnv[i]=-1;
+ }else{
+ if(!tst(i,spec)){
+ printf("Problem! Your system does not seem to provide all of the data types\n"
+ "this version of vbcc needs.\nWrite to vb@compilers.de!\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+ fprintf(hout,"\n\n/* Machine generated file. DON'T TOUCH ME! */\n\n\n");
+ fprintf(cout,"\n\n/* Machine generated file. DON'T TOUCH ME! */\n\n\n");
+ fprintf(hout,"#ifndef DT_H\n");
+ fprintf(hout,"#define DT_H 1\n");
+ fprintf(cout,"#include \"dt.h\"\n\n");
+ for(i=1;i<=TYPECNT;i++){
+ if(cnv[i]>=0){
+ int bits;
+ sscanf(cnvs[cnv[i]].from,"S%dB",&bits);
+ fprintf(hout,"typedef struct {char a[%d];} dt%df;\n",cnvs[cnv[i]].size,i);
+ fprintf(hout,"typedef dt%df z%s;\n",i,typen[i]);
+ fprintf(hout,"typedef %s dt%dt;\n",nt[i],i);
+ fprintf(hout,"dt%dt dtcnv%df(dt%df);\n",i,i,i);
+ fprintf(hout,"dt%df dtcnv%dt(dt%dt);\n",i,i,i);
+ fprintf(cout,"#undef BITSIZE\n#define BITSIZE %d\n",bits);
+ fprintf(cout,"#undef DTTTYPE\n#define DTTTYPE dt%dt\n",i);
+ fprintf(cout,"#undef DTFTYPE\n#define DTFTYPE dt%df\n",i);
+ fprintf(cout,"dt%dt dtcnv%df(dt%df\n",i,i,i);
+ fprintf(cout,"#include \"%s\"\n",cnvs[cnv[i]].filef);
+ fprintf(cout,"dt%df dtcnv%dt(dt%dt\n",i,i,i);
+ fprintf(cout,"#include \"%s\"\n",cnvs[cnv[i]].filet);
+ }else{
+ fprintf(hout,"typedef %s z%s;\n",nt[i],typen[i]);
+ }
+ }
+
+ gen_cast("zc2zm",CHAR,LLONG);
+ gen_cast("zs2zm",SHORT,LLONG);
+ gen_cast("zi2zm",INT,LLONG);
+ gen_cast("zl2zm",LONG,LLONG);
+ gen_cast("zll2zm",LLONG,LLONG);
+ gen_cast("zm2zc",LLONG,CHAR);
+ gen_cast("zm2zs",LLONG,SHORT);
+ gen_cast("zm2zi",LLONG,INT);
+ gen_cast("zm2zl",LLONG,LONG);
+ gen_cast("zm2zll",LLONG,LLONG);
+
+ gen_cast("zuc2zum",UCHAR,ULLONG);
+ gen_cast("zus2zum",USHORT,ULLONG);
+ gen_cast("zui2zum",UINT,ULLONG);
+ gen_cast("zul2zum",ULONG,ULLONG);
+ gen_cast("zull2zum",ULLONG,ULLONG);
+ gen_cast("zum2zuc",ULLONG,UCHAR);
+ gen_cast("zum2zus",ULLONG,USHORT);
+ gen_cast("zum2zui",ULLONG,UINT);
+ gen_cast("zum2zul",ULLONG,ULONG);
+ gen_cast("zum2zull",ULLONG,ULLONG);
+
+ gen_cast("zum2zm",ULLONG,LLONG);
+ gen_cast("zm2zum",LLONG,ULLONG);
+ gen_cast("zf2zld",FLOAT,LDOUBLE);
+ gen_cast("zd2zld",DOUBLE,LDOUBLE);
+ gen_cast("zld2zf",LDOUBLE,FLOAT);
+ gen_cast("zld2zd",LDOUBLE,DOUBLE);
+ gen_cast("zld2zm",LDOUBLE,LLONG);
+ gen_cast("zm2zld",LLONG,LDOUBLE);
+ gen_cast("zld2zum",LDOUBLE,ULLONG);
+ gen_cast("zum2zld",ULLONG,LDOUBLE);
+ gen_cast("zp2zum",POINTER,ULLONG);
+ gen_cast("zum2zp",ULLONG,POINTER);
+
+ fprintf(hout,"#define l2zm(x) %s((%s)(x))\n",castto(LLONG),nt[LLONG]);
+ fprintf(hout,"#define ul2zum(x) %s((%s)(x))\n",castto(ULLONG),nt[ULLONG]);
+ fprintf(hout,"#define d2zld(x) %s((%s)(x))\n",castto(LDOUBLE),nt[LDOUBLE]);
+ fprintf(hout,"#define zm2l(x) ((long)%s(x))\n",castfrom(LLONG));
+ fprintf(hout,"#define zum2ul(x) ((unsigned long)%s(x))\n",castfrom(ULLONG));
+ fprintf(hout,"#define zld2d(x) ((double)%s(x))\n",castfrom(LDOUBLE));
+
+ gen_2op("zmadd","+",LLONG);
+ gen_2op("zumadd","+",ULLONG);
+ gen_2op("zldadd","+",LDOUBLE);
+ gen_2op("zmsub","-",LLONG);
+ gen_2op("zumsub","-",ULLONG);
+ gen_2op("zldsub","-",LDOUBLE);
+ gen_2op("zmmult","*",LLONG);
+ gen_2op("zummult","*",ULLONG);
+ gen_2op("zldmult","*",LDOUBLE);
+ gen_2op("zmdiv","/",LLONG);
+ gen_2op("zumdiv","/",ULLONG);
+ gen_2op("zlddiv","/",LDOUBLE);
+ gen_2op("zmmod","%",LLONG);
+ gen_2op("zummod","%",ULLONG);
+ gen_2op("zmlshift","<<",LLONG);
+ gen_2op("zumlshift","<<",ULLONG);
+ gen_2op("zmrshift",">>",LLONG);
+ gen_2op("zumrshift",">>",ULLONG);
+ gen_2op("zmand","&",LLONG);
+ gen_2op("zumand","&",ULLONG);
+ gen_2op("zmor","|",LLONG);
+ gen_2op("zumor","|",ULLONG);
+ gen_2op("zmxor","^",LLONG);
+ gen_2op("zumxor","^",ULLONG);
+ gen_2op("zmmod","%",LLONG);
+ gen_2op("zummod","%",ULLONG);
+
+ gen_1op("zmkompl","~",LLONG);
+ gen_1op("zumkompl","~",ULLONG);
+
+ gen_cmp("zmleq","<=",LLONG);
+ gen_cmp("zumleq","<=",ULLONG);
+ gen_cmp("zldleq","<=",LDOUBLE);
+ gen_cmp("zmeqto","==",LLONG);
+ gen_cmp("zumeqto","==",ULLONG);
+ gen_cmp("zldeqto","==",LDOUBLE);
+
+ fprintf(hout,"#endif\n");
+
+ fclose(fin);
+ fclose(hout);
+ fclose(cout);
+ free(have);
+ return 0;
+}
+
+
+
+
+
+
diff --git a/datatypes/dtswap32f.c b/datatypes/dtswap32f.c
new file mode 100755
index 0000000..44e0640
--- /dev/null
+++ b/datatypes/dtswap32f.c
@@ -0,0 +1,13 @@
+from)
+{
+ DTTTYPE to;
+ unsigned char *fp=((unsigned char *)&from)+3,*tp=(unsigned char *)&to;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ return to;
+}
+
+
+
diff --git a/datatypes/dtswap32t.c b/datatypes/dtswap32t.c
new file mode 100755
index 0000000..38f2637
--- /dev/null
+++ b/datatypes/dtswap32t.c
@@ -0,0 +1,13 @@
+from)
+{
+ DTFTYPE to;
+ unsigned char *fp=((unsigned char *)&from)+3,*tp=(unsigned char *)&to;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ return to;
+}
+
+
+
diff --git a/datatypes/dtswap64f.c b/datatypes/dtswap64f.c
new file mode 100755
index 0000000..c8cc74c
--- /dev/null
+++ b/datatypes/dtswap64f.c
@@ -0,0 +1,17 @@
+from)
+{
+ DTTTYPE to;
+ unsigned char *fp=((unsigned char *)&from)+7,*tp=(unsigned char *)&to;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ return to;
+}
+
+
+
diff --git a/datatypes/dtswap64t.c b/datatypes/dtswap64t.c
new file mode 100755
index 0000000..fd1d0a3
--- /dev/null
+++ b/datatypes/dtswap64t.c
@@ -0,0 +1,17 @@
+from)
+{
+ DTFTYPE to;
+ unsigned char *fp=((unsigned char *)&from)+7,*tp=(unsigned char *)&to;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ *tp++=*fp--;
+ return to;
+}
+
+
+
diff --git a/datatypes/dtt.c b/datatypes/dtt.c
new file mode 100644
index 0000000..57b2de5
--- /dev/null
+++ b/datatypes/dtt.c
@@ -0,0 +1,11 @@
+from)
+{
+ DTFTYPE to;
+ int i;
+ from&=(((DTTTYPE)1)<<BITSIZE)-1;
+ for(i=0;i<sizeof(to.a);i++){
+ to.a[i]=from&255;
+ from>>=8;
+ }
+ return to;
+}
diff --git a/datatypes/dtwidths.h b/datatypes/dtwidths.h
new file mode 100644
index 0000000..384c745
--- /dev/null
+++ b/datatypes/dtwidths.h
@@ -0,0 +1,240 @@
+"S1BU","S8BULE","dtf.c","dtt.c",1,
+"S1BU","S8BUBE","dtf.c","dtt.c",1,
+"S1BS","S8BSLE","dtf.c","dtt.c",1,
+"S1BS","S8BSBE","dtf.c","dtt.c",1,
+"S2BU","S8BULE","dtf.c","dtt.c",1,
+"S2BU","S8BUBE","dtf.c","dtt.c",1,
+"S2BS","S8BSLE","dtf.c","dtt.c",1,
+"S2BS","S8BSBE","dtf.c","dtt.c",1,
+"S3BU","S8BULE","dtf.c","dtt.c",1,
+"S3BU","S8BUBE","dtf.c","dtt.c",1,
+"S3BS","S8BSLE","dtf.c","dtt.c",1,
+"S3BS","S8BSBE","dtf.c","dtt.c",1,
+"S4BU","S8BULE","dtf.c","dtt.c",1,
+"S4BU","S8BUBE","dtf.c","dtt.c",1,
+"S4BS","S8BSLE","dtf.c","dtt.c",1,
+"S4BS","S8BSBE","dtf.c","dtt.c",1,
+"S5BU","S8BULE","dtf.c","dtt.c",1,
+"S5BU","S8BUBE","dtf.c","dtt.c",1,
+"S5BS","S8BSLE","dtf.c","dtt.c",1,
+"S5BS","S8BSBE","dtf.c","dtt.c",1,
+"S6BU","S8BULE","dtf.c","dtt.c",1,
+"S6BU","S8BUBE","dtf.c","dtt.c",1,
+"S6BS","S8BSLE","dtf.c","dtt.c",1,
+"S6BS","S8BSBE","dtf.c","dtt.c",1,
+"S7BU","S8BULE","dtf.c","dtt.c",1,
+"S7BU","S8BUBE","dtf.c","dtt.c",1,
+"S7BS","S8BSLE","dtf.c","dtt.c",1,
+"S7BS","S8BSBE","dtf.c","dtt.c",1,
+"S9BU","S16BULE","dtf.c","dtt.c",2,
+"S9BU","S16BUBE","dtf.c","dtt.c",2,
+"S9BS","S16BSLE","dtf.c","dtt.c",2,
+"S9BS","S16BSBE","dtf.c","dtt.c",2,
+"S10BU","S16BULE","dtf.c","dtt.c",2,
+"S10BU","S16BUBE","dtf.c","dtt.c",2,
+"S10BS","S16BSLE","dtf.c","dtt.c",2,
+"S10BS","S16BSBE","dtf.c","dtt.c",2,
+"S11BU","S16BULE","dtf.c","dtt.c",2,
+"S11BU","S16BUBE","dtf.c","dtt.c",2,
+"S11BS","S16BSLE","dtf.c","dtt.c",2,
+"S11BS","S16BSBE","dtf.c","dtt.c",2,
+"S12BU","S16BULE","dtf.c","dtt.c",2,
+"S12BU","S16BUBE","dtf.c","dtt.c",2,
+"S12BS","S16BSLE","dtf.c","dtt.c",2,
+"S12BS","S16BSBE","dtf.c","dtt.c",2,
+"S13BU","S16BULE","dtf.c","dtt.c",2,
+"S13BU","S16BUBE","dtf.c","dtt.c",2,
+"S13BS","S16BSLE","dtf.c","dtt.c",2,
+"S13BS","S16BSBE","dtf.c","dtt.c",2,
+"S14BU","S16BULE","dtf.c","dtt.c",2,
+"S14BU","S16BUBE","dtf.c","dtt.c",2,
+"S14BS","S16BSLE","dtf.c","dtt.c",2,
+"S14BS","S16BSBE","dtf.c","dtt.c",2,
+"S15BU","S16BULE","dtf.c","dtt.c",2,
+"S15BU","S16BUBE","dtf.c","dtt.c",2,
+"S15BS","S16BSLE","dtf.c","dtt.c",2,
+"S15BS","S16BSBE","dtf.c","dtt.c",2,
+"S17BU","S32BULE","dtf.c","dtt.c",3,
+"S17BU","S32BUBE","dtf.c","dtt.c",3,
+"S17BS","S32BSLE","dtf.c","dtt.c",3,
+"S17BS","S32BSBE","dtf.c","dtt.c",3,
+"S18BU","S32BULE","dtf.c","dtt.c",3,
+"S18BU","S32BUBE","dtf.c","dtt.c",3,
+"S18BS","S32BSLE","dtf.c","dtt.c",3,
+"S18BS","S32BSBE","dtf.c","dtt.c",3,
+"S19BU","S32BULE","dtf.c","dtt.c",3,
+"S19BU","S32BUBE","dtf.c","dtt.c",3,
+"S19BS","S32BSLE","dtf.c","dtt.c",3,
+"S19BS","S32BSBE","dtf.c","dtt.c",3,
+"S20BU","S32BULE","dtf.c","dtt.c",3,
+"S20BU","S32BUBE","dtf.c","dtt.c",3,
+"S20BS","S32BSLE","dtf.c","dtt.c",3,
+"S20BS","S32BSBE","dtf.c","dtt.c",3,
+"S21BU","S32BULE","dtf.c","dtt.c",3,
+"S21BU","S32BUBE","dtf.c","dtt.c",3,
+"S21BS","S32BSLE","dtf.c","dtt.c",3,
+"S21BS","S32BSBE","dtf.c","dtt.c",3,
+"S22BU","S32BULE","dtf.c","dtt.c",3,
+"S22BU","S32BUBE","dtf.c","dtt.c",3,
+"S22BS","S32BSLE","dtf.c","dtt.c",3,
+"S22BS","S32BSBE","dtf.c","dtt.c",3,
+"S23BU","S32BULE","dtf.c","dtt.c",3,
+"S23BU","S32BUBE","dtf.c","dtt.c",3,
+"S23BS","S32BSLE","dtf.c","dtt.c",3,
+"S23BS","S32BSBE","dtf.c","dtt.c",3,
+"S24BU","S32BULE","dtf.c","dtt.c",3,
+"S24BU","S32BUBE","dtf.c","dtt.c",3,
+"S24BS","S32BSLE","dtf.c","dtt.c",3,
+"S24BS","S32BSBE","dtf.c","dtt.c",3,
+"S25BU","S32BULE","dtf.c","dtt.c",4,
+"S25BU","S32BUBE","dtf.c","dtt.c",4,
+"S25BS","S32BSLE","dtf.c","dtt.c",4,
+"S25BS","S32BSBE","dtf.c","dtt.c",4,
+"S26BU","S32BULE","dtf.c","dtt.c",4,
+"S26BU","S32BUBE","dtf.c","dtt.c",4,
+"S26BS","S32BSLE","dtf.c","dtt.c",4,
+"S26BS","S32BSBE","dtf.c","dtt.c",4,
+"S27BU","S32BULE","dtf.c","dtt.c",4,
+"S27BU","S32BUBE","dtf.c","dtt.c",4,
+"S27BS","S32BSLE","dtf.c","dtt.c",4,
+"S27BS","S32BSBE","dtf.c","dtt.c",4,
+"S28BU","S32BULE","dtf.c","dtt.c",4,
+"S28BU","S32BUBE","dtf.c","dtt.c",4,
+"S28BS","S32BSLE","dtf.c","dtt.c",4,
+"S28BS","S32BSBE","dtf.c","dtt.c",4,
+"S29BU","S32BULE","dtf.c","dtt.c",4,
+"S29BU","S32BUBE","dtf.c","dtt.c",4,
+"S29BS","S32BSLE","dtf.c","dtt.c",4,
+"S29BS","S32BSBE","dtf.c","dtt.c",4,
+"S30BU","S32BULE","dtf.c","dtt.c",4,
+"S30BU","S32BUBE","dtf.c","dtt.c",4,
+"S30BS","S32BSLE","dtf.c","dtt.c",4,
+"S30BS","S32BSBE","dtf.c","dtt.c",4,
+"S31BU","S32BULE","dtf.c","dtt.c",4,
+"S31BU","S32BUBE","dtf.c","dtt.c",4,
+"S31BS","S32BSLE","dtf.c","dtt.c",4,
+"S31BS","S32BSBE","dtf.c","dtt.c",4,
+"S33BU","S64BULE","dtf.c","dtt.c",5,
+"S33BU","S64BUBE","dtf.c","dtt.c",5,
+"S33BS","S64BSLE","dtf.c","dtt.c",5,
+"S33BS","S64BSBE","dtf.c","dtt.c",5,
+"S34BU","S64BULE","dtf.c","dtt.c",5,
+"S34BU","S64BUBE","dtf.c","dtt.c",5,
+"S34BS","S64BSLE","dtf.c","dtt.c",5,
+"S34BS","S64BSBE","dtf.c","dtt.c",5,
+"S35BU","S64BULE","dtf.c","dtt.c",5,
+"S35BU","S64BUBE","dtf.c","dtt.c",5,
+"S35BS","S64BSLE","dtf.c","dtt.c",5,
+"S35BS","S64BSBE","dtf.c","dtt.c",5,
+"S36BU","S64BULE","dtf.c","dtt.c",5,
+"S36BU","S64BUBE","dtf.c","dtt.c",5,
+"S36BS","S64BSLE","dtf.c","dtt.c",5,
+"S36BS","S64BSBE","dtf.c","dtt.c",5,
+"S37BU","S64BULE","dtf.c","dtt.c",5,
+"S37BU","S64BUBE","dtf.c","dtt.c",5,
+"S37BS","S64BSLE","dtf.c","dtt.c",5,
+"S37BS","S64BSBE","dtf.c","dtt.c",5,
+"S38BU","S64BULE","dtf.c","dtt.c",5,
+"S38BU","S64BUBE","dtf.c","dtt.c",5,
+"S38BS","S64BSLE","dtf.c","dtt.c",5,
+"S38BS","S64BSBE","dtf.c","dtt.c",5,
+"S39BU","S64BULE","dtf.c","dtt.c",5,
+"S39BU","S64BUBE","dtf.c","dtt.c",5,
+"S39BS","S64BSLE","dtf.c","dtt.c",5,
+"S39BS","S64BSBE","dtf.c","dtt.c",5,
+"S40BU","S64BULE","dtf.c","dtt.c",5,
+"S40BU","S64BUBE","dtf.c","dtt.c",5,
+"S40BS","S64BSLE","dtf.c","dtt.c",5,
+"S40BS","S64BSBE","dtf.c","dtt.c",5,
+"S41BU","S64BULE","dtf.c","dtt.c",6,
+"S41BU","S64BUBE","dtf.c","dtt.c",6,
+"S41BS","S64BSLE","dtf.c","dtt.c",6,
+"S41BS","S64BSBE","dtf.c","dtt.c",6,
+"S42BU","S64BULE","dtf.c","dtt.c",6,
+"S42BU","S64BUBE","dtf.c","dtt.c",6,
+"S42BS","S64BSLE","dtf.c","dtt.c",6,
+"S42BS","S64BSBE","dtf.c","dtt.c",6,
+"S43BU","S64BULE","dtf.c","dtt.c",6,
+"S43BU","S64BUBE","dtf.c","dtt.c",6,
+"S43BS","S64BSLE","dtf.c","dtt.c",6,
+"S43BS","S64BSBE","dtf.c","dtt.c",6,
+"S44BU","S64BULE","dtf.c","dtt.c",6,
+"S44BU","S64BUBE","dtf.c","dtt.c",6,
+"S44BS","S64BSLE","dtf.c","dtt.c",6,
+"S44BS","S64BSBE","dtf.c","dtt.c",6,
+"S45BU","S64BULE","dtf.c","dtt.c",6,
+"S45BU","S64BUBE","dtf.c","dtt.c",6,
+"S45BS","S64BSLE","dtf.c","dtt.c",6,
+"S45BS","S64BSBE","dtf.c","dtt.c",6,
+"S46BU","S64BULE","dtf.c","dtt.c",6,
+"S46BU","S64BUBE","dtf.c","dtt.c",6,
+"S46BS","S64BSLE","dtf.c","dtt.c",6,
+"S46BS","S64BSBE","dtf.c","dtt.c",6,
+"S47BU","S64BULE","dtf.c","dtt.c",6,
+"S47BU","S64BUBE","dtf.c","dtt.c",6,
+"S47BS","S64BSLE","dtf.c","dtt.c",6,
+"S47BS","S64BSBE","dtf.c","dtt.c",6,
+"S48BU","S64BULE","dtf.c","dtt.c",6,
+"S48BU","S64BUBE","dtf.c","dtt.c",6,
+"S48BS","S64BSLE","dtf.c","dtt.c",6,
+"S48BS","S64BSBE","dtf.c","dtt.c",6,
+"S49BU","S64BULE","dtf.c","dtt.c",7,
+"S49BU","S64BUBE","dtf.c","dtt.c",7,
+"S49BS","S64BSLE","dtf.c","dtt.c",7,
+"S49BS","S64BSBE","dtf.c","dtt.c",7,
+"S50BU","S64BULE","dtf.c","dtt.c",7,
+"S50BU","S64BUBE","dtf.c","dtt.c",7,
+"S50BS","S64BSLE","dtf.c","dtt.c",7,
+"S50BS","S64BSBE","dtf.c","dtt.c",7,
+"S51BU","S64BULE","dtf.c","dtt.c",7,
+"S51BU","S64BUBE","dtf.c","dtt.c",7,
+"S51BS","S64BSLE","dtf.c","dtt.c",7,
+"S51BS","S64BSBE","dtf.c","dtt.c",7,
+"S52BU","S64BULE","dtf.c","dtt.c",7,
+"S52BU","S64BUBE","dtf.c","dtt.c",7,
+"S52BS","S64BSLE","dtf.c","dtt.c",7,
+"S52BS","S64BSBE","dtf.c","dtt.c",7,
+"S53BU","S64BULE","dtf.c","dtt.c",7,
+"S53BU","S64BUBE","dtf.c","dtt.c",7,
+"S53BS","S64BSLE","dtf.c","dtt.c",7,
+"S53BS","S64BSBE","dtf.c","dtt.c",7,
+"S54BU","S64BULE","dtf.c","dtt.c",7,
+"S54BU","S64BUBE","dtf.c","dtt.c",7,
+"S54BS","S64BSLE","dtf.c","dtt.c",7,
+"S54BS","S64BSBE","dtf.c","dtt.c",7,
+"S55BU","S64BULE","dtf.c","dtt.c",7,
+"S55BU","S64BUBE","dtf.c","dtt.c",7,
+"S55BS","S64BSLE","dtf.c","dtt.c",7,
+"S55BS","S64BSBE","dtf.c","dtt.c",7,
+"S56BU","S64BULE","dtf.c","dtt.c",7,
+"S56BU","S64BUBE","dtf.c","dtt.c",7,
+"S56BS","S64BSLE","dtf.c","dtt.c",7,
+"S56BS","S64BSBE","dtf.c","dtt.c",7,
+"S57BU","S64BULE","dtf.c","dtt.c",8,
+"S57BU","S64BUBE","dtf.c","dtt.c",8,
+"S57BS","S64BSLE","dtf.c","dtt.c",8,
+"S57BS","S64BSBE","dtf.c","dtt.c",8,
+"S58BU","S64BULE","dtf.c","dtt.c",8,
+"S58BU","S64BUBE","dtf.c","dtt.c",8,
+"S58BS","S64BSLE","dtf.c","dtt.c",8,
+"S58BS","S64BSBE","dtf.c","dtt.c",8,
+"S59BU","S64BULE","dtf.c","dtt.c",8,
+"S59BU","S64BUBE","dtf.c","dtt.c",8,
+"S59BS","S64BSLE","dtf.c","dtt.c",8,
+"S59BS","S64BSBE","dtf.c","dtt.c",8,
+"S60BU","S64BULE","dtf.c","dtt.c",8,
+"S60BU","S64BUBE","dtf.c","dtt.c",8,
+"S60BS","S64BSLE","dtf.c","dtt.c",8,
+"S60BS","S64BSBE","dtf.c","dtt.c",8,
+"S61BU","S64BULE","dtf.c","dtt.c",8,
+"S61BU","S64BUBE","dtf.c","dtt.c",8,
+"S61BS","S64BSLE","dtf.c","dtt.c",8,
+"S61BS","S64BSBE","dtf.c","dtt.c",8,
+"S62BU","S64BULE","dtf.c","dtt.c",8,
+"S62BU","S64BUBE","dtf.c","dtt.c",8,
+"S62BS","S64BSLE","dtf.c","dtt.c",8,
+"S62BS","S64BSBE","dtf.c","dtt.c",8,
+"S63BU","S64BULE","dtf.c","dtt.c",8,
+"S63BU","S64BUBE","dtf.c","dtt.c",8,
+"S63BS","S64BSLE","dtf.c","dtt.c",8,
+"S63BS","S64BSBE","dtf.c","dtt.c",8,
diff --git a/declaration.c b/declaration.c
new file mode 100644
index 0000000..942bed7
--- /dev/null
+++ b/declaration.c
@@ -0,0 +1,4781 @@
+/* $VER: vbcc (declaration.c) $Revision: 1.90 $ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "vbcc_cpp.h"
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+#define PLAIN_STORAGE_CLASS 7
+#define PARAMETER 8
+#define OLDSTYLE 16
+
+void dynamic_init(Var *v,type *t,const_list *cl,zmax of,int noconst);
+int test_assignment(type *,np);
+int return_sc,return_reg,has_return,return_inline;
+char *return_vattr;
+static int did_return_label;
+#ifdef HAVE_TARGET_ATTRIBUTES
+unsigned long return_tattr;
+#endif
+zumax return_mask;
+zmax init_dyn_sz,init_const_sz;
+int init_dyn_cnt,init_const_cnt;
+
+void init_sl(struct_list *sl);
+
+#ifdef HAVE_ECPP
+/* 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
+
+extern np gen_libcall(char *,np,type *,np,type *);
+extern int float_used;
+extern void optimize(long,Var *);
+
+extern type uct;
+
+void needs(char *s)
+{
+ Var *v;
+ if(!(v=find_ext_var(s))||!strcmp(v->identifier,s)){
+ Var *needs=add_var(s,clone_typ(&uct),EXTERN,0);
+ needs->flags|=(USEDASSOURCE|REFERENCED|NEEDS);
+ }
+}
+
+static void clear_main_ret(void)
+{
+ if(c99&&!strcmp(cur_func,"main")&&return_typ&&ISSCALAR(return_typ->flags)){
+ /* in c99, main returns 0 if it falls from back */
+ IC *new=new_IC();
+ new->code=SETRETURN;
+ new->q1.val.vmax=l2zm(0L);
+ eval_const(&new->q1.val,MAXINT);
+ insert_const(&new->q1.val,return_typ->flags&NU);
+ new->q1.flags=KONST;
+ new->typf=return_typ->flags;
+ new->q2.val.vmax=szof(return_typ);
+ new->q2.flags=new->z.flags=0;
+ new->z.reg=freturn(return_typ);
+ add_IC(new);
+ }
+}
+
+static char *get_string(void)
+/* Liest Stringkonstante und liefert Wert als String (malloced) */
+{
+ np tree;int l;char *p;
+ const_list *cl;
+ killsp();
+ if(ctok->type!=T_STRING) {error(74);return 0;}
+ tree=string_expression();
+ if(!tree||tree->flags!=STRING){
+ error(229);
+ return 0;
+ }
+ cl=tree->cl;l=0;
+ while(cl){
+ l++;
+ cl=cl->next;
+ }
+ p=mymalloc(l);
+ cl=tree->cl;l=0;
+ while(cl){
+ p[l]=CHARBACK(zm2l(zc2zm(cl->other->val.vchar)));
+ l++;
+ cl=cl->next;
+ }
+ if(tree) free_expression(tree);
+ killsp();
+ return p;
+}
+
+/* checks whether string is a valid vector type */
+/* returns the dimension */
+static int check_vect(char *s,char *base)
+{
+ int i=strlen(base),dim;
+ if(strncmp(s,base,i)) return 0;
+ dim=s[i];
+ if(dim=='2'||dim=='3'||dim=='4'||dim=='8'){
+ if(s[i+1]==0)
+ return dim-'0';
+ else
+ return 0;
+ }
+ if(s[i]=='1'&&s[i+1]=='6'&&s[i+2]==0)
+ return 16;
+ return 0;
+}
+
+int settyp(int typnew, int typold)
+/* Unterroutine fuer declaration_specifiers(). */
+{
+ if(DEBUG&2) printf("settyp: new=%d old=%d\n",typnew,typold);
+ if(typold==LONG&&typnew==FLOAT){ error(203); return DOUBLE;}
+ if(typold==LONG&&typnew==DOUBLE) return LDOUBLE;
+ if(c99&&typold==LONG&&typnew==LONG) return LLONG;
+ if(typold==INT&&(typnew==SHORT||typnew==LONG)) return typnew;
+ if(typold!=0&&typnew!=INT){error(47);return(typnew);}
+ if(typold==0&&typnew==INT) return(INT);
+ if(typold==0) return(typnew);
+ if(typold==SHORT||typold==LONG||typold==LLONG) return(typold);
+ error(48);
+ return(typnew);
+}
+
+#define dsc if(storage_class) error(49); if(typ||type_qualifiers) error(50)
+#define XSIGNED 16384
+
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+
+type *declaration_specifiers(void)
+/* Erzeugt neuen Typ und gibt Zeiger darauf zurueck, */
+/* parst z.B. unsigned int, bla etc. */
+{
+ int typ=0,type_qualifiers=0,notdone,storage_class,hard_reg,have_inline;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+#endif
+ char *imerk,sident[MAXI],sbuff[MAXI],*attr=0,*vattr=0;
+ zumax mask=ul2zum(0UL);
+ type *new=new_typ(),*t,*ts;
+ struct_declaration *ssd;
+ struct_list (*sl)[];
+ size_t slsz;
+ Var *v;
+ int dim;
+#ifdef HAVE_TARGET_ATTRIBUTES
+ unsigned long tattr=0;
+#endif
+ storage_class=hard_reg=have_inline=0;
+ do{
+ killsp();notdone=0;
+ if(ctok->type==NAME){
+ if(!strcmp("struct",ctok->name)||!strcmp("union",ctok->name)||(ecpp&&!strcmp("class",ctok->name))){
+ if(!strcmp("struct",ctok->name)) notdone=STRUCT;
+ if(!strcmp("union",ctok->name)) {
+ notdone=UNION;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ next_token();
+ killsp();
+ if(ctok->type!=LBRA){
+ cpbez(sident,1);
+ next_token();
+ killsp();
+ ssd=find_struct(sident,0);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(ssd&&ctok->type==LBRA&&find_struct(sident,nesting)&&ssd->count>0) error(13,sident);
+ if(!ssd||((ctok->type==LBRA||ctok->type==SEMIC)&&!find_struct(sident,nesting))){
+ typ=settyp(notdone,typ);
+ ssd=mymalloc(sizeof(*ssd));
+ ssd->count=0;
+ new->exact=ssd=add_sd(ssd,notdone);
+ if(!ecpp)add_struct_identifier(sident,ssd);
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }else{
+ new->exact=ssd;
+ typ=settyp(new->flags=notdone,typ);
+ }
+ }else{
+ *sident=0;
+ typ=settyp(notdone,typ);
+ ssd=mymalloc(sizeof(*ssd));
+ ssd->count=0;
+ new->exact=ssd=add_sd(ssd,notdone);
+ }
+ if(ssd->typ!=notdone) error(230,sident);
+#ifdef HAVE_ECPP
+/* 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
+ if(ctok->type==LBRA){
+ int bfoffset,bfsize,flex_array=0,cbfo=0;
+ int scount;
+ zmax off=l2zm(0L);
+ next_token();
+ killsp();
+ slsz=SLSIZE;
+ imerk=ident;
+ sl=mymalloc(slsz*sizeof(struct_list));
+ ssd->count=0;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ scount=ssd->count;
+ ts=declaration_specifiers();
+ while(ctok->type!=RBRA&&ts){
+ if(flex_array) error(231);
+ ident=sbuff;
+ t=declarator(clone_typ(ts));
+ killsp();
+ bfsize=bfoffset=-1;
+ if(ctok->type==T_COLON){
+ np tree;
+ if((ts->flags&NQ)!=INT) {
+ error(51);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ }
+ next_token();killsp();tree=assignment_expression();
+
+ if(type_expression(tree,0)){
+ int tsize;
+ if(tree->flags!=CEXPR) error(52);
+ if(!ISINT(tree->ntyp->flags)) error(52);
+ eval_const(&tree->val,tree->ntyp->flags);
+ bfsize=(int)zm2l(vmax);
+ tsize=(int)zm2l(zmmult(sizetab[t->flags&NQ],char_bit));
+ if(bfsize<0||bfsize>tsize||(bfsize==0&&*ident)){
+ error(332);bfsize=1;
+ }
+ if(bfsize+cbfo>tsize){
+ bfoffset=cbfo=0;
+ }else{
+ bfoffset=cbfo;
+ }
+ if(bfsize!=0)
+ cbfo+=bfsize;
+ else
+ cbfo=0;
+ }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(tree) free_expression(tree);
+ }else{
+ if(!ecpp&&*ident==0) error(53);
+ cbfo=0;
+ }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(type_uncomplete(t)){
+ if(!c99||notdone!=STRUCT||flex_array||(t->flags&NQ)!=ARRAY||type_uncomplete(t->next)){
+ error(14,sbuff);
+ freetyp(t);
+ break;
+ }else{
+ flex_array=1;
+ }
+ }
+ if(ISARRAY(t->flags)&&t->dsize){
+ error(352,sbuff);
+ }
+ if(ISFUNC(t->flags)){
+ if(!ecpp){
+ error(15,sbuff);
+ }
+ }
+ if(*ident!=0){
+ int i=scount;
+ while(--i>=0)
+ if(!strcmp((*sl)[i].identifier,ident))
+ error(16,ident);
+ }
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+#ifdef HAVE_ECPP
+/* 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
+ (*sl)[scount].bfoffset=bfoffset;
+ (*sl)[scount].bfsize=bfsize;
+ (*sl)[scount].styp=t;
+ if(!ecpp) (*sl)[scount].identifier=add_identifier(ident,strlen(ident));
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(pack_align>0&&pack_align<falign(t))
+ (*sl)[scount].align=pack_align;
+ else
+ (*sl)[scount].align=falign(t);
+ {
+ zmax m,al=(*sl)[scount].align;
+ zmax sz=szof(t);
+ m=off;
+ if((zmeqto(al,l2zm(0L))||zmeqto(sz,l2zm(0L)))&&!flex_array){
+ if (!ecpp){
+ error(316,ident);
+ }
+ }else{
+ off=zmmult(zmdiv(zmadd(off,zmsub(al,l2zm(1L))),al),al);
+ if(!zmeqto(m,off)) error(306,ident);
+ if(!flex_array){
+ m=zmmult(zmdiv(zmadd(off,zmsub(sz,l2zm(1L))),sz),sz);
+ if(!zmeqto(m,off)) error(307,ident);
+ off=zmadd(off,sz);
+ }
+ }
+ }
+ scount++;
+ if(scount>=slsz-1){
+ slsz+=SLSIZE;
+ sl=myrealloc(sl,slsz*sizeof(struct_list));
+ }
+ killsp();
+ if(ctok->type==COMMA) {next_token();killsp();continue;}
+ if(ctok->type!=SEMIC) error(54); else next_token();
+ killsp();
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+ if(ctok->type!=RBRA){
+ if(ts) freetyp(ts);
+ ts=declaration_specifiers();killsp();
+ }
+ }
+ if(ts) freetyp(ts);
+ ssd->count=scount;
+ if(ssd->count==0) error(55);
+#ifdef HAVE_ECPP
+/* 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
+ ident=imerk;
+ add_sl(ssd,sl);
+ free(sl);
+ if(ctok->type!=RBRA) error(56); else next_token();
+ new->flags=notdone|type_qualifiers;
+ }
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+ notdone=1;
+ }else if(!strcmp("enum",ctok->name)){
+ /* enumerations; die Namen werden leider noch ignoriert */
+ next_token();killsp();notdone=1;
+ if(ctok->type!=LBRA){cpbez(buff,1);next_token();killsp();}
+ if(ctok->type==LBRA){
+ /* mode: 0=start 1=first was not init 2=first was init 3=more init */
+ zmax val; Var *v; type *t;int mode=0;
+ val=l2zm(0L);
+ next_token();killsp();
+ while(ctok->type!=RBRA){
+ cpbez(sident,1);next_token();killsp();
+ if(*sident==0) {error(56);break;}
+ t=new_typ();
+ t->flags=CONST|INT;
+ if(find_var(sident,nesting)) error(17,sident);
+ v=add_var(sident,t,AUTO,0); /* AUTO hier klug? */
+ if(ctok->type==ASGN){
+ if(mode==2) mode=3;
+ if(mode==0) mode=2;
+#ifdef HAVE_MISRA /* MISRA Rule 9.3 checking */
+/* removed */
+#endif
+ next_token();killsp();
+ v->clist=initialization(v->vtyp,0,0,0,0,0);
+ val=zi2zm(v->clist->val.vint);killsp();
+ }else{
+ if(mode==0) mode=1;
+#ifdef HAVE_MISRA /* MISRA Rule 9.3 checking */
+/* removed */
+#endif
+ v->clist=mymalloc(CLS);
+ v->clist->val.vint=zm2zi(val);
+ v->clist->next=v->clist->other=0;
+ v->clist->tree=0;
+ v->clist->idx=l2zm(0L);
+ }
+ vmax=l2zm(1L);val=zmadd(val,vmax);
+ v->vtyp->flags=CONST|ENUM;
+ if(ctok->type!=RBRA&&ctok->type!=COMMA) {error(56);break;}
+ if(ctok->type==COMMA) next_token();
+ killsp();
+ if(ctok->type==RBRA) {next_token(); break;}
+ }
+ }
+ killsp();
+ typ=settyp(INT,typ);
+ }else if(!strcmp("__readsmem",ctok->name)||!strcmp("__writesmem",ctok->name)){
+ enum {READS,WRITES} op;
+ char *imerk,tbuf[MAXI];
+ type *tmp;
+ if(!strcmp("__readsmem",ctok->name))
+ op=READS;
+ else
+ op=WRITES;
+ next_token();killsp();
+ if(ctok->type==LPAR) next_token(); else error(151);
+ imerk=ident;ident=tbuf;
+ tmp=declarator(declaration_specifiers());
+ ident=imerk;
+ if(tmp){
+ if(vattr)
+ vattr=myrealloc(vattr,strlen(vattr)+25);
+ else{
+ vattr=mymalloc(25);
+ vattr[0]=0;
+ }
+ sprintf(vattr+strlen(vattr),";%s(%d)",op==READS?"readmem":"writemem",tmp->flags);
+ }
+ killsp();
+ if(ctok->type==RPAR) next_token(); else error(59);
+ killsp();
+ notdone=1;
+ }else if(!strcmp("void",ctok->name)){
+ next_token();
+ typ=settyp(VOID,typ);notdone=1;
+ }else if(!strcmp("char",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ next_token();
+ typ=settyp(CHAR,typ);
+ notdone=1;
+ if(default_unsigned&&!(type_qualifiers&XSIGNED))
+ type_qualifiers|=UNSIGNED;
+ }else if(!strcmp("short",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ next_token();
+ typ=settyp(SHORT,typ);notdone=1;
+ }else if(!strcmp("int",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ next_token();
+ typ=settyp(INT,typ);notdone=1;
+ }else if(!strcmp("long",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ next_token();
+ typ=settyp(LONG,typ);notdone=1;
+ }else if(!strcmp("float",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ next_token();
+ typ=settyp(FLOAT,typ);notdone=1;
+ }else if(!strcmp("double",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ next_token();
+ typ=settyp(DOUBLE,typ);notdone=1;
+ }else if(!strcmp("const",ctok->name)){
+ next_token();
+ if(type_qualifiers&CONST) error(58);
+ type_qualifiers|=CONST;notdone=1;
+ }else if(!strcmp("volatile",ctok->name)){
+ next_token();
+ if(type_qualifiers&VOLATILE) error(58);
+ type_qualifiers|=VOLATILE;notdone=1;
+ }else if(opencl&&(dim=check_vect(ctok->name,"bool"))){
+ next_token();
+ typ=settyp(VECBOOL+dim-1,typ);
+ notdone=1;
+ }else if(opencl&&(dim=check_vect(ctok->name,"char"))){
+ next_token();
+ typ=settyp(VECCHAR+dim-1,typ);
+ notdone=1;
+ }else if(opencl&&(dim=check_vect(ctok->name,"uchar"))){
+ next_token();
+ typ=settyp((VECCHAR+dim-1)|UNSIGNED,typ);
+ notdone=1;
+ }else if(opencl&&(dim=check_vect(ctok->name,"short"))){
+ next_token();
+ typ=settyp(VECSHORT+dim-1,typ);
+ notdone=1;
+ }else if(opencl&&(dim=check_vect(ctok->name,"ushort"))){
+ next_token();
+ typ=settyp((VECSHORT+dim-1)|UNSIGNED,typ);
+ notdone=1;
+ }else if(opencl&&(dim=check_vect(ctok->name,"int"))){
+ next_token();
+ typ=settyp(VECINT+dim-1,typ);
+ notdone=1;
+ }else if(opencl&&(dim=check_vect(ctok->name,"uint"))){
+ next_token();
+ typ=settyp((VECINT+dim-1)|UNSIGNED,typ);
+ notdone=1;
+ }else if(opencl&&(dim=check_vect(ctok->name,"long"))){
+ next_token();
+ typ=settyp(VECLONG+dim-1,typ);
+ notdone=1;
+ }else if(opencl&&(dim=check_vect(ctok->name,"ulong"))){
+ next_token();
+ typ=settyp((VECLONG+dim-1)|UNSIGNED,typ);
+ notdone=1;
+ }else if(opencl&&(dim=check_vect(ctok->name,"float"))){
+ next_token();
+ typ=settyp(VECFLOAT+dim-1,typ);
+ notdone=1;
+#if 0
+ }else if(c99&&!strcmp("restrict",ctok->name)){
+ next_token();
+ if(type_qualifiers&RESTRICT) error(58);
+ type_qualifiers|=RESTRICT;notdone=1;
+#endif
+ }else if(!strcmp("unsigned",ctok->name)){
+ next_token();
+ if(type_qualifiers&(XSIGNED|UNSIGNED)) error(58);
+ notdone=1;type_qualifiers|=UNSIGNED;
+ }else if(!strcmp("signed",ctok->name)){
+ next_token();
+ if(type_qualifiers&(XSIGNED|UNSIGNED)) error(58);
+ notdone=1;type_qualifiers|=XSIGNED;
+ }else if(!strcmp("auto",ctok->name)){
+ next_token();
+ dsc;storage_class=AUTO;notdone=1;
+ }else if(!strcmp("register",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ next_token();
+ dsc;storage_class=REGISTER;notdone=1;
+ }else if(!strcmp("static",ctok->name)){
+ next_token();
+ dsc;storage_class=STATIC;notdone=1;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+ }else if(!strcmp("extern",ctok->name)){
+ next_token();
+ dsc;storage_class=EXTERN;notdone=1;
+ }else if(!strcmp("typedef",ctok->name)){
+ next_token();
+ dsc;storage_class=TYPEDEF;notdone=1;
+ }else if(c99&&!strcmp("inline",ctok->name)){
+ next_token();
+ have_inline=1;notdone=1;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__reg",ctok->name)){
+ char *d;
+ next_token();killsp();
+ if(ctok->type==LPAR) next_token(); else error(151);
+ killsp();
+ if(d=get_string()){
+ for(hard_reg=1;hard_reg<=MAXR;hard_reg++){
+ if(!strcmp(d,regnames[hard_reg])) break;
+ }
+ if(hard_reg>MAXR){ hard_reg=0;error(220,d);}
+ notdone=1;
+ free(d);
+ }
+ killsp();
+ if(ctok->type==RPAR) next_token(); else error(59);
+ killsp();
+ }else if(!strcmp("__mask",ctok->name)){
+ np tree;
+ next_token();killsp();
+ if(ctok->type==LPAR) next_token(); else error(151);
+ tree=expression();
+ if(tree&&type_expression(tree,0)){
+ if(tree->flags==CEXPR&&ISINT(tree->ntyp->flags)){
+ eval_const(&tree->val,tree->ntyp->flags);
+ mask=vumax;
+ }else
+ error(18);
+ free_expression(tree);
+ }else
+ error(18);
+ killsp();
+ if(ctok->type==RPAR) next_token(); else error(59);
+ killsp();
+ notdone=1;
+ }else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__attr",ctok->name)){
+ char *d;
+ next_token();killsp();
+ if(ctok->type==LPAR) next_token(); else error(151);
+ killsp();
+ if(d=get_string()){
+ if(!attr){
+ attr=d;
+ }else{
+ attr=myrealloc(attr,strlen(attr)+strlen(d)+2);
+ strcat(attr,";");
+ strcat(attr,d);
+ free(d);
+ }
+ notdone=1;
+ }
+ killsp();
+ if(ctok->type==RPAR) next_token(); else error(59);
+ killsp();
+ }else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__vattr",ctok->name)){
+ char *d;
+ next_token();killsp();
+ if(ctok->type==LPAR) next_token(); else error(151);
+ killsp();
+ if(d=get_string()){
+ if(!vattr){
+ vattr=d;
+ }else{
+ vattr=myrealloc(vattr,strlen(vattr)+strlen(d)+2);
+ strcat(vattr,";");
+ strcat(vattr,d);
+ free(d);
+ }
+ notdone=1;
+ }
+ killsp();
+ if(ctok->type==RPAR) next_token(); else error(59);
+ killsp();
+ }else{
+#ifdef HAVE_TARGET_ATTRIBUTES
+ int i;
+ for(i=0;g_attr_name[i];i++){
+ if(!strcmp(g_attr_name[i],ctok->name)){
+ if(tattr&(1L<<i)) error(227,ctok->name);
+ tattr|=(1L<<i);
+ next_token();
+ notdone=1;break;
+ }
+ }
+#endif
+ if(!notdone&&typ==0&&!(type_qualifiers&(XSIGNED|UNSIGNED))){
+ v=find_var(ctok->name,0);
+ if(v&&v->storage_class==TYPEDEF){
+ free(new);
+ new=clone_typ(v->vtyp);
+ typ=settyp(new->flags,typ);
+ notdone=1;
+ next_token();
+ }
+#ifdef HAVE_ECPP
+/* 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
+ }
+ }
+ }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(DEBUG&2) printf("typ:%d\n",typ);
+ }while(notdone);
+ killsp();
+ return_sc=storage_class;
+ return_reg=hard_reg;
+ return_vattr=vattr;
+ return_mask=mask;
+ return_inline=have_inline;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#ifdef HAVE_TARGET_ATTRIBUTES
+ return_tattr=tattr;
+#endif
+ if(typ==0){
+ if(storage_class==0&&type_qualifiers==0&&!hard_reg){
+ free(new);
+ return 0;
+ }
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ typ=INT;
+ }
+ if(type_qualifiers&(XSIGNED|UNSIGNED))
+ if(!ISINT(typ))
+ error(58);
+ new->flags=typ|type_qualifiers;
+ new->attr=attr;
+ return new;
+}
+
+type *declarator(type *a)
+/* Erzeugt einen neuen Typ, auf Basis des Typs a. */
+/* a wird hiermit verkettet. */
+{
+ type *t;
+ killsp();*ident=0;
+ t=direct_declarator(pointer(a));
+ if(!a)
+ {if(t) freetyp(t);return 0;}
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+#ifdef HAVE_EXT_TYPES
+ conv_typ(t);
+#endif
+ return t;
+}
+type *pointer(type *a)
+/* Unterroutine fuer declarator(), behandelt Zeiger auf Typ. */
+{
+ type *t;char *attr;int notdone;
+ if(!a) return(0);
+ killsp();
+ while(ctok->type==STAR){
+ next_token();
+ t=new_typ();
+ t->flags=POINTER_TYPE(a);
+ t->next=a;
+ attr=0;
+ a=t;
+ do{
+ killsp();
+ notdone=0;
+ if(ctok->type==NAME&&!strcmp("const",ctok->name)){
+ a->flags|=CONST;
+ notdone=1;
+ next_token();
+ }else if(ctok->type==NAME&&!strcmp("volatile",ctok->name)){
+ a->flags|=VOLATILE;
+ notdone=1;
+ next_token();
+ }else if(c99&&ctok->type==NAME&&!strcmp("restrict",ctok->name)){
+ a->flags|=RESTRICT;
+ notdone=1;
+ next_token();
+ }else if(ctok->type==NAME&&!strcmp("__attr",ctok->name)){
+ char *d;
+ next_token();
+ killsp();
+ if(ctok->type==LPAR) next_token(); else error(151);
+ killsp();
+ if(d=get_string()){
+ if(!attr){
+ attr=d;
+ }else{
+ attr=myrealloc(attr,strlen(attr)+strlen(d)+2);
+ strcat(attr,";");
+ strcat(attr,d);
+ free(d);
+ }
+ notdone=1;
+ }
+ killsp();
+ if(ctok->type==RPAR) next_token(); else error(59);
+ killsp();
+ }
+ }while(notdone);
+ a->attr=attr;
+ }
+ return a;
+}
+type *direct_declarator(type *a)
+/* Unterroutine zu declarator() */
+/* behandelt [],(funkt),(dekl). */
+{
+ type *rek=0,*merk,*p,*t=0,*first,*last=0;
+ struct_declaration *fsd;
+ struct_list (*sl)[];
+ size_t slsz;char *imerk;
+ char fbuff[MAXI];
+ killsp();
+ if(ctok->type!=NAME&&ctok->type!=LPAR&&ctok->type!=LBRK)
+ return a;
+ if(ctok->type==NAME){
+ cpbez(ident,1);
+ next_token();
+ if(!a) return(0);
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }
+ else if(ctok->type==LPAR&&a){
+ /* Rekursion */
+ token mtok;
+ copy_token(&mtok,ctok);
+ next_token(); killsp();
+ if(ctok->type!=RPAR&&*ident==0&&!declaration(0)){
+ merk=a;
+ rek=declarator(a);
+ if(ctok->type!=RPAR) error(59); else next_token();
+ }else
+
+ push_token(&mtok);
+ free(mtok.name);
+ }
+ if(!a)return(0);
+ killsp();
+ while(ctok->type==LBRK||ctok->type==LPAR){
+ if(ctok->type==LBRK){
+ next_token();
+ killsp();
+ p=new_typ();
+ p->flags=ARRAY;
+ p->next=0;
+ if(ctok->type==RBRK){
+ p->size=l2zm(0L);
+ }else{
+ np tree;
+ tree=expression();
+ if(!type_expression(tree,0)){
+ /* error("incorrect constant expression");*/
+ }else{
+ if(tree->sidefx&&!c99) error(60);
+ if(tree->flags!=CEXPR||!ISINT(tree->ntyp->flags)){
+ if(!c99||!ALLOCVLA_INLINEASM)
+ error(19);
+ else{
+ type *st;IC *new;
+ st=new_typ();
+ st->flags=HAVE_INT_SIZET?(UNSIGNED|INT):(UNSIGNED|LONG);
+ p->dsize=add_tmp_var(st);
+ gen_IC(tree,0,0);
+ convert(tree,st->flags);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=st->flags;
+ new->q1=tree->o;
+ new->z.flags=VAR;
+ new->z.v=p->dsize;
+ new->z.val.vmax=l2zm(0L);
+ new->q2.val.vmax=szof(st);
+ add_IC(new);
+ }
+ }else{
+ eval_constn(tree);
+ p->size=vmax;
+ if(zmleq(p->size,l2zm(0L))) {error(61);p->size=l2zm(1L);}
+ }
+ }
+ free_expression(tree);
+ }
+ if(ctok->type!=RBRK) error(62); else next_token();
+ if(last){
+ last->next=p;
+ last=p;
+ }else{
+ first=last=p;
+ }
+ }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(ctok->type==LPAR){
+ int komma,firstparm,oldstyle=0;
+#if 0 /*#ifdef HAVE_REGPARMS*/
+ treg_handle reg_handle=empty_reg_handle;
+ type rpointer={0};
+ if(!ffreturn(a)&&(a->flags&NQ)!=VOID){
+ rpointer.flags=POINTER_TYPE(a);
+ rpointer.next=a;
+ reg_parm(®_handle,&rpointer,0,a); /*TODO: a might be incomplete */
+ }
+#endif
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ next_token();
+ killsp();
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ fsd=mymalloc(sizeof(*fsd));
+ slsz=SLSIZE;
+ sl=mymalloc(sizeof(struct_list)*slsz);
+ fsd->count=0;
+ imerk=ident;komma=0;
+ enter_block();
+ firstparm=1;
+ while(ctok->type!=RPAR&&ctok->type!=MDOTS){
+ int hard_reg;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+ if(!firstparm&&!komma) error(57);
+ komma=firstparm=0;
+ ident=fbuff;*fbuff=0;
+ t=declaration_specifiers();
+ hard_reg=return_reg;
+ t=declarator(t);
+ if(!t){
+ oldstyle=1;
+ if(*ident==0) {error(20);freetyp(t);continue;}
+ }
+ if(fsd->count){
+ if((t&&!(*sl)[fsd->count-1].styp)||
+ (!t&&(*sl)[fsd->count-1].styp))
+ error(63);
+ }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(!return_sc) return_sc=AUTO;
+ if(return_sc!=AUTO&&return_sc!=REGISTER)
+ {error(21);return_sc=AUTO;}
+ (*sl)[fsd->count].styp=t;
+ (*sl)[fsd->count].storage_class=return_sc;
+ {
+ int m=nesting;
+ nesting=0;
+ (*sl)[fsd->count].identifier=add_identifier(ident,strlen(ident));
+ nesting=m;
+ }
+ if(t){
+ if(((*sl)[fsd->count].styp->flags&NQ)==VOID&&fsd->count!=0)
+ error(22);
+ /* Arrays in Zeiger umwandeln */
+ if(ISARRAY((*sl)[fsd->count].styp->flags))
+ (*sl)[fsd->count].styp->flags=POINTER_TYPE((*sl)[fsd->count].styp->next);
+ /* Funktionen in Zeiger auf Funktionen umwandeln */
+ if(ISFUNC((*sl)[fsd->count].styp->flags)){
+ type *new;
+ new=new_typ();
+ new->next=(*sl)[fsd->count].styp;
+ new->flags=POINTER_TYPE(new->next);
+ (*sl)[fsd->count].styp=new;
+ }
+ }
+ if(hard_reg&®ok(hard_reg,t->flags,-1)<=0) error(217,regnames[hard_reg]);
+#if 0 /*#ifdef HAVE_REGPARMS*/
+ if(t) (*sl)[fsd->count].reg=reg_parm(®_handle,t,0,a); /*TODO: a might be incomplete */
+ if(hard_reg) (*sl)[fsd->count].reg=hard_reg;
+#else
+ (*sl)[fsd->count].reg=hard_reg;
+#endif
+ fsd->count++;
+ if(fsd->count>=slsz-2){ /* eins Reserve fuer VOID */
+ slsz+=SLSIZE;
+ sl=myrealloc(sl,slsz*sizeof(struct_list));
+ }
+ killsp(); /* Hier Syntaxpruefung strenger machen */
+ if(ctok->type==COMMA) {next_token();komma=1; killsp();}
+ }
+ ident=imerk;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(ctok->type!=MDOTS||!komma){
+ int ecpp_addvoid=0;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+ if(ecpp_addvoid||(!ecpp&&fsd->count>0&&(!(*sl)[fsd->count-1].styp||((*sl)[fsd->count-1].styp->flags&NQ)!=VOID))){
+ (*sl)[fsd->count].styp=new_typ();
+ (*sl)[fsd->count].styp->flags=VOID;
+ (*sl)[fsd->count].styp->next=0;
+ (*sl)[fsd->count].reg=0;
+ (*sl)[fsd->count].identifier=empty;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+ fsd->count++;
+ }
+ if(ecpp&&ctok->type==MDOTS){next_token();killsp();}
+ }else if(komma){
+ next_token();komma=0;
+ if(oldstyle) error(221);
+ }
+ p=new_typ();
+ p->flags=FUNKT;
+ {
+ int m=nesting;
+ nesting=0;
+ p->exact=add_sd(fsd,FUNKT);
+ add_sl(fsd,sl);
+ free(sl);
+ nesting=m;
+ }
+#ifdef HAVE_REGPARMS
+ {
+ treg_handle reg_handle=empty_reg_handle;
+ int i,r;
+
+ p->next=a;
+
+ if(!ffreturn(a)&&(a->flags&NQ)!=VOID){
+ type rpointer={0};
+
+ rpointer.flags=POINTER_TYPE(a);
+ rpointer.next=a;
+ reg_parm(®_handle,&rpointer,0,p);
+ }
+
+ for(i=0;i<p->exact->count;i++){
+ if((*p->exact->sl)[i].styp)
+ r=reg_parm(®_handle,(*p->exact->sl)[i].styp,0,p);
+ else
+ r=0;
+ if((*p->exact->sl)[i].reg==0) (*p->exact->sl)[i].reg=r;
+ }
+ }
+#endif
+ killsp();
+ if(komma) error(59);
+ if(ctok->type!=RPAR) error(59); else next_token();
+ killsp();
+ if(ctok->type==COMMA||ctok->type==SEMIC||ctok->type==RPAR||ctok->type==ASGN)
+ leave_block();
+ if(last){
+ last->next=p;
+ last=p;
+ }else{
+ first=last=p;
+ }
+ }
+ killsp();
+ }
+ if(last){last->next=a;last=a;a=first;}
+ if(rek!=0&&rek!=merk){
+ /* Zweite Liste anhaengen */
+ p=rek;
+ while(p->next!=merk) p=p->next;
+ if(p) p->next=a; else ierror(0);
+ return rek;
+ }
+ return a;
+}
+int declaration(int offset)
+/* Testet, ob eine Typangabe kommt. Wenn offset!=0 ist, */
+/* muss s auf '(' zeigen und es wird getestet, ob nach der */
+/* Klammer eine Typangabe kommt. */
+/* In jedem Fall zeigt s danach wieder auf dieselbe Stelle */
+/* im Source. */
+{
+ Var *v;token mtok;
+ int fl=0;
+ if(offset){
+ copy_token(&mtok,ctok);
+ next_token();
+ killsp();
+ }
+ if(ctok->type==NAME){
+ if(!strcmp("auto",ctok->name)) fl=1;
+ else if(!strcmp("char",ctok->name)) fl=1;
+ else if(!strcmp("const",ctok->name)) fl=1;
+ else if(!strcmp("double",ctok->name)) fl=1;
+ else if(!strcmp("enum",ctok->name)) fl=1;
+ else if(!strcmp("extern",ctok->name)) fl=1;
+ else if(!strcmp("float",ctok->name)) fl=1;
+ else if(!strcmp("int",ctok->name)) fl=1;
+ else if(!strcmp("long",ctok->name)) fl=1;
+ else if(!strcmp("register",ctok->name)) fl=1;
+ else if(c99&&!strcmp("restrict",ctok->name)) fl=1;
+ else if(!strcmp("short",ctok->name)) fl=1;
+ else if(!strcmp("signed",ctok->name)) fl=1;
+ else if(!strcmp("static",ctok->name)) fl=1;
+ else if(!strcmp("struct",ctok->name)) fl=1;
+ else if(!strcmp("typedef",ctok->name)) fl=1;
+ else if(!strcmp("union",ctok->name)) fl=1;
+ else if(!strcmp("unsigned",ctok->name)) fl=1;
+ else if(!strcmp("void",ctok->name)) fl=1;
+ else if(!strcmp("volatile",ctok->name)) fl=1;
+ else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__reg",ctok->name)) fl=1;
+ else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__attr",ctok->name)) fl=1;
+ else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__vattr",ctok->name)) fl=1;
+ else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__mask",ctok->name)) fl=1;
+ else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__readsmem",ctok->name)) fl=1;
+ else if(/*!(c_flags[7]&USEDFLAG)&&*/!strcmp("__writesmem",ctok->name)) fl=1;
+ else{
+ v=find_var(ctok->name,0);
+ if(v&&v->storage_class==TYPEDEF) fl=1;
+ }
+ }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(offset){
+ push_token(&mtok);
+ free(mtok.name);
+ }
+ return fl;
+}
+void init_sl(struct_list *sl){
+ if(!sl){ierror(0);return;}
+ sl->identifier=0;
+ sl->styp=0;
+ sl->align=0;
+ sl->bfoffset=-1;
+ sl->bfsize=-1;
+ sl->reg=0;
+ sl->storage_class=0;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+}
+void add_sl(struct_declaration *sd,struct_list (*sl)[])
+/* Fuegt ein struct_list-Array in eine struct_declaration ein. */
+/* Das Array muss mind. sd->count Elements haben und wird kopiert. */
+{
+ size_t sz=sizeof(struct_list)*sd->count;
+ sd->sl=mymalloc(sz);
+ memcpy(sd->sl,sl,sz);
+}
+struct_declaration *add_sd(struct_declaration *new,int typ)
+/* Fuegt eine Declaration in Liste ein. */
+{
+ new->next=0;
+ new->label=0;
+ new->typ=typ;
+ new->identifier=0;
+ new->tunit=last_tunit;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(first_sd[nesting]==0){
+ first_sd[nesting]=last_sd[nesting]=new;
+ }else{
+ last_sd[nesting]->next=new;
+ last_sd[nesting]=new;
+ }
+ return new;
+}
+void free_sd(struct_declaration *p)
+/* Gibt eine struct_declaration-List inkl. struct_lists und */
+/* allen Typen jeder struct_list frei, nicht aber identifier. */
+{
+ int i;struct_declaration *merk;
+ while(p){
+ merk=p->next;
+ if(p->sl){
+ for(i=0;i<p->count;i++){
+ if((*p->sl)[i].styp) freetyp((*p->sl)[i].styp);
+ }
+ if(p->count>0) free(p->sl);
+ }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+#endif
+ free(p);
+ p=merk;
+ }
+}
+char *add_identifier(char *identifier,int length)
+/* Kopiert identifier an sicheren Ort, der spaeter zentral */
+/* freigegeben werden kann. */
+/* Sollte noch einbauen, dass ueberprueft wird, ob schon */
+/* vorhanden und dann nicht zweimal speichern. */
+{
+ identifier_list *new;
+ if((*identifier==0&&length==0)||identifier==empty) return(empty);
+ new=mymalloc(sizeof(identifier_list));
+ new->identifier=mymalloc(length+1);
+ memcpy(new->identifier,identifier,length+1);
+ new->next=0;new->length=length;
+ if(last_ilist[nesting]){
+ last_ilist[nesting]->next=new;
+ last_ilist[nesting]=new;
+ }else{
+ last_ilist[nesting]=first_ilist[nesting]=new;
+ }
+ return(new->identifier);
+}
+void free_ilist(identifier_list *p)
+/* Gibt eine verkettete identifier_liste und saemtliche darin */
+/* gespeicherten Identifier frei. */
+{
+ identifier_list *merk;
+ while(p){
+ merk=p->next;
+ if(p->identifier) free(p->identifier);
+ free(p);
+ p=merk;
+ }
+}
+int type_uncomplete(type *p)
+/* Testet, ob Typ unvollstaendig ist. Momentan gelten nur */
+/* unvollstaendige Strukturen und Arrays von solchen als */
+/* unvollstaendig, aber keine Zeiger oder Funktionen darauf. */
+{
+ struct_declaration *sd;
+ if(!p){ierror(0);return(0);}
+ if(ISSTRUCT(p->flags)||ISUNION(p->flags))
+ if(p->exact->count<=0) return 1;
+ if(ISARRAY(p->flags)){
+ if(!p->dsize&&zmleq(p->size,l2zm(0L))) return 1;
+if(!p->next) ierror(0);
+ if(type_uncomplete(p->next)) return 1;
+ }
+ return 0;
+}
+void add_struct_identifier(char *identifier,struct_declaration *sd)
+/* Erzeugt neuen struct_identifier, fuegt ihn in Liste an und */
+/* vervollstaendigt unvollstaendige Typen dieser Struktur. */
+{
+ struct_identifier *new;
+/* type *t;*/
+ if(DEBUG&1) printf("add_si %s (nesting=%d)->%p\n",identifier,nesting,(void *)sd);
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ new=mymalloc(sizeof(struct_identifier));
+ new->identifier=add_identifier(identifier,strlen(identifier));
+ new->sd=sd;
+ new->next=0;
+ if(first_si[nesting]==0){
+ first_si[nesting]=new;last_si[nesting]=new;
+ }else{
+ last_si[nesting]->next=new;last_si[nesting]=new;
+ }
+ sd->identifier=new->identifier;
+}
+void free_si(struct_identifier *p)
+/* Gibt eine struct_identifier-Liste frei, aber nicht die */
+/* identifiers und struct_declarations. */
+{
+ struct_identifier *merk;
+ while(p){
+ merk=p->next;
+ p->sd->identifier="<prototype-only>";
+ free(p);
+ p=merk;
+ }
+}
+struct_declaration *find_struct(char *identifier,int endnesting)
+
+/* Sucht angegebene Strukturdefinition und liefert */
+/* entsprechende struct_declaration. */
+{
+ struct_identifier *si; int i,l;
+ if(misracheck) l=strlen(identifier);
+ for(i=nesting;i>=endnesting;i--){
+ si=first_si[i];
+ while(si){
+ if(!strcmp(si->identifier,identifier)){
+ if(DEBUG&1) printf("found tag <%s> at nesting %d->%p\n",identifier,i,(void *)si->sd);
+ return(si->sd);
+ }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ si=si->next;
+ }
+ }
+ if(DEBUG&1) printf("didn't find tag <%s>\n",identifier);
+ return(0);
+}
+
+/* generate code to create a variable-lenght-array */
+static void create_allocvl(Var *v)
+{
+ np tree,ds;
+ IC *new;Var *fv;
+
+ /* check if we got a frame-pointer */
+ if(FPVLA_REG&&!regsa[FPVLA_REG]){
+ if(regused[FPVLA_REG])
+ ierror(0);
+ else
+ regsa[FPVLA_REG]=regscratch[FPVLA_REG]=regused[FPVLA_REG]=1;
+ }
+
+ /* if this is the first vla in this block, save old sp */
+ if(!block_vla[nesting]){
+ /* declare function - may be done by the backend, if necessary */
+ if(!(fv=find_ext_var("__oldvlasp"))){
+ type *t;
+ static type voidt={VOID};
+ struct_declaration *sd=mymalloc(sizeof(*sd));
+ t=new_typ();
+ t->flags=FUNKT;
+
+ t->next=new_typ();
+ t->next->flags=POINTER_TYPE(&voidt);
+ t->next->next=clone_typ(&voidt);
+ sd->count=0;
+ t->exact=add_sd(sd,FUNKT);
+ fv=add_var("__oldvlasp",t,EXTERN,0);
+ fv->fi=new_fi();
+ fv->fi->flags|=(ALL_USES|ALL_MODS);
+ fv->fi->inline_asm=mystrdup(OLDSPVLA_INLINEASM);
+ }
+ block_vla[nesting]=add_tmp_var(clone_typ(fv->vtyp->next));
+ tree=gen_libcall("__oldvlasp",0,0,0,0);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->z.flags=VAR;
+ new->z.v=block_vla[nesting];
+ new->z.val.vmax=l2zm(0L);
+ new->q1=tree->o;
+ new->q2.flags=0;
+ new->typf=block_vla[nesting]->vtyp->flags;
+ new->q2.val.vmax=sizetab[new->typf];
+ add_IC(new);
+ free_expression(tree);
+ }
+
+ /* make room on the stack */
+ ds=new_node();
+ ds->flags=IDENTIFIER;
+ ds->identifier=empty;
+ ds->dsize=vlength_szof(v->vtyp);
+ ds->val.vmax=l2zm(0L);
+ ds->ntyp=clone_typ(ds->dsize->vtyp);
+ ds->o.flags=VAR;
+ ds->o.v=ds->dsize;
+ ds->o.val.vmax=l2zm(0L);
+ ds->left=ds->right=0;
+
+ if(!find_ext_var("__allocvla")){
+ /* declare function */
+ struct_declaration *sd=mymalloc(sizeof(*sd));
+ type *t=new_typ();
+ sd->count=1;
+ sd->sl=mymalloc(sizeof(struct_list));
+ (*sd->sl)[0].storage_class=AUTO;
+ (*sd->sl)[0].styp=clone_typ(ds->dsize->vtyp);
+ (*sd->sl)[0].reg=ALLOCVLA_REG;
+ t->flags=FUNKT;
+ t->exact=add_sd(sd,FUNKT);
+ t->next=new_typ();
+ t->next->flags=POINTER_TYPE(v->vtyp);
+ t->next->next=new_typ();
+ t->next->next->flags=v->vtyp->flags;
+ fv=add_var("__allocvla",t,EXTERN,0);
+ fv->fi=new_fi();
+ fv->fi->flags|=(ALL_USES|ALL_MODS);
+ fv->fi->inline_asm=mystrdup(ALLOCVLA_INLINEASM);
+ }
+
+ if(!type_expression(ds,0)) ierror(0);
+ tree=gen_libcall("__allocvla",ds,0,0,0);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->z.flags=VAR;
+ new->z.v=v;
+ new->z.val.vmax=l2zm(0L);
+ new->q1=tree->o;
+ new->q2.flags=0;
+ new->typf=POINTER_TYPE(v->vtyp);
+ new->q2.val.vmax=sizetab[new->typf];
+ add_IC(new);
+ free_expression(tree);
+ vlas=1;
+}
+
+/* reset sp to remove variable-length-arrays */
+void freevl(void)
+{
+ np tree,ds;
+ Var *fv;
+ dontdelete=1; /* never remove them, otherwise, fix_vla_jump get confused */
+ if(!find_ext_var("__resetvlasp")){
+ struct_declaration *sd=mymalloc(sizeof(*sd));
+ type *t=new_typ();
+ sd->count=1;
+ sd->sl=mymalloc(sizeof(struct_list));
+ (*sd->sl)[0].storage_class=AUTO;
+ (*sd->sl)[0].styp=clone_typ(block_vla[nesting]->vtyp);
+ (*sd->sl)[0].reg=FREEVLA_REG;
+ t->flags=FUNKT;
+ t->exact=add_sd(sd,FUNKT);
+ t->next=new_typ();
+ t->next->flags=VOID;
+ fv=add_var("__resetvlasp",t,EXTERN,0);
+ fv->fi=new_fi();
+ fv->fi->flags|=(ALL_USES|ALL_MODS);
+ fv->fi->inline_asm=mystrdup(FREEVLA_INLINEASM);
+ }
+ if(nesting==1){
+ clear_main_ret();
+ gen_label(return_label);
+ did_return_label=1;
+ }
+ ds=new_node();
+ ds->flags=IDENTIFIER;
+ ds->identifier=empty;
+ ds->dsize=block_vla[nesting];
+ ds->val.vmax=l2zm(0L);
+ ds->ntyp=clone_typ(ds->dsize->vtyp);
+ ds->left=ds->right=0;
+ ds->o.flags=VAR;
+ ds->o.v=ds->dsize;
+ ds->o.val.vmax=l2zm(0L);
+ if(!type_expression(ds,0)) ierror(0);
+ tree=gen_libcall("__resetvlasp",ds,0,0,0);
+ free_expression(tree);
+ dontdelete=0;
+}
+
+void clearvl(void)
+{
+ llist *p,*n;
+ vlaadjust_list *vl,*vn;
+ /* look for stack-adjusts that have to be removed */
+ vl=vlaadjusts[nesting];
+ while(vl){
+ int ln;
+ IC *ic=vl->branch;
+ if(ic){
+ ln=ic->typf;
+ if(ic->code!=BRA) ierror(0);
+ p=vladeflabels[nesting];
+ while(p){
+ if(p->label==ln) break;
+ p=p->next;
+ }
+ if(!p){
+ ic=ic->prev;
+ while(ic!=vl->first->prev){
+ if(!ic) ierror(0);
+ ic->code=NOP;
+ ic->q1.flags=ic->q2.flags=ic->z.flags=0;
+ ic=ic->prev;
+ }
+ }
+ }
+ vn=vl->next;
+ free(vl);
+ vl=vn;
+ }
+ freevl();
+ block_vla[nesting]=0;
+ p=vladeflabels[nesting];
+ while(p){
+ n=p->next;
+ free(p);
+ p=n;
+ }
+ p=vlajmplabels[nesting];
+ while(p){
+ n=p->next;
+ free(p);
+ p=n;
+ }
+ vladeflabels[nesting]=vlajmplabels[nesting]=0;
+ vlaadjusts[nesting]=0;
+}
+
+/* Handle a stack of stored sp variables when traversing an IC list; */
+void vla_nesting(IC *p,Var **vn,int *nest)
+{
+ if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"__oldvlasp")){
+ IC *p2=p->next;
+ while(p2&&(p2->code==ALLOCREG||p2->code==FREEREG)) p2=p2->next;
+ if(!p2||p2->code!=GETRETURN||(p2->z.flags&(VAR|DREFOBJ))!=VAR) ierror(0);
+ /*printf("found save sp to %p\n",p2->z.v);*/
+ vn[*nest]=p2->z.v;
+ (*nest)++;
+ vn[*nest]=0;
+ if(*nest>=MAXN) ierror(0);
+ return;
+ }
+ if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"__resetvlasp")){
+ /*printf("found reset\n");*/
+ if(*nest<=0) ierror(0);
+ (*nest)--;
+ return;
+ }
+}
+
+static int return_vla_nest;
+static Var *return_last_vlasp;
+
+/* Find the stack pointer that is needed when jumping to label lab */
+Var *vla_find_sp(int lab)
+{
+ IC *p;int nest=0;
+ static Var *vn[MAXN];
+ for(p=first_ic;p;p=p->next){
+ if(p->code==LABEL&&p->typf==lab){
+ return_vla_nest=nest;
+ return_last_vlasp=vn[nest];
+ if(nest<=0)
+ return 0;
+ else
+ return vn[nest-1];
+ }
+ vla_nesting(p,vn,&nest);
+ }
+ ierror(0);
+}
+
+void vla_jump_fix(void)
+{
+ IC *p;int nest=0;
+ static Var *vn[MAXN],*savedsp;
+ if(DEBUG&1) printf("searching for vla-jump-fixes\n");
+ for(p=first_ic;p;p=p->next){
+ /*pric2(stdout,p);*/
+ if(p->code>=BEQ&&p->code<=BRA){
+ /*printf("jump found\n");*/
+ p->savedsp=0;
+ if(1/*nest>0*/){
+ /*printf("is in vla context!\n");*/
+ savedsp=vla_find_sp(p->typf);
+ if(return_vla_nest>nest||(nest>0&&return_vla_nest==nest&&savedsp!=vn[nest-1])){
+ err_ic=p;
+ error(351);
+ }else if(nest==0||savedsp==vn[nest-1]){
+ /*printf("jump within the same context\n");*/
+ }else{
+ if(vn[nest]){
+ if(DEBUG&1) printf("have to set sp to %p\n",return_last_vlasp);
+ p->savedsp=return_last_vlasp;
+ }else{
+ int ndiff=nest-return_vla_nest-1;
+ IC *p2;
+ /*printf("have to search oldsp ndiff=%d\n",ndiff);*/
+ for(p2=p->prev;p2;p2=p2->prev){
+ if(p2->code==CALL&&(p2->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p2->q1.v->identifier,"__oldvlasp")){
+ if(ndiff==0){
+ /*printf("found savesp\n");*/
+ p2=p2->next;
+ while(p2&&(p2->code==ALLOCREG||p2->code==FREEREG)) p2=p2->next;
+ if(!p2||p2->code!=GETRETURN) ierror(0);
+ if((p2->z.flags&(VAR|DREFOBJ))!=VAR) ierror(0);
+ /*printf("found oldsp %p\n",p2->z.v);*/
+ p->savedsp=p2->z.v;
+ break;
+ }
+ ndiff--;
+ }
+ if(p2->code==CALL&&(p2->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p2->q1.v->identifier,"__resetvlasp")){
+ ndiff++;
+ }
+ }
+ if(!p2) ierror(0);
+ }
+ }
+ }else{
+ /*printf("not in vla context\n");*/
+ }
+ }
+ vla_nesting(p,vn,&nest);
+ }
+ for(p=first_ic;p;p=p->next){
+ if(p->code>=BEQ&&p->code<=BRA){
+ if(p->savedsp){
+ IC *merkfic,*merklic,*newcode,*m,*new,*setr=0;
+ np ds,tree;
+ if(DEBUG&1) printf("generating sp-adjust\n");
+ merkfic=first_ic;merklic=last_ic;
+ first_ic=0;last_ic=0;
+ ds=new_node();
+ ds->flags=IDENTIFIER;
+ ds->identifier=empty;
+ ds->dsize=p->savedsp;
+ ds->val.vmax=l2zm(0L);
+ ds->ntyp=clone_typ(ds->dsize->vtyp);
+ ds->left=ds->right=0;
+ ds->o.flags=VAR;
+ ds->o.v=ds->dsize;
+ ds->o.val.vmax=l2zm(0L);
+ if(!type_expression(ds,0)) ierror(0);
+ tree=gen_libcall("__resetvlasp",ds,0,0,0);
+ free_expression(tree);
+ newcode=first_ic;
+ first_ic=merkfic;last_ic=merklic;
+ if(p->code==BRA){
+ /* check if the branch was preceded by a SETRETURN */
+ IC *p2=p->prev;
+ while(p2&&(p2->code==FREEREG||p2->code==ALLOCREG))
+ p2=p2->prev;
+ if(p2->code==SETRETURN&&p2->z.reg)
+ setr=p2;
+ }else{
+ new=new_IC();
+ new->typf=++label;
+ if(p->code==BEQ) new->code=BRA;
+ else if(p->code==BNE) new->code=BEQ;
+ else if(p->code==BLT) new->code=BGE;
+ else if(p->code==BGT) new->code=BLE;
+ else if(p->code==BLE) new->code=BGT;
+ else if(p->code==BGE) new->code=BLT;
+ insert_IC(p->prev,new);
+ }
+ while(newcode){
+ m=newcode->next;
+ insert_IC(p->prev,newcode);
+ newcode=m;
+ }
+ if(p->code!=BRA){
+ p->code=BRA;
+ new=new_IC();
+ new->code=LABEL;
+ new->typf=label;
+ insert_IC(p,new);
+ }
+ if(setr){
+ /* save the return value to save it from being overwritten */
+ /* could be optimized further */
+ Var *v;
+ if(ISSCALAR(setr->typf)){
+ static type t={0};
+ t.flags=setr->typf;
+ v=add_tmp_var(clone_typ(&t));
+ }else ierror(0);
+ new=new_IC();
+ *new=*setr;
+ new->q1.flags=VAR;
+ new->q1.v=v;
+ new->q1.val.vmax=l2zm(0L);
+ setr->z=new->q1;
+ setr->code=ASSIGN;
+ insert_IC(p->prev,new);
+ }
+ }
+ }
+ }
+}
+
+
+Var *add_tmp_var(type *t)
+{
+ t->flags&=NU;
+ return add_var(empty,t,AUTO,0);
+}
+Var *add_var(char *identifier, type *t, int storage_class,const_list *clist)
+/* Fuegt eine Variable mit Typ in die var_list ein. */
+/* In der storage_class werden die Flags PARAMETER und evtl. */
+/* OLDSTYLE und REGPARM erkannt. */
+{
+ Var *new;int f;
+ struct_declaration *sd;
+ static zmax paroffset;
+ zmax al;
+ /*if(*identifier==0) return;*/ /* sollte woanders bemaekelt werden */
+ if(DEBUG&2) printf("add_var(): %s\n",identifier);
+#ifdef HAVE_TARGET_VARHOOK_PRE
+ add_var_hook_pre(identifier,t,storage_class,clist);
+#endif
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(ISFUNC(t->flags&NQ)&&(ISARRAY(t->next->flags)||ISFUNC(t->next->flags)))
+ error(25);
+ new=mymalloc(sizeof(Var));
+ if(!*identifier&&identifier!=empty) ierror(0);
+ new->clist=clist;
+ new->vtyp=t;
+ new->storage_class=storage_class&PLAIN_STORAGE_CLASS;
+ new->reg=0;
+ new->vattr=0;
+ new->next=0;
+ new->flags=0;
+ new->inr=0;
+ new->fi=0;
+ new->nesting=nesting;
+ new->filename=filename;
+ new->line=line;
+ new->dfilename=0;
+ new->dline=0;
+ new->description=0;
+ new->tunit=last_tunit;
+ new->inline_copy=0;
+ new->index=-1;
+#ifdef HAVE_TARGET_ATTRIBUTES
+ new->tattr=0;
+#endif
+ /* if((storage_class&PLAIN_STORAGE_CLASS)==STATIC||(storage_class&PLAIN_STORAGE_CLASS)==EXTERN) new->flags=USEDASSOURCE|USEDASDEST;*/
+ if(DEBUG&2) printf("storage_class=%d\n",storage_class);
+ if(storage_class&PARAMETER) new->flags|=USEDASDEST;
+ if(storage_class®PARM){
+ new->flags|=REGPARM;
+ if(!(storage_class&DBLPUSH)){
+ if((storage_class&OLDSTYLE)&&(t->flags&NQ)==FLOAT)
+ new->flags|=CONVPARAMETER;
+ storage_class&=~PARAMETER;
+ }
+ }
+ if(DEBUG&2) printf("storage_class=%d\n",storage_class);
+ if(DEBUG&2) printf("max_offset=%ld\n",zm2l(max_offset));
+ if(is_vlength(t)&&storage_class!=AUTO&&storage_class!=REGISTER)
+ error(315);
+ if((storage_class&PLAIN_STORAGE_CLASS)==REGISTER) new->priority=registerpri; else new->priority=0;
+ if(/*nesting==0&&*/new->storage_class==EXTERN){
+ int m=nesting;
+ nesting=0;
+ new->identifier=add_identifier(identifier,strlen(identifier));
+ nesting=m;
+ if(last_ext){
+ last_ext->next=new;
+ last_ext=new;
+ }else{
+ first_ext=last_ext=new;
+ vl0=first_ext;
+ }
+ if(hash_ext) add_hashentry(hash_ext,new->identifier,new);
+ }else{
+ new->identifier=add_identifier(identifier,strlen(identifier));
+ if(last_var[nesting]){
+ new->offset=zmadd(last_var[nesting]->offset,szof(last_var[nesting]->vtyp));
+ last_var[nesting]->next=new;
+ last_var[nesting]=new;
+ }else{
+ new->offset=l2zm(0L);
+ paroffset=l2zm(0L);;
+ first_var[nesting]=last_var[nesting]=new;
+ if(nesting==0) vl1=new;
+ if(nesting==1) vl2=new;
+ }
+ }
+ f=t->flags&NQ;
+ if((storage_class&PLAIN_STORAGE_CLASS)==AUTO||(storage_class&PLAIN_STORAGE_CLASS)==REGISTER){
+ if(DEBUG&2) printf("auto\n");
+ al=falign(t);
+ if((c_flags_val[0].l&2)&&nesting==1&&!(storage_class&PARAMETER)){
+ new->offset=max_offset;
+ }else{
+ if(storage_class&PARAMETER){
+ new->offset=paroffset;
+ if(align_arguments)
+ new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(al,l2zm(1L))),al),al);
+ }else{
+ new->offset=local_offset[nesting];
+ new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(al,l2zm(1L))),al),al);
+ }
+ }
+ if(storage_class&PARAMETER){
+ new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(stackalign,l2zm(1L))),stackalign),stackalign);
+ if(ISINT(f)&&f<INT&&!short_push){
+ /* Integer-Erweiterungen fuer alle Funktionsparameter */
+ paroffset=zmadd(new->offset,sizetab[INT]);
+ }else{
+ if(f==FLOAT&&(storage_class&OLDSTYLE)){
+ /* Bei alten Funktionen werden FLOAT als DOUBLE uebergeben */
+ new->offset=zmmult(zmdiv(zmadd(new->offset,zmsub(align[DOUBLE],l2zm(1L))),align[DOUBLE]),align[DOUBLE]);
+ paroffset=zmadd(new->offset,sizetab[DOUBLE]);
+ }else{
+ paroffset=zmadd(new->offset,szof(new->vtyp));
+ }
+ }
+ }else{
+ local_offset[nesting]=zmadd(new->offset,szof(new->vtyp));
+ }
+ if(!(storage_class&PARAMETER))
+ if(zmleq(max_offset,local_offset[nesting])) max_offset=local_offset[nesting];
+ if(DEBUG&2) printf("max_offset=%ld\n",zm2l(max_offset));
+ }
+ if((storage_class&PLAIN_STORAGE_CLASS)==STATIC) new->offset=l2zm((long)++label);
+ if(storage_class&PARAMETER){
+
+ if(DEBUG&2) printf("parameter\n");
+
+ if(ISINT(f)&&f<INT&&!zmleq(sizetab[INT],sizetab[f])){
+ if(BIGENDIAN){
+ new->offset=zmadd(new->offset,zmsub(sizetab[INT],sizetab[f]));
+ }else{
+ if(!LITTLEENDIAN)
+ ierror(0);
+ }
+ }
+ if((storage_class&OLDSTYLE)&&f==FLOAT){
+ /* Bei alten Funktionen werden DOUBLE nach FLOAT konvertiert */
+ if(!(storage_class®PARM)){
+#if HAVE_LIBCALLS
+ static type dt={DOUBLE},ft={FLOAT};
+ static node n,nn;
+ IC *conv=new_IC();
+ n.flags=REINTERPRET;
+ n.left=&nn;
+ n.ntyp=&dt;
+ nn.flags=IDENTIFIER;
+ nn.identifier=identifier;
+ nn.ntyp=&ft;
+ nn.o.flags=VAR|DONTREGISTERIZE;
+ nn.o.v=new;
+ nn.o.val.vmax=l2zm(0L);
+ n.o=nn.o;
+ convert(&n,FLOAT);
+
+
+ conv->code=ASSIGN;
+ conv->typf=FLOAT;
+ conv->q1=n.o;
+ conv->z.v=new;
+ conv->z.flags=VAR;
+ conv->z.val.vmax=l2zm(0L);
+ conv->q2.val.vmax=sizetab[FLOAT];
+ conv->z.v=new;
+ add_IC(conv);
+#else
+ IC *conv=new_IC();
+ conv->code=CONVERT;
+ conv->typf=FLOAT;
+ conv->typf2=DOUBLE;
+ conv->q1.flags=VAR|DONTREGISTERIZE;
+ conv->z.flags=VAR;
+ conv->q2.flags=0;
+ conv->q1.v=conv->z.v=new;
+ conv->q1.val.vmax=conv->z.val.vmax=l2zm(0);
+ add_IC(conv);
+#endif
+ }
+ new->flags|=CONVPARAMETER;
+ }
+ new->offset=zmsub(l2zm(0L),zmadd(maxalign,new->offset));
+ }
+ if((storage_class&PLAIN_STORAGE_CLASS)==EXTERN){
+ if(!strcmp("fprintf",identifier)) new->flags|=PRINTFLIKE;
+ if(!strcmp("printf",identifier)) new->flags|=PRINTFLIKE;
+ if(!strcmp("sprintf",identifier)) new->flags|=PRINTFLIKE;
+ if(!strcmp("fscanf",identifier)) new->flags|=SCANFLIKE;
+ if(!strcmp("scanf",identifier)) new->flags|=SCANFLIKE;
+ if(!strcmp("sscanf",identifier)) new->flags|=SCANFLIKE;
+ }
+ if(is_vlength(new->vtyp))
+ create_allocvl(new);
+#ifdef HAVE_TARGET_VARHOOK_POST
+ add_var_hook_post(new);
+#endif
+ return(new);
+}
+void free_var(Var *p)
+/* Gibt Variablenliste inkl. Typ, aber ohne Identifier frei. */
+{
+ Var *merk;
+ while(p){
+ if(!*p->identifier&&p->identifier!=empty) ierror(0);
+ free(p->description);
+ free(p->vattr);
+ merk=p->next;
+ if(!(p->flags&USEDASADR)&&(p->storage_class==AUTO||p->storage_class==REGISTER)){
+ if(*p->identifier&&!(p->flags&USEDASDEST)&&ISSCALAR(p->vtyp->flags)) error(64,p->identifier);
+ if(*p->identifier&&!(p->flags&USEDASSOURCE)&&ISSCALAR(p->vtyp->flags)) error(65,p->identifier);
+ }
+ if(DEBUG&2) printf("free_var %s, pri=%d\n",p->identifier,p->priority);
+ if(p->vtyp) freetyp(p->vtyp);
+ if(p->clist) free_clist(p->clist);
+ if(p->fi){
+ if(DEBUG&2) printf("free_fi of function %s\n",p->identifier);
+ free_fi(p->fi);
+ if(DEBUG&2) printf("end free_fi of function %s\n",p->identifier);
+ }
+ free(p);
+ p=merk;
+ }
+}
+Var *find_ext_var(char *identifier)
+{
+ Var *v;int l;
+ if(misracheck) l=strlen(identifier);
+ if(hash_ext) return find_name(hash_ext,identifier);
+ for(v=first_ext;v;v=v->next){
+ if(!strcmp(v->identifier,identifier)) return v;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+ }
+ return 0;
+}
+Var *find_var(char *identifier,int endnesting)
+/* Sucht Variable mit Bezeichner und liefert Zeiger zurueck */
+/* es werden nur Variablen der Bloecke endnesting-nesting */
+/* durchsucht. */
+{
+ int i,l;Var *v;
+ if(identifier==0||*identifier==0) return 0;
+ if(misracheck) l=strlen(identifier);
+ for(i=nesting;i>=endnesting;i--){
+ for(v=first_var[i];v;v=v->next){
+ if(!strcmp(v->identifier,identifier))
+ return v;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }
+ }
+ if(endnesting==0){
+ v=find_ext_var(identifier);
+ if(v&&!(v->flags&NOTINTU))
+ return v;
+ else
+ return 0;
+ }else
+ return 0;
+}
+
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+
+
+
+int check_zero_initialisation(const_list* cl, int typ)
+{
+
+ if (cl->next) return 0;
+ if (cl->tree) return 0;
+ if (cl->other) {
+ return check_zero_initialisation(cl->other,typ);
+ } else {
+ eval_const(&cl->val,typ);
+ if ( (zmeqto(vmax,l2zm(0L))) && (zumeqto(vumax,ul2zum(0UL))) && (zldeqto(vldouble,d2zld(0.0))) ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* decide whether a initialization shall be performed only be generated code
+ or if a table copy should be used first */
+int use_only_dyn_init(zmax sz,zmax dyn_sz,zmax const_sz,int dyn_cnt,int const_cnt)
+{
+ if(zmleq(sz,l2zm(clist_copy_stack)))
+ return 1;
+ if(zmeqto(dyn_sz,l2zm(0L)))
+ return 0;
+ if(!zmleq(zmdiv(sz,dyn_sz),l2zm(2L)))
+ return 0;
+ else
+ return 1;
+}
+
+void init_local_compound(Var *v)
+{
+ if(v->storage_class==AUTO||v->storage_class==REGISTER){
+ IC *new;
+ /* Initialisierung von auto-Variablen */
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=v->vtyp->flags;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(v->vtyp);
+ new->z.flags=VAR;
+ new->z.v=v;
+ new->z.val.vmax=l2zm(0L);
+ if(v->clist->tree){
+ /* einzelner Ausdruck */
+ gen_IC(v->clist->tree,0,0);
+ convert(v->clist->tree,v->vtyp->flags&NU);
+ new->q1=v->clist->tree->o;
+ add_IC(new);
+ /* v->clist=0;*/
+ }else{
+ /* Array etc. */
+ Var *nv;
+ if(!ISSCALAR(v->vtyp->flags)&&!use_only_dyn_init(szof(v->vtyp),init_dyn_sz,init_const_sz,init_dyn_cnt,init_const_cnt)){
+ nv=add_var(empty,clone_typ(v->vtyp),STATIC,v->clist);
+ nv->flags|=DEFINED;
+ nv->dfilename=filename;
+ nv->dline=line;
+ nv->vtyp->flags|=CONST;
+ /* v->clist=0;*/
+ new->q1.flags=VAR;
+ new->q1.v=nv;
+ new->q1.val.vmax=l2zm(0L);
+
+ add_IC(new);
+
+ dynamic_init(v,v->vtyp,v->clist,0,1);
+ }else{
+ dynamic_init(v,v->vtyp,v->clist,0,0);
+ }
+ }
+ }
+}
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+void var_declaration(void)
+/* Bearbeitet eine Variablendeklaration und erzeugt alle */
+/* noetigen Strukturen. */
+{
+ type *ts,*t,*old=0,*om=0;char *imerk,vident[MAXI];
+ int mdef=0,makeint=0,notdone,storage_class,msc,extern_flag,isfunc,
+ had_decl,hard_reg,mhr,diffunit=0,inline_flag;
+ Var *v;
+ char *vattr;
+ zumax mask;
+ int base_type;
+#ifdef HAVE_TARGET_ATTRIBUTES
+ unsigned long tattr;
+#endif
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ ts=declaration_specifiers();notdone=1;
+
+ storage_class=return_sc;hard_reg=return_reg;vattr=return_vattr;mask=return_mask;
+ inline_flag=return_inline;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+ if(for_decl&&storage_class!=0&&storage_class!=AUTO&&storage_class!=REGISTER){
+ error(299);
+ storage_class=AUTO;
+ }
+
+#ifdef HAVE_TARGET_ATTRIBUTES
+ tattr=return_tattr;
+#endif
+ if(storage_class==EXTERN) extern_flag=1; else extern_flag=0;
+ killsp();
+ if(ctok->type==SEMIC){
+ if(!ts) error(0);
+ if(storage_class||(!ISSTRUCT(ts->flags)&&!ISUNION(ts->flags)&&(ts->flags&NQ)!=INT))
+ error(36);
+ freetyp(ts);
+ next_token();killsp();
+ return;
+ }
+ if(nesting==0&&(storage_class==AUTO||storage_class==REGISTER))
+ {error(66);storage_class=EXTERN;}
+ if(!ts){
+ if(nesting<=1){
+ ts=new_typ();
+ ts->flags=INT;ts->next=0;
+ makeint=1;
+ if(!storage_class) storage_class=EXTERN;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ error(67);
+ }else{
+ error(365);
+ }
+ }
+ if(storage_class==0){
+ if(nesting==0)
+ storage_class=EXTERN;
+ else
+ storage_class=AUTO;
+ }
+ msc=storage_class;mhr=hard_reg;
+ while(notdone){
+ int oldnesting=nesting;
+ imerk=ident;ident=vident;*vident=0; /* merken von ident hier vermutlich */
+ storage_class=msc;hard_reg=mhr;
+ if(old) {freetyp(old);old=0;}
+ t=declarator(clone_typ(ts));
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#ifdef HAVE_EXT_TYPES
+ conv_typ(t);
+#endif
+ if(!ISFUNC(t->flags)){
+ isfunc=0;
+ if(inline_flag) error(301);
+ }else{
+ isfunc=1;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(storage_class!=STATIC&&storage_class!=TYPEDEF) storage_class=EXTERN;
+ }
+ ident=imerk; /* nicht unbedingt noetig ? */
+ if(!*vident){
+ free(ts);free(t);
+ error(36);return;
+ }
+ v=find_var(vident,oldnesting);
+ if(!v&&/*oldnesting==0&&*/storage_class==EXTERN&&cross_module&&(v=find_ext_var(vident))){
+ v->flags&=~NOTINTU;
+ diffunit=1;
+ /*FIXME: check auf doppelte Def. */
+ }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(v){
+ had_decl=1;
+ if(storage_class==TYPEDEF){
+ error(226,v->identifier);
+ }else{
+ if(nesting>0&&(v->flags&DEFINED)&&!extern_flag&&!isfunc){
+ error(27,vident);
+ }else{
+ if(t&&v->vtyp&&!compatible_types(v->vtyp,t,NU|CONST|VOLATILE)){
+ if(ISFUNC(t->flags)&&!ISFUNC(v->vtyp->flags))
+ error(361,vident);
+ else
+ error(68,vident);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ }
+ if((storage_class!=v->storage_class&&!extern_flag)||hard_reg!=v->reg)
+ error(28,v->identifier);
+ if(!isfunc&&!extern_flag) v->flags|=TENTATIVE;
+ }
+#ifdef HAVE_TARGET_ATTRIBUTES
+ {
+ int i;
+ for(i=0;g_attr_name[i];i++){
+ if((v->tattr&(1L<<i))!=(tattr&(1L<<i))) error(228,vident,g_attr_name[i]);
+ }
+ v->tattr=tattr;
+ }
+#endif
+ if(vattr){
+ if(!v->vattr||!strstr(v->vattr,vattr)){
+ error(370,v->identifier,vattr,v->vattr?v->vattr:empty);
+ add_attr(&v->vattr,vattr);
+ }
+ if(ISFUNC(v->vtyp->flags)) fi_from_attr(v);
+ }
+ if(!isfunc){
+ if(!ISARRAY(t->flags)||!zmeqto(t->size,l2zm(0L))){
+ free(v->vtyp);
+ v->vtyp=t;
+ }
+ }else{
+ om=v->vtyp;
+ if(t->exact->count>0){
+ old=v->vtyp;v->vtyp=t;
+ }
+ }
+ }
+#ifdef HAVE_TARGET_VARHOOK_POST
+ add_attr_haddecl=v;
+ add_var_hook_post(v);
+ add_attr_haddecl=0;
+#endif
+
+ }else{
+ had_decl=0;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(isfunc&&ctok->type!=COMMA&&ctok->type!=SEMIC&&ctok->type!=RPAR&&ctok->type!=ASGN&&nesting>0) nesting--;
+ if(!zumeqto(mask,ul2zum(0UL))){
+ sprintf(vident+strlen(vident),".%lu",zum2ul(mask));
+ }
+ v=add_var(vident,t,storage_class,0);
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ v->reg=hard_reg;
+ if(vattr)
+ add_attr(&v->vattr,vattr);
+ if(ISFUNC(v->vtyp->flags))
+ fi_from_attr(v);
+#ifdef HAVE_TARGET_ATTRIBUTES
+ v->tattr=tattr;
+#endif
+ if(isfunc&&ctok->type!=COMMA&&ctok->type!=SEMIC&&ctok->type!=RPAR&&ctok->type!=ASGN&&nesting>=0) nesting++;
+ if(!v) ierror(0);
+ else{
+ if(!isfunc&&!extern_flag){
+ v->flags|=TENTATIVE;
+ if(nesting>0){
+ v->flags|=DEFINED;
+ v->dfilename=filename;
+ v->dline=line;
+ }
+ }
+ }
+ om=0;
+ }
+ if(isfunc&&inline_flag){
+ v->flags|=INLINEFUNC;
+ if(extern_flag) v->flags|=INLINEEXT;
+ }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(disallow_statics&&v->storage_class==STATIC&&*v->identifier&&!is_const(v->vtyp))
+ error(302,v->identifier);
+ killsp();
+ /* Inline-Assembler-Code in Funktionsdeklarationen */
+ if(ctok->type==ASGN&&ISFUNC(v->vtyp->flags)&&(header_cnt>0||!(c_flags[7]&USEDFLAG))){
+ np tree;
+ next_token();killsp();
+ if(v->fi){free(v->fi->inline_asm);v->fi->inline_asm=0;}
+ if(!v->fi) v->fi=new_fi();
+ v->fi->inline_asm=get_string();
+ /*STRBACK(v->fi->inline_asm);*/
+ mdef=1;
+ }else{
+ /*if(v->fi){free(v->fi->inline_asm);v->fi->inline_asm=0;}*/
+ }
+ /* Initialisierung von Variablen bei Deklaration */
+ if(ctok->type==ASGN){
+
+ next_token();killsp();
+ if(!had_decl&&v->nesting==0&&v->storage_class==EXTERN&&strcmp("main",v->identifier))
+ error(168,v->identifier);
+ if(v->flags&DEFINED){
+ if(nesting==0) error(30,v->identifier);
+ }else{
+ v->flags|=DEFINED;
+ v->dfilename=filename;
+ v->dline=line;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }
+ if(v->storage_class==TYPEDEF) error(114,v->identifier);
+ if(extern_flag){
+ if(nesting==0)
+ error(118,v->identifier);
+ else
+ error(207,v->identifier);
+ if(v->storage_class!=EXTERN){ error(77);v->storage_class=EXTERN;}
+ }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ init_dyn_sz=l2zm(0L);
+ init_dyn_cnt=0;
+ init_const_sz=l2zm(0L);
+ init_const_cnt=0;
+ v->clist=initialization(v->vtyp,v->storage_class==AUTO||v->storage_class==REGISTER,0,0,0,0);
+ /* MISRA Rule 9.2 violation checking and error reporting */
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(v->clist){
+ if(ISARRAY(v->vtyp->flags)&&zmeqto(v->vtyp->size,l2zm(0L))){
+ const_list *p=v->clist;
+ while(p){v->vtyp->size=zmadd(p->idx,l2zm(1L));p=p->next;}
+ if(v->storage_class==AUTO||v->storage_class==REGISTER){
+ local_offset[nesting]=zmadd(local_offset[nesting],szof(v->vtyp));
+ if(zmleq(max_offset,local_offset[nesting])) max_offset=local_offset[nesting];
+ }
+ }
+ if(v->storage_class==AUTO||v->storage_class==REGISTER){
+
+ init_local_compound(v);
+
+ }else if(c_flags[19]&USEDFLAG){
+ /* Ohne Optimierung gleich erzeugen; das ist noch */
+ /* etwas von der genauen Implementierung der Liste */
+ /* der Variablen abhaengig. */
+ Var *merk=v->next;
+ v->next=0;
+ gen_vars(v);
+ v->next=merk;
+ v->clist=0;
+ }
+ }
+ }else{
+ if((v->flags&DEFINED)&&type_uncomplete(v->vtyp)) error(202,v->identifier);
+ if((v->vtyp->flags&CONST)&&(v->storage_class==AUTO||v->storage_class==REGISTER))
+ error(119,v->identifier);
+ }
+ if(ctok->type==COMMA) {next_token();killsp();mdef=1;} else notdone=0;
+ }
+ freetyp(ts);
+
+ if(ISFUNC(t->flags)&&v->reg)
+ t->next->reg=v->reg;
+
+ if(!mdef&&t&&(t->flags&NQ)==FUNKT&&ctok->type!=SEMIC){
+ /* Funktionsdefinition*/
+ int i,oldstyle=0;
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+#ifdef HAVE_REGPARMS
+ treg_handle reg_handle;
+#endif
+ if(DEBUG&1) printf("Funktionsdefinition! %s %p\n",v->identifier,(void *)v);
+ {
+ int i;
+ for(i=1;i<=MAXR;i++) {regs[i]=regused[i]=regsa[i];regsbuf[i]=0;}
+ }
+ cur_func=v->identifier;
+ cur_funcv=v;
+ if(only_inline==2) only_inline=0;
+ if(nesting<1) enter_block();
+ if(nesting>1) error(32);
+ if(v->flags&DEFINED){
+ if(!inline_flag||!cross_module){
+ error(33,v->identifier);
+ }else{
+ if(v->fi->first_ic){
+ free_IC(v->fi->first_ic);
+ v->fi->first_ic=0;
+ }
+ }
+ }else{
+ v->flags|=DEFINED;
+ v->dfilename=filename;
+ v->dline=line;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }
+ if(storage_class!=EXTERN&&storage_class!=STATIC) error(34);
+ if(extern_flag&&!inline_flag) error(120);
+ if(storage_class==EXTERN&&!strcmp(v->identifier,"main")&&(!t->next||t->next->flags!=INT)) error(121);
+ if(!had_decl&&v->nesting==0&&v->storage_class==EXTERN&&strcmp("main",v->identifier))
+ error(168,v->identifier);
+ while(!ecpp&&ctok->type!=LBRA){
+ /* alter Stil */
+ type *nt=declaration_specifiers();notdone=1;oldstyle=OLDSTYLE;
+ if(!ts) {error(35);}
+ while(notdone){
+ int found=0;
+ imerk=ident;ident=vident;*vident=0;
+ ts=declarator(clone_typ(nt));
+ ident=imerk;
+ if(!ts) {error(36);}
+ else{
+ for(i=0;i<t->exact->count;i++){
+ if(!strcmp((*t->exact->sl)[i].identifier,vident)){
+ found=1;
+ if((*t->exact->sl)[i].styp){
+ error(69,vident);
+ freetyp((*t->exact->sl)[i].styp);
+ }
+ /* typ[] in *typ */
+ if(ISARRAY(ts->flags)) ts->flags=POINTER_TYPE(ts);
+ /* typ() in *typ() */
+ if(ISFUNC(ts->flags)){
+ type *new=new_typ();
+ new->flags=POINTER_TYPE(ts);
+ new->next=ts;
+ ts=new;
+ }
+ if(!return_sc) return_sc=AUTO;
+ if(return_sc!=AUTO&&return_sc!=REGISTER)
+ {error(122);return_sc=AUTO;}
+ (*t->exact->sl)[i].storage_class=return_sc;
+ (*t->exact->sl)[i].reg=return_reg;
+ if(return_reg) error(219);
+ (*t->exact->sl)[i].styp=ts;
+ }
+ }
+ }
+ if(!found) {error(37,vident);}
+ killsp();
+ if(ctok->type==COMMA) {next_token();killsp();} else notdone=0;
+ }
+ if(nt) freetyp(nt);
+ if(ctok->type==SEMIC){
+ next_token();killsp();
+ }else{
+ error(54);
+ while(ctok->type!=LBRA&&ctok->type!=SEMIC){next_token();killsp();}
+ }
+ }
+ if(!ecpp&&t->exact->count==0){
+ struct_list sl[1];
+ if(DEBUG&1) printf("prototype converted to (void)\n");
+ t->exact->count=1;
+ sl[0].identifier=empty;
+ sl[0].storage_class=AUTO;
+ sl[0].styp=new_typ();
+ sl[0].styp->flags=VOID;
+ sl[0].styp->next=0;
+ sl[0].reg=0;
+ nesting--;
+ add_sl(t->exact,&sl);
+ nesting++;
+ }
+ if(om&&om->exact&&!compare_sd(om->exact,t->exact)) {
+ error(123);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ }
+ nocode=0;currentpri=1;
+ /* enter_block();*/
+ local_offset[1]=l2zm(0L);
+ return_var=0;
+ if(!v->vtyp) ierror(0);
+#ifdef HAVE_REGPARMS
+ reg_handle=empty_reg_handle;
+#endif
+ if(v->vtyp->next->flags==VOID){
+ return_typ=0;
+ }else{
+ return_typ=v->vtyp->next;
+ if(!ffreturn(return_typ)&&(return_typ->flags&NQ)!=VOID){
+ /* Parameter fuer die Rueckgabe von Werten, die nicht in einem */
+ /* Register sind. */
+ type *rt=new_typ();int reg;
+ rt->flags=POINTER_TYPE(return_typ);rt->next=return_typ;
+#ifdef HAVE_REGPARMS
+ reg=reg_parm(®_handle,rt,0,v->vtyp);
+ if(!reg){
+ return_var=add_var(empty,clone_typ(rt),AUTO|PARAMETER|oldstyle,0);
+ }else{
+ return_var=add_var(empty,clone_typ(rt),reg<0?(AUTO|PARAMETER|REGPARM|DBLPUSH|oldstyle):(AUTO|PARAMETER|REGPARM|oldstyle),0);
+ return_var->reg=reg;
+ }
+#else
+ return_var=add_var(empty,clone_typ(rt),AUTO|PARAMETER|oldstyle,0);
+#endif
+ return_var->flags|=DEFINED;
+ return_var->dfilename=filename;
+ return_var->dline=line;
+ free(rt);
+ }
+ }
+ first_ic=last_ic=0;ic_count=0;max_offset=l2zm(0L);
+ if(!zmleq(local_offset[1],Z0)) max_offset=local_offset[1];
+ for(i=0;i<t->exact->count;i++){
+ /* TODO: missing pointer for struct return */
+#ifdef HAVE_REGPARMS
+ int didrp=0;
+ if((*t->exact->sl)[i].styp){
+ int tr;
+ tr=reg_parm(®_handle,(*t->exact->sl)[i].styp,0,t);
+ didrp=1;
+ if(!(*t->exact->sl)[i].reg) (*t->exact->sl)[i].reg=tr;
+ }
+#endif
+ if(!(*t->exact->sl)[i].styp&&*(*t->exact->sl)[i].identifier){
+ type *nt;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ nt=new_typ();
+ nt->flags=INT;
+ (*t->exact->sl)[i].styp=nt;
+ (*t->exact->sl)[i].storage_class=AUTO;
+ (*t->exact->sl)[i].reg=0;
+ error(124);
+ }
+ if(*(*t->exact->sl)[i].identifier){
+ Var *tmp;int sc,tr;
+ sc=((*t->exact->sl)[i].storage_class|PARAMETER|oldstyle);
+#ifdef HAVE_REGPARMS
+ if(!didrp){
+ if(!t->exact->sl) ierror(0);
+ if(!(*t->exact->sl)[i].styp) ierror(0);
+ tr=reg_parm(®_handle,(*t->exact->sl)[i].styp,0,t);
+ if(!(*t->exact->sl)[i].reg) (*t->exact->sl)[i].reg=tr;
+ }
+#endif
+ if((*t->exact->sl)[i].reg>0) sc|=REGPARM;
+ if((*t->exact->sl)[i].reg<0) sc|=(REGPARM|DBLPUSH);
+ tmp=add_var((*t->exact->sl)[i].identifier,clone_typ((*t->exact->sl)[i].styp),sc,0);
+ tmp->reg=(*t->exact->sl)[i].reg;
+ tmp->flags|=DEFINED;
+ tmp->dfilename=filename;
+ tmp->dline=line;
+ if(oldstyle){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ freetyp((*t->exact->sl)[i].styp);
+ (*t->exact->sl)[i].styp=0; /* Prototype entfernen */
+ }
+ }
+ }
+ if(oldstyle) t->exact->count=0; /* Prototype entfernen */
+ /* local_offset[1]=l2zm(0L);*/
+ return_label=++label;
+ function_calls=0;float_used=0;has_return=0;goto_used=0;vlas=0;
+ did_return_label=0;
+ for(i=1;i<=MAXR;i++) simple_scratch[i]=0;
+ if(v->storage_class==EXTERN&&(v->flags&INLINEFUNC))
+ disallow_statics=1;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+
+ if(c99){
+ /* c99 predefined __func__ */
+ type *ft=new_typ();
+ Var *fnc;
+
+ /* create type */
+ ft->flags=ARRAY;
+ ft->size=l2zm((long)strlen(cur_func)+1);
+ ft->next=new_typ();
+ ft->next->flags=CONST|CHAR;
+
+ /* use string_expression() to create const_list */
+ fnc=add_var("__func__",ft,STATIC,cl_from_string(cur_func,cur_func+strlen(cur_func)));
+ fnc->flags|=DEFINED;
+ }
+
+ /* Generate intermediate code for function */
+ compound_statement();
+
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ cur_funcv=0;
+ disallow_statics=0;
+ if(block_vla[nesting]) clearvl();
+ if((v->vtyp->next->flags&NQ)!=VOID&&!has_return){
+ if(strcmp(v->identifier,"main")) error(173,v->identifier);
+ else error(174,v->identifier);
+ }
+#if 0
+ {int i;
+ for(i=1;i<=MAXR;i++) if(regs[i]!=regsa[i]) {printf("Register %s:\n",regnames[i]);ierror(0);}
+ }
+#endif
+ if(!did_return_label){
+ clear_main_ret();
+ gen_label(return_label);
+ }
+ /* backpatch code for jumps out of vla-scope if necessary */
+ if(vlas)
+ vla_jump_fix();
+ if(cross_module){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->statics=first_var[0];
+ }else if(first_ic&&errors==0){
+ if((c_flags[2]&USEDFLAG)&&ic1){fprintf(ic1,"function %s\n",v->identifier); pric(ic1,first_ic);}
+ vl1=first_var[0];
+ vl2=first_var[1];
+ vl3=merk_varf;
+ optimize(optflags,v);
+ if((c_flags[3]&USEDFLAG)&&ic2){fprintf(ic2,"function %s\n",v->identifier); pric(ic2,first_ic);}
+ if(out&&!only_inline&&!(c_flags[5]&USEDFLAG)){
+ memset(regs_modified,0,RSIZE);
+ gen_code(out,first_ic,v,max_offset);
+ static_stack_check(v);
+ v->flags|=GENERATED;
+#ifdef HAVE_REGS_MODIFIED
+ if(!v->fi) v->fi=new_fi();
+ if(v->fi->flags&ALL_REGS)
+ {
+ int i;
+ for(i=1;i<=MAXR;i++){
+ if(reg_pair(i,&rp)){
+ if(BTST(regs_modified,i)){
+ BSET(regs_modified,rp.r1);
+ BSET(regs_modified,rp.r2);
+ }else{
+ if(BTST(regs_modified,rp.r1)||BTST(regs_modified,rp.r2))
+ BSET(regs_modified,i);
+ }
+ }
+ }
+ memcpy(v->fi->regs_modified,regs_modified,RSIZE);
+ v->fi->flags|=ALL_REGS;
+ }
+#endif
+ }
+ /*if(DEBUG&8192){fprintf(ic2,"function %s, after gen_code\n",v->identifier); pric(ic2,first_ic);}*/
+ free_IC(first_ic);
+ first_ic=last_ic=0;
+ }
+ if(cross_module){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->first_ic=first_ic;
+ v->fi->last_ic=last_ic;
+ first_ic=last_ic=0;
+ }
+ if(v->fi&&v->fi->first_ic){
+ Var *vp;
+ if(DEBUG&1) printf("leave block %d (inline-version)\n",nesting);
+ if(block_vla[nesting]) clearvl();
+ if(nesting!=1) ierror(0);
+ if(merk_varl) merk_varl->next=first_var[nesting]; else merk_varf=first_var[nesting];
+ if(last_var[nesting]) merk_varl=last_var[nesting];
+ if(merk_sil) merk_sil->next=first_si[nesting]; else merk_sif=first_si[nesting];
+ if(last_si[nesting]) merk_sil=last_si[nesting];
+ if(merk_sdl) merk_sdl->next=first_sd[nesting]; else merk_sdf=first_sd[nesting];
+ if(last_sd[nesting]) merk_sdl=last_sd[nesting];
+ if(merk_ilistl) merk_ilistl->next=first_ilist[nesting]; else merk_ilistf=first_ilist[nesting];
+ if(last_ilist[nesting]) merk_ilistl=last_ilist[nesting];
+
+ if(merk_varf&&!only_inline&&!cross_module) gen_vars(merk_varf);
+ if(first_llist) free_llist(first_llist);
+ first_llist=0;
+ if(first_clist) free_clist(first_clist);
+ first_clist=0;
+ if(merk_sif) free_si(merk_sif);
+ /* struct-declarations erst ganz am Schluss loeschen. Um zu vermeiden, */
+ /* dass struct-declarations in Prototypen frei werden und dann eine */
+ /* spaetere struct, dieselbe Adresse bekommt und dadurch gleich wird. */
+ /* Nicht sehr schoen - wenn moeglich noch mal aendern. */
+ /* if(merk_sdf) free_sd(merk_sdf);*/
+ /* hier noch was ueberlegen */
+ /* if(merk_ilistf) free_ilist(merk_ilistf);*/
+ nesting--;
+ v->fi->vars=merk_varf;
+ /* v->fi->vars=first_var[1];*/
+ /* keine echten Parameter=>keine negativen Offsets */
+ /* vp=first_var[1];*/
+ if(!cross_module){
+ vp=merk_varf;
+ while(vp){
+ if(vp->storage_class==AUTO||vp->storage_class==REGISTER){
+ /*if(DEBUG&1024) printf("handling variable %s(%ld)/%p\n",vp->identifier,zm2l(vp->offset),(void*)vp);*/
+ if(!zmleq(l2zm(0L),vp->offset)){
+ vp->offset=l2zm(0L);
+ if(DEBUG&1024) printf("converted parameter <%s>(%ld) for inlining\n",vp->identifier,(long)zm2l(vp->offset));
+ }else vp->offset=l2zm(4L); /* Dummy, da recalc_offsets? */
+ }
+ vp=vp->next;
+ }
+ }
+ }else{
+ leave_block();
+ }
+ if(only_inline==2) only_inline=0;
+ cur_func="oops, I forgot it";
+ }else{
+ if(makeint) error(125);
+ if(ctok->type==SEMIC) next_token(); else error(54);
+ if(ISFUNC(t->flags)&&t->exact){
+ struct_declaration *sd=t->exact;int i,f;
+ for(f=0,i=0;i<sd->count;i++)
+ if(!(*sd->sl)[i].styp){error(126);f=1;}
+ if(f){
+ for(i=0;i<sd->count;i++) if((*sd->sl)[i].styp) freetyp((*sd->sl)[i].styp);
+ sd->count=0;
+ }
+ }
+ }
+ if(old) freetyp(old);
+}
+int compatible_types(type *a,type *b,int qual)
+/* Vergleicht, ob Typ beider Typen gleich ist, const/volatile */
+/* werden laut ANSI nicht beruecksichtigt. */
+{
+ struct_declaration *sd;
+ int af=a->flags&qual,bf=b->flags&qual;
+ if(af!=bf) return(0);
+ af&=NQ;bf&=NQ;
+ if(ISFUNC(af)){
+ if(a->exact->count&&!compare_sd(a->exact,b->exact)) return(0);
+ }
+ if(ISSTRUCT(af)||ISUNION(af)){
+ if(cross_module&&a->exact->tunit!=b->exact->tunit) return 1;
+ if(a->exact!=b->exact) return(0);
+ }
+ if(ISARRAY(af)){
+ if(!zmeqto(a->size,l2zm(0L))&&!zmeqto(b->size,l2zm(0L))&&!zmeqto(a->size,b->size)) return(0);
+ }
+ if(a->next==0&&b->next!=0) return(0);
+ if(a->next!=0&&b->next==0) return(0);
+ if(a->next==0&&b->next==0) return(1);
+ if(qual!=NQ) qual=(NU|CONST|VOLATILE);
+ return(compatible_types(a->next,b->next,qual));
+}
+int compare_sd(struct_declaration *a,struct_declaration *b)
+/* Vergleicht, ob zwei struct_declarations identisch sind */
+/* Wird nur nur fuer Prototypen benutzt, leere Liste immer gleich. */
+{
+ int i;
+ if(!a->count||!b->count) return(1);
+ if(a->count!=b->count) return(0);
+ for(i=0;i<a->count;i++){
+ if((*a->sl)[i].styp&&(*b->sl)[i].styp&&!compatible_types((*a->sl)[i].styp,(*b->sl)[i].styp,NU)) return(0);
+ if((*a->sl)[i].reg!=(*b->sl)[i].reg) {error(368);return 0;}
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ }
+ return(1);
+}
+void free_clist(const_list *p)
+/* Gibt clist frei. */
+{
+ const_list *merk;
+ return;
+ while(p){
+ merk=p->next;
+ if(p->other) free_clist(p->other);
+ if(p->tree) free_expression(p->tree);
+ free(p);
+ p=merk;
+ }
+}
+void gen_clist(FILE *,type *,const_list *);
+
+void gen_vars(Var *v)
+/* Generiert Variablen. */
+{
+ int mode,al,first_pass=1;Var *p;
+ if(errors!=0||(c_flags[5]&USEDFLAG)) return;
+ if(optsize)
+ al=zm2l(maxalign);
+ else
+ al=0;
+ for(;al>=0;al--){
+ for(mode=0;mode<3;mode++){
+ int i,flag;
+ for(p=v;p;p=p->next){
+ if(p->flags&NEEDS) continue;
+ if(optsize&&zm2l(falign(p->vtyp))!=al)
+ continue;
+ if(cross_module&&!(p->flags&REFERENCED)) continue;
+ if(DEBUG&2) printf("gen_var(): %s\n",p->identifier);
+ if(p->storage_class==STATIC||p->storage_class==EXTERN){
+ if(!(p->flags&GENERATED)){
+ if(p->storage_class==EXTERN&&!(p->flags&(USEDASSOURCE|USEDASDEST))&&!(p->flags&(TENTATIVE|DEFINED))) continue;
+ if(p->storage_class==STATIC&&p->nesting>0&&!(p->flags&(USEDASSOURCE|USEDASDEST))) continue;
+ /* erst konstante initialisierte Daten */
+ if(mode==0){
+ if(!p->clist) continue;
+ if(!(p->vtyp->flags&(CONST|STRINGCONST))){
+ type *t=p->vtyp;int f=0;
+ do{
+ if(t->flags&(CONST|STRINGCONST)) break;
+ if(!ISARRAY(t->flags)){f=1;break;}
+ t=t->next;
+ }while(1);
+ if(f) continue;
+ }
+ }
+ /* dann initiolisierte */
+ if(mode==1&&!p->clist) continue;
+ /* und dann der Rest */
+
+ if(mode==2&&p->clist) continue;
+
+ if(!(p->flags&(TENTATIVE|DEFINED))){
+ if(!((p->vtyp->flags&NQ)==FUNKT)||!p->fi||!p->fi->inline_asm){
+ if(mask_opt){
+ if((p->flags&PRINTFLIKE)&&!strstr(p->identifier,".")) needs("vfprintf");
+ if((p->flags&SCANFLIKE)&&!strstr(p->identifier,".")) needs("vfscanf");
+ }
+ gen_var_head(out,p);
+ }
+ if(p->storage_class==STATIC&&(!p->fi||!p->fi->inline_asm)) error(127,p->identifier);
+ continue;
+ }else{
+ /*gen_align(out,falign(p->vtyp));*/
+ }
+ if(!((p->vtyp->flags&NQ)==FUNKT)||!p->fi||!p->fi->inline_asm){
+ if(mask_opt){
+ if((p->flags&PRINTFLIKE)&&!strstr(p->identifier,".")) needs("vfprintf");
+ if((p->flags&SCANFLIKE)&&!strstr(p->identifier,".")) needs("vfscanf");
+ }
+ gen_var_head(out,p);
+ }
+ if(!p->clist){
+ if(type_uncomplete(p->vtyp)) error(202,p->identifier);
+ gen_ds(out,szof(p->vtyp),p->vtyp);
+ }else{
+ gen_clist(out,p->vtyp,p->clist);
+ }
+ p->flags|=GENERATED;
+ }else if(p->flags&INLINEEXT){
+ /* a function was declared extern inline and defined;
+ we have to create external linkage */
+ int m=p->flags;
+ /* pretend, it was only declared, but not defined and remove
+ INLINEEXT */
+ p->flags&=~(DEFINED|INLINEEXT);
+ gen_var_head(out,p);
+ p->flags|=DEFINED;
+ }
+ }
+ }
+ first_pass=0;
+ }
+ }
+ if(mask_opt){
+ for(p=v;p;p=p->next)
+ if(p->flags&NEEDS) gen_var_head(out,p);
+ }
+}
+
+/* creates code that dynamically initializes a variable */
+void dynamic_init(Var *v,type *t,const_list *cl,zmax of,int noconst)
+{
+ int f=t->flags;
+ if(ISARRAY(f)){
+ zmax i;
+ for(i=l2zm(0L);!zmleq(t->size,i);i=zmadd(i,l2zm(1L))){
+ if(cl&&zmeqto(cl->idx,i)){
+ dynamic_init(v,t->next,cl->other,of,noconst);
+ cl=cl->next;
+ }else{
+ dynamic_init(v,t->next,0,of,noconst);
+ }
+ of=zmadd(of,szof(t->next));
+ }
+ }else if(ISUNION(f)&&(!cl||!cl->tree)){
+ dynamic_init(v,(*t->exact->sl)[cl?zm2l(cl->idx):0].styp,cl?cl->other:0,of,noconst);
+ }else if(ISSTRUCT(f)&&(!cl||!cl->tree)){
+ zmax al;int fl;type *st;
+ int bfo,i;
+ for(i=0;i<t->exact->count&&cl;i++){
+ if(!cl->other){
+ if(errors==0)
+ ierror(0);
+ return;
+ }
+ st=(*t->exact->sl)[i].styp;
+ al=(*t->exact->sl)[i].align;
+ if(!(*t->exact->sl)[i].identifier) ierror(0);
+ bfo=(*t->exact->sl)[i].bfoffset;
+ if(!zmeqto(zmmod(of,al),l2zm(0L))){
+ of=zmadd(of,zmsub(al,zmmod(of,al)));
+ }
+ if(bfo>=0){
+ int bfs=(*t->exact->sl)[i].bfsize;
+ static obj dest = {0};
+
+ dest.flags=VAR;
+ dest.v=v;
+ dest.val.vmax=of;
+
+ if(bfo==0){
+ /* first clear entire bitfield */
+ IC *new=new_IC();
+ new->code=ASSIGN;
+ new->z=dest;
+ new->typf=st->flags;
+ new->q2.val.vmax=sizetab[st->flags&NQ];
+ new->q1.flags=KONST;
+ new->q1.val.vmax=l2zm(0L);
+ eval_const(&new->q1.val,MAXINT);
+ insert_const(&new->q1.val,st->flags&NU);
+ add_IC(new);
+ }
+
+ /* bitfield */
+ if(!zmeqto(cl->idx,l2zm(i))||!cl->other){
+ /* nothing to do, initialized before */
+ }else if(cl->other->tree){
+ obj dummy;
+ gen_IC(cl->other->tree,0,0);
+ convert(cl->other->tree,st->flags);
+ insert_bitfield(&dest,&cl->other->tree->o,&cl->other->tree->o,bfs,bfo,st->flags,1);
+ cl=cl->next;
+ }else{
+ static obj val = {0};
+ val.flags=KONST;
+ val.val=cl->other->val;
+ insert_bitfield(&dest,&val,&val,bfs,bfo,st->flags,1);
+ cl=cl->next;
+ }
+ if(i+1>=t->exact->count||(*t->exact->sl)[i+1].bfoffset<=0||!cl){
+ of=zmadd(of,szof(st));
+ }
+ }else{
+ if(zmeqto(l2zm((long)i),cl->idx)){
+ dynamic_init(v,st,cl->other,of,noconst);
+ cl=cl->next;
+ }else
+ dynamic_init(v,st,0,of,noconst);
+ of=zmadd(of,szof(st));
+ }
+ }
+ for(;i<t->exact->count;i++){
+ st=(*t->exact->sl)[i].styp;
+ al=(*t->exact->sl)[i].align;
+ bfo=(*t->exact->sl)[i].bfoffset;
+ if(bfo>0) continue;
+ if(!zmeqto(zmmod(of,al),l2zm(0L))){
+ of=zmadd(of,zmsub(al,zmmod(of,al)));
+ }
+ dynamic_init(v,st,0,of,noconst);
+ of=zmadd(of,szof(st));
+ }
+ }else{
+ IC *new;
+ if(noconst&&(!cl||!cl->tree))
+ return;
+ new=new_IC();
+ new->code=ASSIGN;
+ new->z.flags=VAR;
+ new->z.v=v;
+ new->z.val.vmax=of;
+ new->typf=t->flags;
+ new->q2.val.vmax=szof(t);
+ if(!cl){
+ new->q1.flags=KONST;
+ gval.vmax=l2zm(0L);
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q1.val,t->flags&NU);
+ }else if(cl->tree){
+ gen_IC(cl->tree,0,0);
+ if(ISSCALAR(t->flags))
+ convert(cl->tree,t->flags);
+ new->q1=cl->tree->o;
+ }else{
+ new->q1.flags=KONST;
+ new->q1.val=cl->val;
+ }
+ add_IC(new);
+ }
+}
+
+
+void gen_clist(FILE *f,type *t,const_list *cl)
+/* Generiert dc fuer const_list. */
+{
+ int i,bfo,bfs;zmax sz;zumax bfval=ul2zum(0UL);
+
+#if 0
+ for(i=0;i<(int)szof(t);i++){
+ zuchar c;int s;
+ s=get_clist_byte(t,cl,i,&c);
+ printf("%03d: 0x%02x (%d)\n",i,(int)c,s);
+ }
+#endif
+
+
+ if(ISARRAY(t->flags)){
+ for(sz=l2zm(0L);!zmleq(t->size,sz)&&cl;cl=cl->next){
+ if(!cl->other){ierror(0);return;}
+ if(!zmeqto(sz,cl->idx))
+ gen_ds(f,zmmult(zmsub(cl->idx,sz),szof(t->next)),t->next);
+
+ gen_clist(f,t->next,cl->other);
+ sz=zmadd(cl->idx,l2zm(1L));
+ }
+ if(!zmleq(t->size,sz)) gen_ds(f,zmmult(zmsub(t->size,sz),szof(t->next)),t->next);
+ return;
+ }
+ if(ISUNION(t->flags)){
+ int i=zm2l(cl->idx);
+ if(cl&&cl->tree){
+ /* union initialized by another union */
+ gen_ds(f,szof(t),t);
+ }else{
+ gen_clist(f,(*t->exact->sl)[i].styp,cl->other);
+ sz=zmsub(szof(t),szof((*t->exact->sl)[i].styp));
+ if(!zmeqto(sz,l2zm(0L))) gen_ds(f,sz,0);
+ }
+ return;
+ }
+ if(ISSTRUCT(t->flags)){
+ zmax al;int fl;type *st;
+ sz=l2zm(0L);
+ if(cl&&cl->tree){
+ /* initialized by another */
+ gen_ds(f,szof(t),t);
+ sz=zmadd(sz,szof(t));
+ }else{
+ for(i=0;i<t->exact->count&&cl;i++){
+ if(!cl->other){ierror(0);return;}
+ st=(*t->exact->sl)[i].styp;
+ al=(*t->exact->sl)[i].align;
+ if(!(*t->exact->sl)[i].identifier) ierror(0);
+ bfo=(*t->exact->sl)[i].bfoffset;
+ if(!zmeqto(zmmod(sz,al),l2zm(0L))){
+ gen_ds(f,zmsub(al,zmmod(sz,al)),0);
+ sz=zmadd(sz,zmsub(al,zmmod(sz,al)));
+ }
+ if(bfo>=0){
+ /* bitfield */
+ if((*t->exact->sl)[i].identifier[0]){
+ bfs=(*t->exact->sl)[i].bfsize;
+ if(zmeqto(l2zm((long)i),cl->idx)){
+ eval_const(&cl->other->val,st->flags);
+ cl=cl->next;
+ }else{
+ vumax=ul2zum(0UL);
+ }
+ vumax=zumand(vumax,zumsub(zumlshift(ul2zum(1UL),ul2zum((unsigned long)bfs)),ul2zum(1UL)));
+ bfval=zumor(bfval,zumlshift(vumax,ul2zum((unsigned long)bflayout(bfo,bfs,st->flags))));
+ }
+ if(i+1>=t->exact->count||(*t->exact->sl)[i+1].bfoffset<=0||!cl){
+ /* last bitfield in integer */
+ const_list bfcl;
+ gval.vumax=bfval;
+ eval_const(&gval,UNSIGNED|MAXINT);
+ insert_const(&bfcl.val,st->flags&NU);
+ bfcl.tree=0;
+ gen_dc(f,st->flags&NU,&bfcl);
+ bfval=ul2zum(0L);
+ sz=zmadd(sz,szof(st));
+ }
+ }else{
+ if(zmeqto(l2zm((long)i),cl->idx)){
+ gen_clist(f,st,cl->other);
+ cl=cl->next;
+ }else
+ gen_ds(f,szof(st),st);
+ sz=zmadd(sz,szof(st));
+ }
+ }
+ for(;i<t->exact->count;i++){
+ st=(*t->exact->sl)[i].styp;
+ al=(*t->exact->sl)[i].align;
+ bfo=(*t->exact->sl)[i].bfoffset;
+ if(bfo>0) continue;
+ if(!zmeqto(zmmod(sz,al),l2zm(0L))){
+ gen_ds(f,zmsub(al,zmmod(sz,al)),0);
+ sz=zmadd(sz,zmsub(al,zmmod(sz,al)));
+ }
+ gen_ds(f,szof((*t->exact->sl)[i].styp),(*t->exact->sl)[i].styp);
+ sz=zmadd(sz,szof(st));
+ }
+ }
+ al=falign(t);
+ if(!zmeqto(zmmod(sz,al),l2zm(0L)))
+ gen_ds(f,zmsub(al,zmmod(sz,al)),0);
+ return;
+ }
+
+ if(cl->tree) cl->tree->o.am=0;
+
+ if(zmeqto(cl->idx,l2zm(-1L)))
+ gen_ds(f,szof(t),t);
+ else
+ gen_dc(f,t->flags&NU,cl);
+}
+
+/* finds the correct place in a const list to insert new initializer */
+const_list *insert_cl(const_list *old,zmax idx)
+{
+ const_list *p,*cl=0;
+ if(old&&zmleq(old->idx,idx)){
+ p=old;
+ do{
+ if(zmeqto(p->idx,idx)){
+ /* found existing entry */
+ cl=p;
+ break;
+ }
+ if(!p->next||!zmleq(p->next->idx,idx))
+ break;
+ p=p->next;
+ }while(p);
+ }else
+ p=0;
+ /* we need a new entry */
+ if(!cl){
+ cl=mymalloc(CLS);
+ cl->tree=0;
+ cl->other=0;
+ cl->idx=idx;
+ if(p){
+ cl->next=p->next;
+ p->next=cl;
+ }else
+ cl->next=old;
+ }
+ return cl;
+}
+
+const_list *designator(type *t,const_list *cl)
+{
+ int f=t->flags&NQ;
+ np tree;
+ if(!c99) return 0;
+ if(ISARRAY(f)&&ctok->type==LBRK){
+ next_token();
+ killsp();
+ tree=expression();
+ if(ctok->type!=RBRK)
+ error(62);
+ else
+ {next_token();killsp();}
+ if(!type_expression(tree,0)){
+ /* error("incorrect constant expression");*/
+ }else{
+ if(tree->sidefx) error(60);
+ if(tree->flags!=CEXPR||!ISINT(tree->ntyp->flags)){
+ error(19);
+ }else{
+ /* check index for valid range */
+ eval_constn(tree);
+ if(!zmleq(l2zm(0L),vmax)) {error(354);vmax=l2zm(0L);}
+ if(!zmeqto(t->size,l2zm(0L))&&zmleq(t->size,vmax)) {error(354);vmax=l2zm(0L);}
+
+ cl=insert_cl(cl,vmax);
+
+ return cl;
+ }
+ }
+ }else if((ISSTRUCT(f)||ISUNION(f))&&ctok->type==DOT){
+ next_token();
+ killsp();
+ if(ctok->type!=NAME){
+ error(53);
+ }else{
+ int i,n=-1;
+ for(i=0;i<t->exact->count;i++)
+ if(!strcmp((*t->exact->sl)[i].identifier,ctok->name)) n=i;
+ if(n<0){
+ error(23,ctok->name);
+ return 0;
+ }
+ next_token();
+ killsp();
+
+ if(!ISUNION(f)||!cl)
+ cl=insert_cl(cl,l2zm((long)n));
+
+ return cl;
+ }
+ }
+ return 0;
+}
+
+/* declare a builtin function with up to two scalar arguments */
+Var *declare_builtin(char *name,int ztyp,int q1typ,int q1reg,int q2typ,int q2reg,int nosidefx,char *asm)
+{
+ struct_declaration *sd;
+ type *t;
+ Var *v;
+ int args;
+ if(!(v=find_ext_var(name))){
+ sd=mymalloc(sizeof(*sd));
+ if(q1typ==0) args=1;
+ else if(q2typ!=0) args=3;
+ else args=2;
+ sd->sl=mymalloc(args*sizeof(struct_list));
+ memset(sd->sl,0,args*sizeof(struct_list));
+ sd->count=args;
+ if(q1typ){
+ (*sd->sl)[0].styp=new_typ();
+ (*sd->sl)[0].styp->flags=q1typ;
+ (*sd->sl)[0].reg=q1reg;
+ }
+ if(q2typ){
+ (*sd->sl)[1].styp=new_typ();
+ (*sd->sl)[1].styp->flags=q2typ;
+ (*sd->sl)[1].reg=q2reg;
+ }
+ (*sd->sl)[args-1].styp=new_typ();
+ (*sd->sl)[args-1].styp->flags=VOID;
+ (*sd->sl)[args-1].reg=0;
+ t=new_typ();
+ t->flags=FUNKT;
+ t->exact=add_sd(sd,FUNKT);
+ t->next=new_typ();
+ t->next->flags=ztyp;
+ v=add_var(name,t,EXTERN,0);
+ v->flags|=BUILTIN;
+ if(asm||nosidefx){
+ v->fi=new_fi();
+ if(asm) v->fi->inline_asm=asm;
+ if(nosidefx){
+ v->fi->call_cnt=v->fi->use_cnt=v->fi->change_cnt=0;
+ v->fi->flags=ALL_CALLS|ALL_USES|ALL_MODS|ALWAYS_RETURNS|NOSIDEFX;
+ }
+ }
+ }
+ return v;
+}
+
+
+const_list *initialization(type *t,int noconst,int level,int desi,struct_declaration *fstruct,const_list *first)
+/* Traegt eine Initialisierung in eine const_list ein. */
+{
+ const_list *cl,**prev;
+ np tree,tree2;
+ int bracket,desi_follows=0;
+ zmax i;
+ token mtok;
+
+ int f=t->flags&NQ;
+ if(ISFUNC(f)){error(42);return(0);}
+ if(ctok->type==LBRA){next_token();killsp();bracket=1;} else bracket=0;
+ if(ISARRAY(f)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(t->dsize){
+ error(358);
+ }else if(zmeqto(t->size,l2zm(0L))&&level!=0){
+ error(359);
+ }else if(ctok->type==T_STRING&&t->next&&(t->next->flags&NQ)==CHAR){
+ killsp();
+ tree=string_expression();
+ first=tree->cl;
+ free_expression(tree);
+ }else{
+ const_list *last=first;
+ if(level==0&&!bracket) error(157);
+ for(i=l2zm(0L);desi_follows||((zmeqto(t->size,l2zm(0L))||!zmleq(t->size,i)||ctok->type==LBRK)&&ctok->type!=RBRA);i=zmadd(i,l2zm(1L))){
+ if(!zmleq(i,0)){
+ if(ctok->type==COMMA){next_token();killsp();} else break;
+ if(ctok->type==RBRA) break;
+ }
+ /* check for first designated initializer */
+ cl=designator(t,first);
+ if(!cl){
+ /* no designator */
+ cl=insert_cl(last,i);
+ cl->other=initialization(t->next,c99?noconst:0,level+1,0,fstruct,cl->other);
+ if(cl->other&&zmeqto(cl->other->idx,l2zm(-2L))){
+ first=cl->other;
+ first->other=0;
+ break;
+ }
+ }else{
+ /* designator: store current object and handle remaining designators */
+ i=cl->idx;
+ if(ctok->type!=ASGN){
+ if(ctok->type!=LBRK&&ctok->type!=DOT)
+ error(355);
+ }else{
+ cl->other=0;
+ next_token();killsp();
+ }
+ cl->other=initialization(t->next,c99?noconst:0,level+1,1,fstruct,cl->other);
+ }
+ if(cl->next==first) first=cl;
+ last=cl;
+ killsp();
+ if(desi&&!bracket)
+ break;
+ desi_follows=0;
+ if(ctok->type==COMMA){
+ copy_token(&mtok,ctok);
+ next_token();killsp();
+ if(ctok->type==LBRK)
+ desi_follows=1;
+ push_token(&mtok);
+ }
+ }
+
+ if(bracket&&zmeqto(i,l2zm(0L))) error(360);
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }
+ }else if(ISSTRUCT(f)&&(bracket||!noconst||c99)){
+ if(t->exact->count<=0)
+ {error(43);return(0);}
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+ prev=0;
+ if(level==0&&!bracket&&!c99) error(157);
+ for(i=l2zm(0L);desi_follows||(!zmleq(t->exact->count,i)&&ctok->type!=RBRA);i=zmadd(i,l2zm(1L))){
+ if(!desi_follows&&(*t->exact->sl)[zm2l(i)].identifier[0]==0) continue; /* unnamed bitfield */
+ if(!zmleq(i,0)){
+ if(ctok->type==COMMA){next_token();killsp();} else break;
+ if(ctok->type==RBRA) break;
+ }
+ cl=designator(t,first);
+
+ if(!cl){
+ cl=insert_cl(first,l2zm((long)i));
+ cl->other=initialization((*t->exact->sl)[zm2l(i)].styp,c99?noconst:0,level+1,0,!fstruct&&!bracket&&zmeqto(i,l2zm(0L))?t->exact:fstruct,cl->other);
+ if(cl->other&&zmeqto(cl->other->idx,l2zm(-2L))){
+ if(fstruct){
+ first=cl->other;
+ first->other=0;
+ }else{
+ *cl=*cl->other;
+ cl->idx=l2zm(-1L);
+ cl->other=0;
+ first=cl;
+ }
+ break;
+ }
+ }else{
+ i=zm2l(cl->idx);
+ if(ctok->type!=ASGN){
+ if(ctok->type!=LBRK&&ctok->type!=DOT)
+ error(355);
+ }else{
+ next_token();killsp();
+ cl->other=0;
+ }
+ cl->other=initialization((*t->exact->sl)[zm2l(i)].styp,c99?noconst:0,level+1,1,fstruct,cl->other);
+ }
+ if(cl->next==first) first=cl;
+ if(desi&&!bracket)
+ break;
+ desi_follows=0;
+ if(ctok->type==COMMA){
+ copy_token(&mtok,ctok);
+ next_token();killsp();
+ if(ctok->type==DOT)
+ desi_follows=1;
+ push_token(&mtok);
+ }
+ }
+
+ if(bracket&&zmeqto(i,l2zm(0L))) error(360);
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+ }else if(ISUNION(f)&&(c99||bracket||!noconst)){
+ if(t->exact->count<=0)
+ {error(44);return(0);}
+
+ if(level==0&&!bracket&&!c99) error(157);
+ desi_follows=1;
+ while(desi_follows){
+ cl=designator(t,first);
+
+ if(!cl){
+ cl=insert_cl(first,l2zm((long)0));
+ cl->other=initialization((*t->exact->sl)[0].styp,c99?noconst:0,level+1,0,!fstruct&&!bracket?t->exact:fstruct,cl->other);
+ if(cl->other&&zmeqto(cl->other->idx,l2zm(-2L))){
+ if(fstruct){
+ first=cl->other;
+ first->other=0;
+ }else{
+ *cl=*cl->other;
+ cl->other=0;
+ cl->idx=l2zm(-1L);
+ first=cl;
+ }
+ break;
+ }
+ }else{
+ i=zm2l(cl->idx);
+ if(ctok->type!=ASGN){
+ if(ctok->type!=LBRK&&ctok->type!=DOT)
+ error(355);
+ }else{
+ next_token();killsp();
+ cl->other=0;
+ }
+ cl->other=initialization((*t->exact->sl)[zm2l(i)].styp,c99?noconst:0,level+1,1,fstruct,cl->other);
+ }
+ first=cl;
+ if(desi&&!bracket)
+ break;
+ desi_follows=0;
+ if(ctok->type==COMMA){
+ copy_token(&mtok,ctok);
+ next_token();killsp();
+ if(ctok->type==DOT)
+ desi_follows=1;
+ else
+ push_token(&mtok);
+ }
+ }
+ }else{
+ int oldconst=const_expr;
+ tree2=tree=assignment_expression();
+
+ if(!tree){error(45);return(0);}
+ if(!noconst) const_expr=1;
+ if(!type_expression(tree,t)){free_expression(tree); const_expr=oldconst;return 0;}
+ const_expr=oldconst;
+
+ tree=makepointer(tree);
+
+ /* check for complete assignment in dynamic initialization */
+ if(noconst&&(ISSTRUCT(tree->ntyp->flags)||ISUNION(tree->ntyp->flags))&&fstruct==tree->ntyp->exact){
+ first=mymalloc(CLS);
+ first->tree=tree;
+ first->next=first->other=0;
+ first->idx=l2zm(-2L);
+ return first;
+ }
+
+ if(!test_assignment(t,tree)){free_expression(tree); return 0;}
+ if(!noconst){
+ /* nur Konstanten erlaubt (bei Arrays/Strukturen etc. oder static) */
+ if(tree->flags!=CEXPR){
+ /*while(tree->flags==CAST) tree=tree->left;*/
+ if(!tree->sidefx/*tree->flags==ADDRESS||tree->flags==ADDRESSS||tree->flags==ADDRESSA*/){
+ const_expr=1;
+ gen_IC(tree,0,0);
+ const_expr=oldconst;
+ if(!(tree->o.flags&VARADR)){
+ /* hier fehlen noch viele Pruefungen */
+ free_expression(tree);error(46);
+ return(0);
+ }
+ tree->o.v->flags|=USEDASADR;
+ first=mymalloc(CLS);
+ first->next=first->other=0;
+ first->tree=tree;
+ first->idx=l2zm(0L);
+ killsp();
+ }else{
+ free_expression(tree);error(46);
+ return(0);
+ }
+ }else{
+ first=mymalloc(CLS);
+ first->idx=l2zm(0L);
+ first->next=first->other=0;
+ first->tree=0;
+ eval_constn(tree);
+ tree->ntyp->flags=t->flags;
+ insert_constn(tree);
+ first->val=tree->val;
+ free_expression(tree2);
+ killsp();
+ }
+ }else{
+ /* auch anderes erlaubt */
+ first=mymalloc(CLS);
+ first->next=first->other=0;
+ first->tree=tree;
+ killsp();
+ if(!tree->sidefx){
+ if(tree->flags==CEXPR){
+ eval_constn(tree);
+ tree->ntyp->flags=t->flags;
+ insert_constn(tree);
+ first->val=tree->val;
+ first->tree=0;
+ first->idx=l2zm(0L);
+ init_const_sz=zmadd(init_const_sz,szof(tree->ntyp));
+ init_const_cnt++;
+ free_expression(tree2);
+ }else{
+ first->idx=l2zm(-1L);
+ init_dyn_sz=zmadd(init_dyn_sz,szof(tree->ntyp));
+ init_dyn_cnt++;
+ }
+ }else{
+ first->idx=l2zm(-1L);
+ init_dyn_sz=zmadd(init_dyn_sz,szof(tree->ntyp));
+ init_dyn_cnt++;
+ }
+ }
+ }
+ if(bracket){
+ if(ctok->type==COMMA){next_token();killsp();}
+ if(ctok->type==RBRA){next_token();killsp();} else error(128);
+ }
+ return(first);
+}
+#ifdef HAVE_ECPP
+/* 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 */
+/* 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 */
+/* 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 */
+/* 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 */
+/* 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/doc/errors.texi b/doc/errors.texi
new file mode 100644
index 0000000..798b39b
--- /dev/null
+++ b/doc/errors.texi
@@ -0,0 +1,1399 @@
+ @item "declaration expected" (Fatal, Error, ANSI-violation)
+
+ Something is pretty wrong with the source.
+
+
+ @item "only one input file allowed" (Fatal)
+
+ vbcc accepts only a single filename to compile. You can use a
+ frontend to compile multiple files or perhaps you mistyped an
+ option.
+
+
+ @item "Flag <%s> specified more than once" ()
+
+ You specified a command line option that should be specified only
+ once more than once. Maybe you have this option in your config-file
+ and used it in the command line, too?
+ The first occurrence will override the latter ones.
+
+
+ @item "Flag <%s> needs string" (Fatal)
+
+ This option hast to be specified with a string parameter, e.g.
+ -flag=foobar
+
+
+ @item "Flag <%s> needs value" (Fatal)
+
+ This option hast to be specified with an integer parameter, e.g.
+ -flag=1234
+
+
+ @item "Unknown Flag <%s>" (Fatal)
+
+ This option is not recognized by vbcc. Perhaps you mistyped it, used
+ the wrong case or specified an option of the frontend to vbcc?
+
+
+ @item "No input file" (Fatal)
+
+ You did not specify an input file. Your source file should not start
+ with a '-' and if you use a frontend make sure it has the proper
+ suffix.
+
+
+ @item "Could not open <%s> for input" (Fatal)
+
+ A file could not be opened.
+
+
+ @item "need a struct or union to get a member" (Error, ANSI-violation)
+
+ The source contains something like a.b where a is not a structure
+ or union.
+
+
+ @item "too many (%d) nested blocks" (Fatal, Error)
+
+ vbcc only allows a maximum number of nested blocks
+ (compund-statements). You can increase this number by changing
+ the line #define MAXN <something> in vbc.h and recompiling vbcc.
+
+
+ @item "left block 0" (Error, ANSI-violation)
+
+ This error should not occur.
+
+
+ @item "incomplete struct <%s>" (Error, ANSI-violation)
+
+ You tried to get a member of an incomplete structure/union.
+ You defined struct x y; somewhere without defining struct x@{...@}.
+
+
+ @item "out of memory" (Fatal, Error)
+
+ Guess what.
+
+
+ @item "redeclaration of struct <%s>" (Error, ANSI-violation)
+
+ You may not redeclare a struct/union in the same block.
+
+
+ @item "incomplete type (%s) in struct" (Error, ANSI-violation)
+
+ Every member in a struct/union declaration must be complete.
+ Perhaps you only wanted a pointer to that type and forgot the '*'?
+
+
+ @item "function (%s) in struct/union" (Error, ANSI-violation)
+
+ Functions cannot be members of structs/unions.
+
+
+ @item "redeclaration of struct/union member <%s>" (Error, ANSI-violation)
+
+ Two members of a struct/union have the same name.
+
+
+ @item "redeclaration of <%s>" (Error, ANSI-violation)
+
+ You used a name already in use in an enumeration.
+
+
+ @item "invalid constant expression" (Error, ANSI-violation)
+
+ ??? Nowhere to find...
+
+
+ @item "array dimension must be constant integer" (Error, ANSI-violation)
+
+ The dimensions of an array must be constants (real constants,
+ const int x=100; int y[x]; is not allowed) and integers
+ (int y[100.0]; is not allowed either).
+
+
+ @item "no declarator and no identifier in prototype" (Error, ANSI-violation)
+
+
+
+ @item "invalid storage-class in prototype" (Error, ANSI-violation)
+
+ Function parameters may only be auto or register.
+
+
+ @item "void not the only function argument" (Error, ANSI-violation)
+
+ You tried to declare a function that has an argument of type void
+ as well as other arguments.
+
+
+ @item "<%s> no member of struct/union" (Error, ANSI-violation)
+
+ The struct/union does not contain a member called like that.
+
+
+ @item "increment/decrement is only allowed for aithmetic and pointer types" (Error, ANSI-violation)
+
+
+
+ @item "functions may not return arrays or functions" (Error, ANSI-violation)
+
+
+
+ @item "only pointers to functions can be called" (Error, ANSI-violation)
+
+ You tried to call something that did not decay into a pointer to
+ a function.
+
+
+ @item "redefinition of var <%s>" (Error, ANSI-violation)
+
+
+
+ @item "redeclaration of var <%s> with new storage-class" (Error, ANSI-violation)
+
+
+
+ @item "first operand of conditional-expression must be arithmetic or pointer type" (Error, ANSI-violation)
+
+
+
+ @item "multiple definitions of var <%s>" (Error, ANSI-violation)
+
+ There have been multiple definitions of a global variable with
+ initialization.
+
+
+ @item "operands of : do not match" (Error, ANSI-violation)
+
+ In an expression of the form a ? b : c
+ - a and b must have the same type or
+ - a and b both must have arithmetic types or
+ - one of them must be a pointer and the other must be void * or 0
+
+
+ @item "function definition in inner block" (Error, ANSI-violation)
+
+ C does not allow nested functions.
+
+
+ @item "redefinition of function <%s>" (Error, ANSI-violation)
+
+ Defining two functions with the same name in one translation-unit
+ is no good idea.
+
+
+ @item "invalid storage-class for function" (Error, ANSI-violation)
+
+ Functions must not have storage-classes register or auto.
+
+
+ @item "declaration-specifiers expected" (Error, ANSI-violation)
+
+
+
+ @item "declarator expected" (Error, ANSI-violation)
+
+
+
+ @item "<%s> is no parameter" (Error, ANSI-violation)
+
+ In an old-style function definition you tried to declare a name as
+ parameter which was not in the identifier-list.
+
+
+ @item "assignment of different structs/unions" (Error, ANSI-violation)
+
+
+
+ @item "invalid types for assignment" (Error, ANSI-violation)
+
+ In an assignment-context (this includes passing arguments to
+ prototyped functions) the source and target must be one of the
+ following types:
+
+ - both are arithmetic types
+ - both are the same struct/union
+ - one of them is a pointer to void and the other one is any pointer
+ - the target is any pointer and the source is an integral
+ constant-expression with the value 0
+ - both are pointer to the same type (here the target may have
+ additional const/volatile qualifiers - not recursively, however)
+
+ Any other combinations should be illegal.
+
+
+ @item "only 0 can be compared against pointer" (Warning, ANSI-violation)
+
+ You may not compare a pointer against any other constant but a
+ 0 (null pointer).
+
+
+ @item "pointers do not point to the same type" (Warning, ANSI-violation)
+
+ You tried to compare or assign pointers that point to different
+ types. E.g. the types they point to may have different attributes.
+
+
+ @item "function initialized" (Error, Fatal, ANSI-violation)
+
+ There was a '=' after a function declaration.
+
+
+ @item "initialization of incomplete struct" (Error, Fatal, ANSI-violation)
+
+ A structure is incomplete if the only its name, but not the
+ content is known. You cannot do much with such structures.
+
+
+ @item "initialization of incomplete union" (Error, Fatal, ANSI-violation)
+
+ A union is incomplete if the only its name, but not the
+ content is known. You cannot do much with such unions.
+
+
+ @item "empty initialization" (Error, ANSI-violation)
+
+ There was no valid expression after the '=' in a variable definition.
+
+
+ @item "initializer not a constant" (Error, ANSI-violation)
+
+ Static variables and compound types may only be initialized with
+ constants.
+ Variables with const qualifier are no valid constant-expressions
+ here.
+
+ Addresses of static variables are ok, but casting them may turn
+ them into non-constant-expressions.
+
+
+ @item "double type-specifier" (Warning, ANSI-violation)
+
+
+
+ @item "illegal type-specifier" (Warning, ANSI-violation)
+
+
+
+ @item "multiple storage-classes" (Warning, ANSI-violation)
+
+
+
+ @item "storage-class specifier should be first" (Warning, ANSI-violation)
+
+
+
+ @item "bitfields must be ints" (Warning, ANSI-violation)
+
+
+
+ @item "bitfield width must be constant integer" (Warning, ANSI-violation)
+
+
+
+ @item "struct/union member needs identifier" (Warning, ANSI-violation)
+
+
+
+ @item "; expected" (Warning, ANSI-violation)
+
+ Probably you forgot a ';' or there is a syntactic error in an
+ expression.
+
+
+ @item "struct/union has no members" (Warning, ANSI-violation)
+
+ You defined an empty struct or union.
+
+
+ @item "@} expected" (Warning, ANSI-violation)
+
+
+
+ @item ", expected" (Warning, ANSI-violation)
+
+
+
+ @item "invalid unsigned" (Warning, ANSI-violation)
+
+
+
+ @item ") expected" (Warning, ANSI-violation)
+
+
+
+ @item "array dimension has sidefx (will be ignored)" (Warning, ANSI-violation)
+
+
+
+ @item "array of size 0 (set to 1)" (Warning, ANSI-violation)
+
+ ANSI C does not allow arrays or any objects to have a size of 0.
+
+
+ @item "] expected" (Warning, ANSI-violation)
+
+
+
+ @item "mixed identifier- and parameter-type-list" (Warning, ANSI-violation)
+
+
+
+ @item "var <%s> was never assigned a value" (Warning)
+
+
+
+ @item "var <%s> was never used" (Warning)
+
+
+
+ @item "invalid storage-class" (Warning, ANSI-violation)
+
+
+
+ @item "type defaults to int" (Warning)
+
+
+
+ @item "redeclaration of var <%s> with new type" (Warning, ANSI-violation)
+
+
+
+ @item "redeclaration of parameter <%s>" (Warning, ANSI-violation)
+
+
+
+ @item ": expected" (Warning, ANSI-violation)
+
+
+
+ @item "illegal escape-sequence in string" (Warning, ANSI-violation)
+
+
+
+ @item "character constant contains multiple chars" (Warning)
+
+
+
+ @item "could not evaluate sizeof-expression" (Error, ANSI-violation)
+
+
+
+ @item "" expected (unterminated string)" (Error, ANSI-violation)
+
+
+
+ @item "something wrong with numeric constant" (Error, ANSI-violation)
+
+
+
+ @item "identifier expected" (Fatal, Error, ANSI-violation)
+
+
+
+ @item "definition does not match previous declaration" (Warning, ANSI-violation)
+
+
+
+ @item "integer added to illegal pointer" (Warning, ANSI-violation)
+
+
+
+ @item "offset equals size of object" (Warning)
+
+
+
+ @item "offset out of object" (Warning, ANSI-violation)
+
+
+
+ @item "only 0 should be cast to pointer" (Warning)
+
+
+
+ @item "unknown identifier <%s>" (Error, ANSI-violation)
+
+
+
+ @item "too few function arguments" (Warning, ANSI-violation)
+
+
+
+ @item "division by zero (result set to 0)" (Warning, ANSI-violation)
+
+
+
+ @item "assignment of different pointers" (Warning, ANSI-violation)
+
+
+
+ @item "lvalue required for assignment" (Error, ANSI-violation)
+
+
+
+ @item "assignment to constant type" (Error, ANSI-violation)
+
+
+
+ @item "assignment to incomplete type" (Error, ANSI-violation)
+
+
+
+ @item "operands for || and && have to be arithmetic or pointer" (Error, ANSI-violation)
+
+
+
+ @item "bitwise operations need integer operands" (Error, ANSI-violation)
+
+
+
+ @item "assignment discards const" (Warning, ANSI-violation)
+
+ You assigned something like (const type *) to (type *).
+
+
+ @item "relational expression needs arithmetic or pointer type" (Error, ANSI-violation)
+
+
+
+ @item "both operands of comparison must be pointers" (Error, ANSI-violation)
+
+ You wrote an expression like a == b where one operand was a pointer
+ while the other was not. Perhaps a function is not declared correctly
+ or you used NULL instead of 0?
+
+
+ @item "operand needs arithmetic type" (Error, ANSI-violation)
+
+
+
+ @item "pointer arithmetic with void * is not possible" (Error, ANSI-violation)
+
+ Adding/subtracting from a pointer to void is not possible.
+
+
+ @item "pointers can only be subtracted" (Error, ANSI-violation)
+
+ You cannot add, multiply etc. two pointers.
+
+
+ @item "invalid types for operation <%s>" (Error, ANSI-violation)
+
+
+
+ @item "invalid operand type" (Error, ANSI-violation)
+
+
+
+ @item "integer-pointer is not allowed" (Error, ANSI-violation)
+
+ You may not subtract a pointer from an integer.
+ Adding an integer or subtracting it from a pointer is ok.
+
+
+@item "assignment discards volatile" (Warning, ANSI-violation)
+
+ You assigned something like (volatile type *) to (type *).
+
+
+@item "<<, >> and % need integer operands" (Error, ANSI-violation)
+
+
+
+@item "casting from void is not allowed" (Error, ANSI-violation)
+
+ Casting something of type void to anything makes no sense.
+
+
+@item "integer too large to fit into pointer" (Error, ANSI-violation)
+
+ You tried to assign an integer to a pointer that is too small to
+ hold the integer.
+ Note that assignment of pointers<->integers is never portable.
+
+
+@item "only integers can be cast to pointers" (Error, ANSI-violation)
+
+
+
+@item "invalid cast" (Error, ANSI-violation)
+
+
+
+@item "pointer too large to fit into integer" (Error, ANSI-violation)
+
+ You tried to assign a pointer to an integer that is too small to
+ hold the pointer.
+ Note that assignment of pointers<->integers is never portable.
+
+
+@item "unary operator needs arithmetic type" (Error, ANSI-violation)
+
+
+
+@item "negation type must be arithmetic or pointer" (Error, ANSI-violation)
+
+
+
+@item "complement operator needs integer type" (Error, ANSI-violation)
+
+
+
+@item "pointer assignment with different qualifiers" (Warning, ANSI-violation)
+
+ You tried to assign a pointer to a pointer that points to a type
+ with different qualifiers (e.g. signed<->unsigned).
+
+
+@item "dereferenced object is no pointer" (Error, ANSI-violation)
+
+
+
+@item "dereferenced object is incomplete" (Error, ANSI-violation)
+
+ You tried to dereference a pointer to an incomplete object.
+ Either you had a pointer to an array of unknown size or a pointer
+ to a struct or union that was not (yet) defined.
+
+
+@item "only 0 should be assigned to pointer" (Warning, ANSI-violation)
+
+ You may not assign constants other than a null pointer to any
+ pointer.
+
+
+@item "typedef <%s> is initialized" (Warning, ANSI-violation)
+
+
+
+@item "lvalue required to take address" (Error, ANSI-violation)
+
+ You can only get the address of an object, but not of expressions
+ etc.
+
+
+@item "unknown var <%s>" (Error, ANSI-violation)
+
+
+
+@item "address of register variables not available" (Error, ANSI-violation)
+
+ If a variable is declared as 'register' its address may not be
+ taken (no matter if the variable actually gets assigned to a
+ register).
+
+
+@item "var <%s> initialized after 'extern'" (Warning)
+
+
+
+@item "const var <%s> not initialized" (Warning)
+
+ A constant variable was not initialized in its definition.
+ As there is no other legal way to assign a value to a constant
+ variable this is probable an error.
+
+
+@item "function definition after 'extern'" (Warning, ANSI-violation)
+
+
+
+@item "return type of main is not int" (Warning, ANSI-violation)
+
+ main() should be defined as
+
+ int main(int argc, char **argv)
+
+ Especially the return type of main must be 'int' - 'void' is
+ not allowed by ANSI C.
+
+
+@item "invalid storage-class for function parameter" (Warning, ANSI-violation)
+
+ Function parameters may only have 'auto' or 'register' as
+ storage-class. 'static' or 'extern' are not allowed.
+
+
+@item "formal parameters conflict with parameter-type-list" (Warning, ANSI-violation)
+
+
+
+@item "parameter type defaults to int" (Warning)
+
+ A function definition contains no explicit type specifier.
+ 'int' will be assumed.
+
+
+@item "no declaration-specifier, used int" (Warning, ANSI-violation)
+
+ A variable was declared/defined without a type specified.
+ This is not allowed in ANSI C (apart from functions).
+
+
+@item "no declarator in prototype" (Warning, ANSI-violation)
+
+
+
+@item "static var <%s> never defined" (Warning)
+
+
+
+@item "@} expected" (Warning)
+
+
+
+@item "left operand of comma operator has no side-effects" (Warning)
+
+ In an expression of the form a,b a has no side-effects and is
+ therefore superfluous.
+
+
+@item "label empty" (Error, ANSI-violation)
+
+ There was a ':' without an identifier before it.
+
+
+@item "redefinition of label <%s>" (Error, ANSI-violation)
+
+ The label was defined more than once in the same function.
+ Consider that labels can not be hidden in inner blocks.
+
+
+@item "case without switch" (Error, ANSI-violation)
+
+ A case label was found outside of any switch-statements.
+
+
+@item "case-expression must be constant" (Error, ANSI-violation)
+
+ The expression after 'case' must be constant.
+
+
+@item "case-expression must be integer" (Error, ANSI-violation)
+
+ The expression after 'case' must be integer.
+
+
+@item "empty if-expression" (Error, ANSI-violation)
+
+ There was no valid expression after 'if'.
+
+
+@item "if-expression must be arithmetic or pointer" (Error, ANSI-violation)
+
+ The expression after 'if' must be arithmetic (i.e. an integer
+ or floating point type) or a pointer.
+
+
+@item "empty switch-expression" (Error, ANSI-violation)
+
+ There was no valid expression after 'switch'.
+
+
+@item "switch-expression must be integer" (Error, ANSI-violation)
+
+ The expression after 'switch' must be an integer.
+
+
+@item "multiple default labels" (Error, ANSI-violation)
+
+ There was more than one default label in a switch-statement.
+
+
+@item "while-expression must be arithmetic or pointer" (Error, ANSI-violation)
+
+ The expression after the 'while' must be arithmetic (i.e. an integer
+ or floating point type) or a pointer.
+
+
+@item "empty while-expression" (Error, ANSI-violation)
+
+ There was no valid expression after 'while'.
+
+
+@item "for-expression must be arithmetic or pointer" (Error, ANSI-violation)
+
+ The expression inside the 'for' must be arithmetic (i.e. an integer
+ or floating point type) or a pointer.
+
+
+@item "do-while--expression must be arithmetic or pointer" (Error, ANSI-violation)
+
+ The expression after the 'while' must be arithmetic (i.e. an integer
+ or floating point type) or a pointer.
+
+
+@item "goto without label" (Error, ANSI-violation)
+
+ 'goto' must be followed by a label.
+
+
+@item "continue not within loop" (Error, ANSI-violation)
+
+ 'continue' is only allowed inside of loops.
+ Perhaps there are unbalanced '@{' '@}'.
+
+
+@item "break not in matching construct" (Error, ANSI-violation)
+
+ 'break' is only allowed inside of loops or switch-statements.
+ Perhaps there are unbalanced '@{' '@}'.
+
+
+@item "label <%s> was never defined" (Error, ANSI-violation)
+
+ There is a goto to a label that was never defined.
+
+
+@item "label <%s> was never used" (Warning)
+
+ You defined a label, but there is no goto that jumps to it.
+
+
+@item "register %s not ok" (Warning)
+
+ There was an internal error (i.e. a bug in the compiler)!
+ Please report the error to vb@@compilers.de. Thanks!
+
+
+@item "default not in switch" (Warning, ANSI-violation)
+
+ A default label that is not in any switch-statement was found.
+ Perhaps there are unbalanced '@{' '@}'.
+
+
+@item "( expected" (Warning, ANSI-violation)
+
+
+
+@item "loop eliminated" (Warning)
+
+ There was a loop that will never be executed (e.g. while(0)...)
+ and therefore the entire loop was eliminated.
+ I do not know any reason for such loops, so there is probably an
+ error.
+
+
+@item "statement has no effect" (Warning)
+
+ There is a statement that does not cause any side-effects (e.g.
+ assignments, function calls etc.) and is therefore superfluous.
+ E.g. you might have typed a==b; instead of a=b;
+
+
+@item "'while' expected" (Warning, ANSI-violation)
+
+ The 'while' in a do-while loop is missing.
+
+
+@item "function should not return a value" (Warning)
+
+ You specified an argument to return although the function is
+ void. Declare the function as non-void.
+
+
+@item "function should return a value" (Warning)
+
+ You did not specify an argument to return although the function
+ is not void. Declare the function as void or specify a return
+ value.
+
+
+@item "@{ expected" (Warning, ANSI-violation)
+
+
+
+@item "internal error %d in line %d of file %s !!" (Fatal, Error)
+
+ There was an internal error (i.e. a bug in the compiler)!
+ Please report the error to vb@@compilers.de. Thanks!
+
+
+@item "there is no message number %d" (Fatal)
+
+ You tried to activate or suppress a message that does not exist.
+
+
+@item "message number %d cannot be suppressed" (Fatal)
+
+ You cannot suppress a message that displays a real error,
+ ANSI-violation or another real problem.
+ Only 'harmless' warnings can be suppressed.
+
+
+@item "implicit declaration of function <%s>" (Warning)
+
+ A function was called before it was declared and therefore
+ implicitly declared as
+
+ int function();
+
+ This should be avoided in new programs.
+
+
+@item "function call without prototype in scope" (Warning)
+
+ When writing new programs it is probably sensible to use prototypes
+ for every function. If a function is called without a prototype in
+ scope this may cause incorrect type conversions and is usually an
+ error.
+
+
+@item "#pragma used" (Warning)
+
+ Usage of #pragma should be avoided in portable programs.
+
+
+@item "assignment in comparison context" (Warning)
+
+ The expression in an if-, for-, while- or do-while-statement
+ is an assignment, e.g.
+
+ if(i=0)...
+
+ This could an error, if you wanted if(i==0).
+ If you turned on this warning and want it to shut up for a
+ certain expression you can cast it to its type, e.g.
+
+ if((int)(i=0))...
+
+ Note that only assignments with '=' will be warned, not '+=' etc.
+
+
+@item "comparison redundant because operand is unsigned" (Warning)
+
+ A comparison with an unsigned variable is redundant, because
+ the result will always be constant, e.g.
+
+ unsigned int i;
+ if(i<0)...
+
+ This usually is a programming error and can be avoided in all cases.
+
+
+@item "cast to narrow type may cause loss of precision" (Warning)
+
+ A variable is cast to a type smaller than its original type, so
+ that some information may get lost.
+ However this warning will be displayed in lots of cases where
+ no problem can arise, e.g. (short)(a==b).
+
+
+@item "pointer cast may cause alignment problems" (Warning)
+
+ A pointer is cast to a pointer to a type with stricter alignment
+ requirements, i.e. the new pointer might be invalid if you do not
+ know what you are doing.
+ Those casts should be avoidable in all 'usual' cases.
+
+
+@item "no declaration of global variable <%s> before definition" (Warning)
+
+ It is usually good to declare all global variables (including
+ functions) in header files.
+
+
+@item "'extern' inside function" (Warning)
+
+ Declaration of external variables in inner blocks is usually
+ not a good idea.
+
+
+@item "dead assignment to <%s> eliminated" (Warning)
+
+ A variable is assigned a value that is never used or gets
+ overwritten before it is used. If this occurs in real code then
+ there is either an error or an unnecessary assignment.
+
+ This is detected only in optimizing compilation.
+
+
+@item "var <%s> is used before defined" (Warning)
+
+ The variable is used before it was assigned a value and therefore
+ is undefined. It cannot be detected if the code where it is used
+ can be reached, but if it is reached it will cause undefined
+ behaviour. So it is most probably an error either way (see 170).
+
+ However not all uninitialized usages can be found.
+
+ Also note that the compiler may choose convenient values for
+ uninitialized variables. Example:
+
+ int f(int a)
+ @{
+ int x;
+ if(a) x=0;
+ return(x);
+ @}
+
+ Here the optimizer may choose that x==0 if it is uninitialized and
+ then only generate a return(0);
+ It can also happen that you get different values if you read an
+ uninitialized variable twice although it was not assigned a value
+ in between.
+
+ This is only detected in optimizing compilation.
+
+
+@item "would need more than %ld optimizer passes for best results" (Warning)
+
+ The optimizer would probably be able to do some further
+ optimizations if you increased the number of allowed passes
+ with the -optpasses=n option.
+
+
+@item "function <%s> has no return statement" (Warning)
+
+ A non-void function has no return statement. Either this function
+ never returns (then better declare it as void) or it reaches
+ end of control which would be an error.
+
+ As main() cannot be declared as void you will not be warned if
+ main has no return statement. If you want a warning for main, too,
+ you can turn on warning 174.
+
+
+@item "function <main> has no return statement" (Warning)
+
+ The same like 173 for main, so you can turn it on/off separately.
+
+
+@item "this code is weird" (Warning)
+
+ The code has a very strange control flow. There is probably a
+ jump inside a loop or something similar and the optimizer will
+ not make any loop optimization and perhaps worse register
+ allocation on this construct.
+ There must be goto statements in the source.
+
+ This warning is only detected in optimizing compilation.
+
+
+@item "size of incomplete type not available" (Warning, ANSI-violation)
+
+ An incomplete type must not be the argument for sizeof.
+
+
+@item "line too long" (FATAL, Error, ANSI-violation, Preprocessor)
+
+
+
+@item "identifier must begin with a letter or underscore" (FATAL, Error, ANSI-violation, Preprocessor)
+
+
+
+@item "cannot redefine macro" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "missing ) after argumentlist" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "identifier expected" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "illegal character in identifier" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "missing operand before/after ##" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "no macro-argument after #-operator" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "macro redefinition not allowed" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "unexpected end of file (unterminated comment)" (FATAL, Error, Preprocessor)
+
+
+
+@item "too many nested includes" (FATAL, Error, Preprocessor)
+
+
+
+@item "#else without #if/#ifdef/#ifndef" (FATAL, Error, ANSI-violation, Preprocessor)
+
+
+
+@item "#else after #else" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "#endif without #if" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "cannot include file" (FATAL, Error, Preprocessor)
+
+
+
+@item "expected \" or < in #include-directive" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "unknown #-directive" (Warning, Preprocessor)
+
+
+
+@item "wrong number of macro arguments" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "macro argument expected" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "out of memory" (FATAL, Error, Preprocessor)
+
+
+
+@item "macro redefinition" (Warning, Preprocessor)
+
+
+
+@item "/* in comment" (Warning, Preprocessor)
+
+
+
+@item "cannot undefine macro" (Error, ANSI-violation, Preprocessor)
+
+
+
+@item "characters after #-directive ignored" (Warning, Preprocessor)
+
+
+
+@item "duplicate case labels" (Warning, ANSI-violation)
+
+ Each case-label in a switch-statement must have a distinct constant
+ value attached (after converting it to the type of the
+ switch-expression).
+
+
+@item "var <%s> is incomplete" (Warning, ANSI-violation)
+
+ An incomplete var was defined. probably you wrote something like:
+
+ int a[];
+
+
+@item "long float is no longer valid" (Warning, ANSI-violation)
+
+ 'long float' was a synonym for double in K&R C, but this is no longer
+ allowed in ANSI C.
+
+
+@item "long double is not really supported by vbcc" (Warning)
+
+ vbcc does not know about long double yet and therefore will use it
+ simply as a synonym for double. This should not break any legal code,
+ but you will not get error messages if you e.g. assign a pointer to
+ double to a pointer to long double.
+
+
+@item "empty struct-declarations are not yet handled correct" (Warning)
+
+ obsolete
+
+
+@item "identifier too long (only %d characters are significant)" (Warning)
+
+
+
+@item "illegal initialization of var <%s>" (Warning, ANSI-violation)
+
+ Perhaps you tried to initialize a variable with external linkage
+ in an inner block.
+
+
+@item "suspicious loop" (Warning)
+
+ vbcc thinks a loop-condition looks suspicious. A possible example
+ could be for(i=0;i!=7;i+=2)
+
+
+@item "ansi/iso-mode turned on" (Warning)
+
+ You turned on the ANSI/ISO-conforming mode. This warning is always
+ displayed unless it is suppressed. So vbcc cannot be blamed to miss
+ a diagnostic for any constraint violation. :-)
+
+
+@item "division by zero (result set to 0)" (Warning, ANSI-violation)
+
+ Similar to warning 84.
+
+
+@item "constant out of range" (Warning, ANSI-violation)
+
+ An integral constant is too large to fit into an unsigned long.
+
+
+@item "constant is unsigned due to size" (Warning)
+
+ If an integral constant is so large that it cannot be represented
+ as long its type is promoted to unsigned long.
+
+
+@item "varargs function called without prototype in scope" (Warning)
+
+ A function which takes a variable number of arguments must not be
+ called without a prototype in scope. E.g. calling printf() without
+ #include <stdio.h> may cause this warning.
+
+
+@item "suspicious format string" (Warning)
+
+ The format-string of a printf-/scanflike function seems to be corrupt
+ or not matching the type of the arguments.
+
+
+@item "format string contains \'\\0\'" (Warning)
+
+ The format string for a printf-/scanflike function contains an
+ embedded '\0' character.
+
+
+@item "illegal use of keyword <%s>" (Warning, ANSI-violation)
+
+ The reserved keywords of C may not be used as identifier.
+
+
+@item "register <%s> used with wrong type" (Error)
+
+
+@item "register <%s> is not free" (Error)
+
+
+@item "'__reg' used in old-style function definition" (Warning)
+
+
+@item "unknown register \"%s\"" (Warning)
+
+
+@item "'...' only allowed with prototypes" (Warning, ANSI-violation)
+
+
+@item "Hey, do you really know the priority of '&&' vs. '||'?" (Warning)
+
+
+@item "be careful with priorities of <</>> vs. +/-" (Warning)
+
+
+@item "address of auto variable returned" (Warning)
+
+
+@item "void function returns a void expression" (Warning)
+
+
+@item "redeclaration of typedef <%s>" (Warning, ANSI-violation)
+
+
+@item "multiple specification of attribute \"%s\"" (Warning)
+
+
+@item "redeclaration of var \"%s\" with differing setting of attribute \"%s\"" (Warning)
+
+@item "string-constant expected" (Error)
+
+@item "tag \"%s\" used for wrong type" (Warning, ANSI-violation)
+
+@item "member after flexible array member" (Error, ANSI-violation)
+
+@item "illegal number" (Error, ANSI-violation)
+
+@item "void character constant" (Preprocessor, Error, ANSI-violation)
+
+@item "spurious tail in octal character constant" (Preprocessor, Error, ANSI-violation)
+
+@item "spurious tail in hexadecimal character constant" (Preprocessor, Error, ANSI-violation)
+
+@item "illegal escape sequence in character constant" (Preprocessor, Error, ANSI-violation)
+
+@item "invalid constant integer value" (Preprocessor, Error, ANSI-violation)
+
+@item "a right parenthesis was expected" (Preprocessor, Error, ANSI-violation)
+
+@item "a colon was expected" (Preprocessor, Error, ANSI-violation)
+
+@item "truncated constant integral expression" (Preprocessor, Error, ANSI-violation)
+
+@item "rogue operator '%s' in constant integral expression" (Preprocessor, Error, ANSI-violation)
+
+@item "invalid token in constant integral expression" (Preprocessor, Error, ANSI-violation)
+
+@item "trailing garbage in constant integral expression" (Preprocessor, Error, ANSI-violation)
+
+@item "void condition for a #if/#elif" (Preprocessor, Error, ANSI-violation)
+
+@item "void condition (after expansion) for a #if/#elif" (Preprocessor, Error, ANSI-violation)
+
+@item "invalid '#include'" (Preprocessor, Error, ANSI-violation)
+
+@item "macro expansion did not produce a valid filename for #include" (Preprocessor, Error, ANSI-violation)
+
+@item "file '%s' not found" (Preprocessor, Error, ANSI-violation)
+
+@item "not a valid number for #line" (Preprocessor, Error, ANSI-violation)
+
+@item "not a valid filename for #line" (Preprocessor, Error, ANSI-violation)
+
+@item "rogue '#'" (Preprocessor, Error, ANSI-violation)
+
+@item "rogue #else" (Preprocessor, Error, ANSI-violation)
+
+@item "rogue #elif" (Preprocessor, Error, ANSI-violation)
+
+@item "unmatched #endif" (Preprocessor, Error, ANSI-violation)
+
+@item "unknown cpp directive '#%s'" (Preprocessor, Error, ANSI-violation)
+
+@item "unterminated #if construction" (Preprocessor, Error, ANSI-violation)
+
+@item "could not flush output (disk full ?)" (Preprocessor, Error, ANSI-violation)
+
+@item "truncated token" (Preprocessor, Error, ANSI-violation)
+
+@item "illegal character '%c'" (Preprocessor, Error, ANSI-violation)
+
+@item "unfinished string at end of line" (Preprocessor, Error, ANSI-violation)
+
+@item "missing macro name" (Preprocessor, Error, ANSI-violation)
+
+@item "trying to redefine the special macro %s" (Preprocessor, Error, ANSI-violation)
+
+@item "truncated macro definition" (Preprocessor, Error, ANSI-violation)
+
+@item "'...' must end the macro argument list" (Preprocessor, Error, ANSI-violation)
+
+@item "void macro argument" (Preprocessor, Error, ANSI-violation)
+
+@item "missing comma in macro argument list" (Preprocessor, Error, ANSI-violation)
+
+@item "invalid macro argument" (Preprocessor, Error, ANSI-violation)
+
+@item "duplicate macro argument" (Preprocessor, Error, ANSI-violation)
+
+@item "'__VA_ARGS__' is forbidden in macros with a fixed number of arguments" (Preprocessor, Error, ANSI-violation)
+
+@item "operator '##' may neither begin nor end a macro" (Preprocessor, Error, ANSI-violation)
+
+@item "operator '#' not followed by a macro argument" (Preprocessor, Error, ANSI-violation)
+
+@item "macro '%s' redefined unidentically" (Preprocessor, Error, ANSI-violation)
+
+@item "not enough arguments to macro" (Preprocessor, Error, ANSI-violation)
+
+@item "unfinished macro call" (Preprocessor, Error, ANSI-violation)
+
+@item "too many argument to macro" (Preprocessor, Error, ANSI-violation)
+
+@item "operator '##' produced the invalid token '%s%s'" (Preprocessor, Error, ANSI-violation)
+
+@item "quad sharp" (Preprocessor, Error, ANSI-violation)
+
+@item "void macro name" (Preprocessor, Error, ANSI-violation)
+
+@item "macro %s already defined" (Preprocessor, Error, ANSI-violation)
+
+@item "trying to undef special macro %s" (Preprocessor, Error, ANSI-violation)
+
+@item "illegal macro name for #ifdef" (Preprocessor, Error, ANSI-violation)
+
+@item "unfinished #ifdef" (Preprocessor, Error, ANSI-violation)
+
+@item "illegal macro name for #undef" (Preprocessor, Error, ANSI-violation)
+
+@item "unfinished #undef" (Preprocessor, Error, ANSI-violation)
+
+@item "illegal macro name for #ifndef" (Preprocessor, Error, ANSI-violation)
+
+@item "unfinished #ifndef" (Preprocessor, Error, ANSI-violation)
+
+@item "reconstruction of <foo> in #include" (Preprocessor, Warning)
+
+@item "comment in the middle of a cpp directive" (Preprocessor, Warning)
+
+@item "null cpp directive" (Preprocessor, Warning)
+
+@item "rogue '#' in code compiled out" (Preprocessor, Warning)
+
+@item "rogue '#' dumped" (Preprocessor, Warning)
+
+@item "#error%s" (Preprocessor, ANSI-violation, Error)
+
+@item "trigraph ?""?%c encountered" (Preprocessor, Warning)
+
+@item "unterminated #if construction (depth %ld)" (Preprocessor, Error, ANSI-violation)
+
+@item "malformed identifier with UCN: '%s'" (Preprocessor, Warning, ANSI-violation)
+
+@item "truncated UTF-8 character" (Preprocessor, Warning, ANSI-violation)
+
+@item "identifier not followed by whitespace in #define" (Preprocessor, Warning, ANSI-violation)
+
+@item "assignment discards restrict" (Warning, ANSI-violation)
+
+@item "storage-class in declaration within for() converted to auto" (Warning, ANSI-violation)
+
+@item "corrupted special object" (ANSI-violation, Fatal)
+
+@item "<inline> only allowed in function declarations" (Error, ANSI-violation)
+
+@item "reference to static variable <%s> in inline function with external linkage" (Error, ANSI-violation)
+
+@item "underflow of pragma popwarn" (Error, ANSI-violation)
+
+@item "invalid argument to _Pragma" (Preprocessor, Error, ANSI-violation)
+
+@item "missing comma before '...'" (Preprocessor, Error, ANSI-violation)
+
+@item "padding bytes behind member <%s>" (Warning)
+
+@item "member <%s> does not have natural alignment" (Warning)
+
+@item "function <%s> exceeds %s limit" (Warning)
+
+@item "%s could not be calculated for function <%s>" (Warning)
+
+@item "offsetof applied to non-struct" (Error, ANSI-violation)
+
+@item "trailing garbage in #ifdef" (Preprocessor, Warning, ANSI-violation)
+
+@item "too many arguments to macro" (Preprocessor, Warning, ANSI-violation)
+
+@item "truncated comment" (Preprocessor, Warning|ANSI-violation)
+
+@item "trailing garbage in preprocessing directive" (Preprocessor, Warning, ANSI-violation)
+
+@item "variable-length array must have auto storage-class" (Error, ANSI-violation)
+
+@item "member <%s> has type with zero alignment/size (probably void)" (Error, ANSI-violation, Fatal)
+
+@item "stack information for target <%s> unavailable" (Warning)
+
+@item "used registers information unavailable for target <%s>" (Warning)
+
+@item "computed %sstack usage %d but set to %d" (Warning)
+
+@item "unable to compute call targets" (Warning)
+
+@item "computed register usage differs from specified one" (Warning)
+
+@item "trailing garbage in #include" (Preprocessor, Warning ,ANSI-violation)
+
+@item "target-warning: %s" (Warning)
+
+@item "target-error: %s" (Error)
diff --git a/doc/interface.texi b/doc/interface.texi
new file mode 100644
index 0000000..5648833
--- /dev/null
+++ b/doc/interface.texi
@@ -0,0 +1,2830 @@
+
+@section Introduction
+
+This chapter is under construction!
+
+
+
+This chapter describes some of the internals of @command{vbcc}
+ and tries to explain
+what has to be done to write a code generator for @command{vbcc}.
+However if someone wants to write one, I suggest to contact me first,
+so that it can be integrated into the source tree.
+
+You have to create a new directory for the new target named
+@file{machines/<target-name>} and write the files @file{machine.c},
+@file{machine.h}
+and @file{machine.dt}. The compiler for this target will be called
+@command{vbcc<target-name>} and can be built doing a
+@command{make TARGET=<target-name> bin/vbcc<target-name>}.
+
+From now on integer means any of @code{char, short, int, long, long long} or their
+unsigned couterparts. Arithmetic means integer or @code{float} or
+@code{double} or @code{long double}.
+Elementary type means arithmetic or pointer.
+
+Note that this documentation may mention explicit values when introducing
+symbolic constants. This is due to copying and pasting from the source
+code. These values may not be up to date and in some cases can be overridden.
+Therefore do never use the absolute values but rather the symbolic
+representations.
+
+
+@section Building vbcc
+
+This section deals with the steps necessary to build the typical
+@command{vbcc} executables from the sources.
+
+@subsection Directory Structure
+
+ The vbcc-directory contains the following important files and
+ directories:
+@table @file
+@item vbcc/
+The main directory containing the compiler sources.
+
+@item vbcc/Makefile
+The Makefile used to build @command{vbcc}.
+
+@item vbcc/frontend/
+Directory containing the source to @command{vc}, the compiler driver.
+
+@item vbcc/machines/<target>/
+Directory for the @code{<target>} backend.
+
+@item vbcc/machines/ucpp/
+Directory containing the builtin preprocessor.
+
+@item vbcc/vsc/
+Directory containing source to @command{vsc}, the instruction scheduler.
+
+@item vbcc/bin/
+Directory the executables will be placed in.
+@end table
+
+ All compiling is done from the main directory.
+ The frontend @command{vc}
+ is not target-dependend and therefore only one version
+ is created.
+
+ Every available target has at least one subdirectory with its name in
+ @file{vbcc/machines} and contains at least the files
+@file{machine.h}, @file{machine.c} and
+ @file{machine.dt}. Target-specific object-files will also be stored in that
+ directory.
+
+ The executables will be placed in @file{vbcc/bin/}. The main compiler will
+ be called @command{vbcc<target>}.
+
+
+@subsection Adapting the Makefile
+
+ Before building anything you have to insert correct values for
+ @code{CC, NCC, LDFLAGS} and @code{NLDFLAGS} in the @file{Makefile}.
+
+@table @code
+ @item CC
+ Here you have to insert a command that invokes an ANSI C
+ compiler you want to use to build vbcc. It must support
+ @option{-D}, @option{-I}, @option{-c} and @option{-o}
+ the same like e.g. @command{vc} or @command{gcc}.
+ Additional options should also be inserted here. E.g. if you
+ are compiling for the Amiga with @command{vbcc} you should add
+ @option{-DAMIGA}.
+
+ @item LDFLAGS
+ Here you have to add options which are necessary for linking.
+ E.g. some compilers need special libraries for floating-point.
+
+ @item NCC
+ @itemx NLDFLAGS
+ These are similar to @code{CC} and @code{LDFLAGS} but they must always
+ describe a native compiler, i.e. Programs compiled with @code{NCC/NLDFLAGS}
+ must be executable on the host system. This is needed because during
+ the build programs may have to be executed on the host.
+@end table
+
+ An example for the Amiga using @command{vbcc} would be:
+@example
+ CC = vc -DAMIGA -c99
+ LDFLAGS = -lmieee
+ NCC = $(CC)
+ NLDFLAGS = $(LDFLAGS)
+@end example
+
+ An example for a typical Unix-installation would be:
+@example
+ CC = cc
+ LDFLAGS = -lm
+ NCC = $(CC)
+ NLDFLAGS = $(LDFLAGS)
+@end example
+
+The following settings are probably necessary for Open/Free/Any BSD i386 systems:
+@example
+ CC = gcc -D_ANSI_SOURCE
+ LDFLAGS = -lm
+ NCC = $(CC)
+ NLDFLAGS = $(LDFLAGS)
+@end example
+
+
+@subsection Building vc
+
+Note to users of Open/Free/Any BSD i386 systems: You will probably have to use
+GNU make instead of BSD make, i.e. in the following examples replace "make"
+with "gmake".
+
+ Type:
+@example
+ make bin/vc
+@end example
+
+@subsection Building vsc
+
+ Type:
+@example
+ make TARGET=<target> bin/vsc<target>
+@end example
+ For example:
+@example
+ make TARGET=alpha bin/vscalpha
+@end example
+
+ Omit this step if there is no file @file{machines/<target>/schedule.c}.
+
+
+@subsection Building vbcc
+
+ Type:
+
+@example
+ make TARGET=<target> bin/vbcc<target>
+@end example
+For example:
+@example
+ make TARGET=alpha bin/vbccalpha
+@end example
+
+ During the build the program @command{dtgen} will be generated and executed on
+ the host-system. First it will ask you whether you are building a
+ cross-compiler.
+
+ Answer @code{y} only if you are building a cross-compiler (i.e. a compiler
+ which does not produce code for the same machine it it running on).
+
+ Note that it does _not_ matter if you are cross-building a compiler,
+ i.e. if you are running on system A and building a B->B compiler
+ by using an A->B compiler then you can answer @code{n}.
+
+ If you answered @code{y} you will be asked if your system/compiler offers
+ certain datatypes. This refers to the compiler you described with
+ CC in the Makefile.
+ E.g. if @code{CC} is an A->B cross-compiler you have to answer the questions
+ according to B.
+ To each question answer @code{y} or @code{n} depending if such a datatype is
+ available on that compiler. If you answered @code{y} you have to type in
+ the name of that type on the compiler (e.g. @code{signed int},
+ @code{unsigned char} etc.).
+ If there are not enough datatypes available to build @command{vbcc}
+ an error
+ message will be printed and the build aborts.
+
+
+@subsection Configuring
+
+ Consult the @command{vbcc}-documentation for information on
+ how to create the necessary config-files.
+
+
+@subsection Building Cross-Compilers
+
+ As there is often confusion when it comes to cross-building compilers
+ or building cross-compilers, here is what has to be done to cross-build
+ a B->C cross-compiler on system A with only a native A->A compiler
+ available.
+
+ This is done by first building an A->B compiler and then cross-building
+ the B->C compiler using the A->B compiler.
+
+ For the first step you use the A->A compiler for @code{CC} as well as
+ @code{NCC}.
+ Now you type:
+@example
+ make bin/vc
+ make TARGET=B bin/vscB # omit if there is no machines/B/schedule.c
+ make TARGET=B bin/vbccB
+@end example
+
+ The questions about datatypes are answered according to A.
+ Then you should write a @file{vc.config} for the @code{vbccB}
+ cross-compiler.
+
+ Now create a second directory containing all the sources to @command{vbcc}
+ and
+ set @code{CC/LDFLAGS} to @command{vc} using the config-file for vbccB and
+ @code{NCC/NLDFLAGS}
+ to the A->A compiler. Type:
+@example
+ make bin/vc
+ make TARGET=C bin/vscC # omit if there is no machines/C/schedule.c
+ make TARGET=C bin/vbccC
+@end example
+
+
+
+@section The Intermediate Code
+
+@command{vbcc} will generate intermediate code for every function and pass
+this code to the code generator which has to convert it into the desired output.
+
+In the future there may be a code generator generator which reads a machine
+description file and generates a code generator from that, but it is not
+clear whether this could simplify much without taking penalties in the
+generated code.
+Anyway, this would be a layer on top of the current interface to the code
+generator, so that the interface described in this document would still be
+valid and accessible.
+
+@subsection General Format
+
+The intermediate code is represented as a doubly linked list of quadruples
+(I am calling them ICs from now on) consisting mainly of an operator, two
+source operands and a target. They are represented like this:
+
+@example
+
+struct IC@{
+ struct IC *prev;
+ struct IC *next;
+ int code;
+ int typf;
+ int typf2;
+ [...]
+ struct obj q1;
+ struct obj q2;
+ struct obj z;
+ [...]
+ struct ext_ic ext; /* optional */
+@};
+@end example
+
+The only members relevant to the code generator are
+@code{prev, next, code, typf, typf2, q1, q2, z} and (optionally) @code{ext_ic}.
+
+@code{prev} and @code{next} are pointers to the previous and next IC.
+The first IC has @code{prev==0} and the last one has @code{next==0}.
+
+@code{typf} and @code{typf2} are the type of the operands of this IC.
+In most ICs all operands have the same type and therefore only @code{typf}
+is used. However, some ICs have operands of different types (e.g.
+converting an operand to another type or adding an integer to a pointer).
+@code{typf2} is used in these cases.
+
+Macros are provided which yield the type of an operand.
+@code{q1typ(), q2typ()} and @code{ztyp()} return the type of the first source
+operand, the second source operand and the destination, respectively.
+They have to be passed a pointer to a valid IC as argument. The results are
+undefined if the IC does not contain the specified operand (e.g. @code{q2typ()}
+for an IC with only a single operand).
+
+The standard types which are defined by default are:
+
+@example
+ #define CHAR
+ #define SHORT
+ #define INT
+ #define LONG
+ #define LLONG
+ #define FLOAT
+ #define DOUBLE
+ #define LDOUBLE
+ #define VOID
+ #define POINTER
+ #define ARRAY
+ #define STRUCT
+ #define UNION
+ #define ENUM /* not relevant for code generator */
+ #define FUNKT
+@end example
+
+ and can be additionally or'ed by
+
+@example
+ #define UNSIGNED
+ #define CONST
+ #define VOLATILE
+ #define UNCOMPLETE
+@end example
+
+ However, only @code{UNSIGNED} is of real importance for the code generator.
+ @code{typf&NQ} yields the type without any qualifiers, @code{typf&NU}
+ yields the type without any qualifiers but @code{UNSIGNED}.
+
+It is possible for backends to define additional types. @xref{exttypes}
+for documentation on how to extend the type system.
+
+@node operands
+@subsection Operands
+
+@code{q1, q2} and @code{z} are the source1 (quelle1 in German), source2 and
+target (ziel) operands, respectively.
+If a result has to be computed, it always will be stored in the object @code{z}
+and the objects @code{q1} and @code{q2} usually may not be destroyed during
+this operation (unless they are aliased with the destination).
+
+The objects are described by this structure:
+
+@example
+
+struct obj@{
+ int flags;
+ int reg;
+ int dtyp;
+ struct Var *v;
+ struct AddressingMode *am;
+ union atyps@{
+ zchar vchar;
+ zchar 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;
+ @} val;
+@};
+
+@end example
+
+@code{flags} specifies the kind of object. It can be a combination of
+
+@table @code
+
+@item #define KONST 1
+ The object is a constant. Its value is in the corresponding (to
+ @code{typf} or @code{typf2})
+ member of @code{val}.
+
+@item #define VAR 2
+ The object is a variable. The pointer to its @code{struct Var} is in
+ @code{v}. @code{val.vlong} vontains an offset that has to be added to it.
+ Fur further details, @pxref{Variables}.
+
+@item #define DREFOBJ 32
+ The content of the location in memory the object points to is used.
+ @code{dtyp} contains the type of the pointer. In systems with
+ only one pointer type, this will always be @code{POINTER}.
+
+@item #define REG 64
+ The object is a register. @code{reg} contains its number.
+
+@item #define VARADR 128
+ The address of the object is to be used. Only together with static
+ variables (i.e. @code{storage_class == STATIC} or @code{EXTERN}).
+
+@end table
+
+The possible combinations of these flags should be:
+
+@itemize
+ @item @code{0} (no object)
+ @item @code{KONST}
+ @item @code{KONST|DREFOBJ}
+ @item @code{REG}
+ @item @code{VAR}
+ @item @code{VAR|REG}
+ @item @code{REG|DREFOBJ}
+ @item @code{KONST|DREFOBJ}
+ @item @code{VAR|DREFOBJ}
+ @item @code{VAR|REG|DREFOBJ}
+ @item @code{VAR|VARADR}
+@end itemize
+
+Also some other bits which are not relevant to the code generator may be set.
+
+Constants will usually be in @code{q2} if possible. One of the sources always
+is not constant and the target is always an lvalue.
+The types of the operands can be queried using the macros
+@code{q1typ(), q2typ()} and @code{ztyp()}.
+In most cases (i.e. when not explicitly stated) the type is an elementary type
+(i.e. arithmetic or pointer).
+
+@code{am} can be used to store information on special addressing modes.
+This has to be handled by the by the code generator. However @code{am} has to be 0
+or has to point to a @code{struct AddressingMode} that was allocated using @code{malloc()}
+when the code generator returns. @code{struct AddressingMode} has to be defined
+in @file{machine.h}.
+
+@code{val} stores either the value of the object if it is a constant or an
+offset if it is a variable.
+
+@code{code} specifies the operation. Fur further details @pxref{operations}.
+
+
+
+@node Variables
+@subsection Variables
+
+ A @code{struct Var} looks like:
+
+@example
+
+ struct Var@{
+ int storage_class;
+ [...]
+ char *identifier;
+ [...]
+ zmax offset;
+ struct Typ *vtyp;
+ [...]
+ char *vattr;
+ unsigned long tattr; /* optional */
+ @};
+@end example
+
+
+ The relevant entries are:
+
+@table @code
+ @item identifier
+ The name of the variable. Usually only of interest for variables
+ with external-linkage.
+
+ @item storage_class
+ One of:
+ @example
+ #define AUTO 1
+ #define REGISTER 2
+ #define STATIC 3
+ #define EXTERN 4
+ #define TYPEDEF 5 /* not relevant */
+ @end example
+ The backend should use the macros @code{isauto(), isstatic()}
+ and @code{isextern()} to check which category a variable falls into.
+
+ @item offset
+ Contains an offset relative to the beginning of the variable's
+ storage. Used, for example, when accessing members of structures.
+
+ @item vtyp
+ The type of the variable (@pxref{compositetypes}).
+
+ @item vattr
+ A string with attributes used in the declaration of the variable.
+ @xref{targetattributes} for further details.
+
+ @item tattr
+ Flags used when declaring the variable.
+ @xref{targetattributes} for further details.
+@end table
+
+ If the variable is not assigned to a register (i.e. bit @code{REG}
+ is not set in the flags of the corresponding @code{struct obj}) then
+ the variable can be addressed in the following ways (with
+ examples of 68k-code):
+
+@table @code
+ @item isauto(storage_class) != 0
+ @code{offset} contains the offset inside the local-variables
+ section. The code generator must decide how it's going to handle
+ the activation record.
+ If @code{offset < 0} then the variable is a function argument on
+ the
+ stack. In this case the offset in the parameter-area is
+ @code{- (offset + maxalign)}.
+
+ The code generator may have to calculate the actual offset
+ to a stack- or frame-pointer from the value in @code{offset}.
+@example
+ offset + val.vlong(sp)
+@end example
+ Note that @code{storage_class == REGISTER} is equivalent to
+ @code{AUTO} - whether
+ the variable is actually assigned a register is specified by
+ the bit @code{REG} in the @code{flags} of the @code{struct obj}.
+
+ @item isextern(storage_class) != 0
+ The variable can be addressed through its name in @code{identifier}.
+@example
+ val.vlong + '_'identifier
+@end example
+
+ @item isstatic(storage_class) != 0
+ The variable can be addressed through a numbered label. The
+ label number is stored in @code{offset}.
+@example
+ val.vlong+'l'offset
+@end example
+@end table
+
+@node compositetypes
+@subsection Composite Types
+
+The C language offers types which are composed out of other types,
+e.g. structures or arrays. Therefore, a C type can be an arbitrarily
+complex structure. Usually the backend does not need to deal with
+those structures. The ICs contain only the simple type flags, e.g.
+@code{INT} or @code{STRUCT}, but not the members of a structure (instead
+the size is given).
+
+Most backends do not have to deal with complex types at all, but
+there are some ways to access them, if needed (for example, they may be
+needed when generating debug information). Therefore, this chapter
+describes the representation of such full types.
+
+Types are represented by the following structure:
+@example
+struct Typ @{
+ int flags;
+ struct Typ *next;
+ struct struct_declaration *exact;
+ zmax size;
+ char *attr;
+@};
+@end example
+
+@code{flags} is the simple type as it is generally used in the
+backend. The meaning of the other members depends on @code{flags}.
+@code{attr} is an attribute that can be added to the type using
+the sytax @code{__attr("...")} (which is parsed like a type-qualifier,
+e.g. @code{const}). If several attributes are specified
+for a type, the strings will be concatenated, separated by semi-colons.
+
+If the type is a pointer (@code{ISPOINTER(flags) != 0}), then @code{next}
+will point to the type the pointer points to.
+
+If the type is an array (@code{ISARRAY(flags) != 0}), then @code{size}
+contains the number of elements and @code{next} points to a type structure
+representing the type of each array element.
+
+If the type is a structure (@code{ISSTRUCT(flags) != 0}), a union
+(@code{ISUNION(flags) != 0}) or a function (@code{ISFUNC(flags) != 0}),
+then @code{exact}
+is a pointer to a @code{struct_declaration} (which is also used to represent
+unions and function prototypes) that looks like this:
+@example
+struct struct_declaration @{
+ int count;
+ int label;
+ int typ;
+ ...
+ struct struct_list (*sl)[];
+ char *identifier;
+@};
+@end example
+
+@code{count} is the number of members, @code{label} can be used to store
+a label when generating debug information. @code{typ} is either @code{STRUCT},
+@code{UNION} or @code{FUNKT} to denote whether it applies to a structure,
+union or function-prototype.
+
+@code{identifier} is only available for struct- and union-tags.
+
+@code{sl} points to an array of @code{struct struct_list}s which contain
+information on each member/parameter:
+@example
+struct struct_list @{
+ char *identifier;
+ struct Typ *styp;
+ zmax align;
+ int bfoffset;
+ int bfsize;
+ int storage_class;
+ int reg;
+@};
+@end example
+
+@code{identifier} is the identifier of the member/parameter, if available.
+@code{styp} denotes the full type, @code{align} the alignment in bytes
+(only for struct/union), @code{bfoffset} and @code{bfsize} the size and
+offset of bitfield-members, @code{storage_class} the storage class of
+function parameters (may be @code{AUTO} or @code{REGISTER}) and @code{reg}
+denotes the register a parameter is passed in.
+
+Example: If @code{struct Typ *t} points to a structure-type, then the type
+of the second structure member can be accessed through
+@code{(*t->exact->sl)[1].styp}.
+
+A prototyped function will have a last argument of type @code{VOID} unless
+it is a function accepting a variable number of arguments. If a function
+was declared without a prototype it will have no parameters, a function
+declared with prototype accepting no arguments will have one parameter of
+type @code{VOID}.
+
+Also, in the case of a function type, the @code{next}-member of a
+@code{struct Typ} points to the return type of the function.
+
+
+@node operations
+@subsection Operations
+
+This section lists all the different operations allowed in the
+intermediate code passed to the backend. It lists the symbolic name
+of the @code{code} value (the value should not be used), a template
+of the operands and a description. The description sometimes
+contains internals (e.g. which types are stored in @code{typf} and
+which in @code{typf2}), but they should not be used. Access them using
+the macros provided (e.g. @code{q1typ,q2typ,ztyp}) whenever possible.
+
+
+@table @code
+@item #define ASSIGN 2
+
+ Copy @code{q1} to @code{z}. @code{q1->z}.
+
+ @code{q2.val.vmax} contains the size of the objects (this is
+ necessary if it is an array or a struct). It should be accessed
+ using the @code{opsize()}-macro.
+ @code{typf} does not have to be an elementary type!
+
+ The only case where @code{typf == ARRAY} should be in automatic initializations.
+
+ It is also possible that @code{(typf&NQ) == CHAR} but the size is != 1. This is
+ created for an inline memcpy/strcpy where the type is not known.
+
+@item #define OR 16
+@item #define XOR 17
+@itemx #define AND 18
+
+ Bitwise boolean operations. @code{q1,q2->z}.
+
+ All operands are integers.
+
+@item #define LSHIFT 25
+@itemx #define RSHIFT 26
+
+ Bit shifting. @code{q1,q2->z}.
+
+ @code{'q2'} is the number of shifts.
+ All operands are integers.
+
+@item #define ADD 27
+@item #define SUB 28
+@item #define MULT 29
+@itemx #define DIV 30
+
+ Standard arithmetic operations. @code{q1,q2->z}.
+
+ All operands are of arithmetic types (integers or floating point).
+
+@item #define MOD 31
+
+ Modulo (@code{%}). @code{q1,q2->z}.
+
+ All operands are integers.
+
+@item #define KOMPLEMENT 33
+
+ Bitwise complement. @code{q1->z}.
+
+ All operands are integers.
+
+@item #define MINUS 38
+
+ Unary minus. @code{q1->z}.
+
+ All operands are of arithmetic types (integers or floating point).
+
+@item #define ADDRESS 40
+
+ Get the address of an object. @code{q1->z}.
+
+ @code{z} is always a pointer and @code{q1} is always an auto variable.
+
+@item #define CALL 42
+
+ Call the function @code{q1}. @code{q1}.
+
+ @code{q2.val.vmax} contains the number of bytes pushed on the stack as
+ function arguments for this call (use the @code{pushedargsize()}-macro
+ to access this size). Those may have to be popped from the
+ stack after the function returns depending on the calling mechanism.
+
+ A @code{CALL} IC has a member @code{arg_cnt} which contains the number
+ of arguments to this function call. @code{arg_list[i]} (with @code{i}
+ in the range 0...@code{arg_cnt-1}) contains the pointer to the
+ IC passing the @code{i}-th argument.
+
+@item #define CONVERT 50
+
+ Convert one type to another. @code{q1->z}.
+
+ @code{z} is always of the type @code{typf}, @code{q1} of type @code{typf2}.
+
+ Conversions between floating point and pointers do not occur, neither
+ do conversions to and from structs, unions, arrays or void.
+
+@item #define ALLOCREG 65
+
+ Allocate a register. @code{q1}.
+
+ From now on the register @code{q1.reg} is in use. No code has to be generated
+ for this, but it is probably useful to keep track of the registers
+ in use to know which registers are available for the code generator
+ at a certain time and which registers are trashed by the function.
+
+@item #define FREEREG 66
+
+ Release a register. @code{q1}.
+
+ From now on the register @code{q1.reg} is free.
+
+ Also it means that the value currently stored in @code{q1.reg} is not used any
+ more and provides a little bit of data flow information.
+ Note however, if a @code{FREEREG} follows a branch, the value of the register
+ may be used at the target of the branch.
+
+@item #define COMPARE 77
+
+ Compare and set condition codes. @code{q1,q2(->z)}.
+
+ Compare the operands and set the condition code, so that
+ @code{BEQ, BNE, BLT, BGE, BLE} or @code{BGT} works as desired.
+ If @code{z.flags == 0} (this is always the case unless the backend sets
+ @code{multiple_ccs} to 1 and @option{-no-multiple-ccs} is not used)
+ the condition codes will be evaluated only by an IC immediately
+ following the @code{COMPARE}, i.e. the next instruction (except possible
+ @code{FREEREG}s) will be a conditional branch.
+
+ However, if a target supports several condition code registers and sets
+ the global variable @code{multiple_ccs} to 1, @command{vbcc} might use those registers
+ and perform certain optimizations. In this case @code{z} may be non-empty and the
+ condition codes have to be stored in @code{z}.
+
+ Note that even if @code{multiple_ccs} is set, a backend must nevertheless
+ be able to deal with @code{z == 0}.
+
+@item #define TEST 68
+
+ Test @code{q1} against 0 and set condition codes. @code{q1(->z)}
+
+ This is equivalent to @code{COMPARE q1,#0}
+ but only the condition code for @code{BEQ} and @code{BNE} has to be set.
+
+@item @code{#define LABEL 69}
+
+ Generate a label. @code{typf} specifies the number of the label.
+
+@item #define BEQ 70
+@item #define BNE 71
+@item #define BLT 72
+@item #define BGE 73
+@item #define BLE 74
+@itemx #define BGT 75
+
+ Branch on condition codes. (@code{q1}).
+
+ @code{typf} specifies the label where program execution shall continue, if the
+ condition code is true (otherwise continue with next statement).
+ The condition codes mean equal, not equal, less than, greater or equal,
+ less or equal and greater than.
+ If @code{q1} is empty (@code{q1.flags == 0}), the codes set by the last @code{COMPARE}
+ or @code{TEST} must be evaluated. Otherwise @code{q1} contains the condition codes.
+
+ On some machines the type of operands of a comparison (e.g unsigned or
+ signed) is encoded in the branch instructions rather than in the
+ comparison instructions. In this case the code generator has to keep
+ track of the type of the last comparison.
+
+ Similarly, in some architectures, the compare and the branch can be
+ combined.
+
+@item #define BRA 76
+
+ Branch always. @code{typf} specifies the label where program execution
+ continues.
+
+@item #define PUSH 78
+
+ Push @code{q1} on the stack (for argument passing). @code{q1}.
+
+ @code{q2.val.vmax} contains the size of the object (should be accessed
+ using the @code{opsize()}-macro), @code{z.val.vmax}
+ contains the size that has to be pushed (access it using the
+ @code{pushsize()}-macro). These sizes may differ due to
+ alignment issues.
+
+ @code{q1} does not have to
+ be an elementary type (see @code{ASSIGN}).
+ Also, @code{q1} can be empty. This is used for ABIs which require
+ stack-slots to be omitted.
+
+ Depending on @code{ORDERED_PUSH} the @code{PUSH} ICs are generated
+ starting with the first or the last arguments. The direction of
+ the stack-growth can be chosen by the backend. Note that this is only
+ used for function-arguments, they can be pushed in opposite direction
+ of the real stack.
+
+@item #define ADDI2P 81
+
+ Add an integer to a pointer. @code{q1,q2->z}.
+
+ @code{q1} and @code{z} are always pointers (of type @code{typf2}) and
+ @code{q2} is an integer of type @code{typf}.
+ @code{z} has to be @code{q1} increased by @code{q2} bytes.
+
+@item #define SUBIFP 82
+
+ Subtract an Integer from a pointer. @code{q1,q2->z}.
+
+ @code{q1} and @code{z} are always pointers (of type @code{typf2}) and
+ @code{q2} is an integer of type @code{typf}.
+ @code{z} has to be @code{q1} decreased by @code{q2} bytes.
+
+@item #define SUBPFP 83
+
+ Subtract a pointer from a pointer. @code{q1,q2->z}.
+
+ @code{q1} and @code{q2} are pointers (of type @code{typf2}) and
+ @code{z} is an integer of type @code{typf}.
+ @code{z} has to be @code{q1 - q2} in bytes.
+
+@item #define GETRETURN 93
+
+ Get the return value of the last function call. @code{->z}.
+
+ If the return value is in a register, its number will be @code{q1.reg}.
+ Otherwise @code{q1.reg} will be 0.
+ @code{GETRETURN} immediately follows a @code{CALL} IC (except possible
+ @code{FREEREG}s).
+
+@item #define SETRETURN 94
+
+ Set the return value of the current function. @code{q1}.
+
+ If the return value is passed in a register, the register number will be @code{z.reg}.
+ Otherwise @code{z.reg} will be 0.
+ @code{SETRETURN} is immediately followed by a function exit (i.e. it is the last
+ IC or followed by an unconditional branch to a label which is the last
+ IC - always ignoring possible @code{FREEREG}s).
+
+@item #define MOVEFROMREG 95
+
+ Move a register to memory. @code{q1->z}.
+
+ @code{q1} is always a register and @code{z} an array of size @code{regsize[q1.reg]}.
+
+@item #define MOVETOREG 96
+
+ Load a register from memory. @code{q1->z}.
+
+ @code{z} is always a register and @code{q1} an array of size @code{regsize[z.reg]}.
+
+@item #define NOP 97
+
+ Do nothing.
+
+@end table
+
+
+@section Type System
+
+@subsection Target Data Types
+
+As the compiler should be portable, we must not assume anything about
+the data types of the host system which is not guaranteed by
+ANSI/ISO C. Especially do not assume that the data types of the host
+system correspond to the ones of the target system.
+
+Therefore, @command{vbcc} will provide typedefs which can hold a data type
+of the target machine and (as there is no operator overloading in C)
+functions or macros to perform arithmetic on these types.
+
+The typedefs for the basic target's data types (they can be extended
+by additional types) are:
+
+@table @code
+ @item zchar
+ Type @code{char} on the target machine.
+ @item zuchar
+ Type @code{unsigned char} on the target machine.
+ @item zshort
+ Type @code{short} on the target machine.
+ @item zushort
+ Type @code{unsigned short} on the target machine.
+ @item zint
+ Type @code{int} on the target machine.
+ @item zuint
+ Type @code{unsigned int} on the target machine.
+ @item zlong
+ Type @code{long} on the target machine.
+ @item zulong
+ Type @code{unsigned long} on the target machine.
+ @item zllong
+ Type @code{long long} on the target machine.
+ @item zullong
+ Type @code{unsigned long long} on the target machine.
+ @item zmax
+ A type capable of storing (and correctly doing arithmetic on)
+ every signed integer type. Defaults to @code{zllong}.
+ @item zumax
+ A type capable of storing (and correctly doing arithmetic on)
+ every unsigned integer type. Defaults to @code{zullong}.
+ @item zfloat
+ Type @code{float} on the target machine.
+ @item zdouble
+ Type @code{double} on the target machine.
+ @item zldouble
+ Type @code{long double} on the target machine.
+ @item zpointer
+ A byte pointer on the target machine. Not really used.
+@end table
+
+These typedefs and arithmetic functions to work on them will be
+generated by the program @command{dtgen} when compiling @command{vbcc}.
+It will create the files @file{machines/$(TARGET)/dt.h} and @file{dt.c}.
+
+These files are generated from @file{machines/$(TARGET)/machine.dt}
+which must describe what representations the code generator needs.
+@command{dtgen} will then ask for available types on the host system and
+choose appropriate ones and/or install emulation functions, if available.
+
+In @file{machine.dt}, every data type representation gets a symbol (the ones which are
+already available can be looked up in @file{datatypes/datatypes.h} - new
+ones will be added when necessary).
+The first 14 lines must contain the representations for the
+following types:
+
+@enumerate
+ @item @code{signed char}
+ @item @code{unsigned char}
+ @item @code{signed short}
+ @item @code{unsigned short}
+ @item @code{signed int}
+ @item @code{unsigned int}
+ @item @code{signed long}
+ @item @code{unsigned long}
+ @item @code{signed long long}
+ @item @code{unsigned long long}
+ @item @code{float}
+ @item @code{double}
+ @item @code{long double}
+ @item @code{void *}
+@end enumerate
+
+If the code generator can use several representations, these can be
+added on the same line separated by spaces. E.g. the code generator
+for m68k does not care if the integers are stored big-endian or
+little-endian on the host system because it only accesses them through
+the provided arithmetic functions. It does, however, access floats
+and doubles through byte-pointers and therefore requires them to
+be stored in big-endian-format.
+
+@subsection Target Arithmetic
+
+Now you have a lot of functions/macros performing operations using the
+target machine's arithmetic. You can look them up in @file{dt.h/dt.c}.
+E.g. @code{zmadd()} takes two @code{zmax} and returns their sum as @code{zmadd}. @code{zumadd()} does
+the same with @code{zumax}, @code{zldadd()} with long doubles. No functions for smaller types
+are needed because you can calculate with the wider types and convert the
+results down if needed.
+
+Therefore, there are also conversion functions which convert between types of the
+target machine. E.g. @code{zm2zc} takes a @code{zmax} and returns the value
+converted to a @code{zchar}.
+Again, look at @file{dt.h/dt.c} to see which ones are there.
+
+A few functions for converting between target and host types are also
+there, e.g. @code{l2zm} takes a long and returns it converted to @code{zmax}.
+
+At last there are functions for comparing target data types. E.g.
+@code{zmleq(a,b)} returns true if @code{zlong a <= zlong b} and false otherwise.
+@code{zleqto(a,b)} returns true if @code{zlong a == zlong b} and false otherwise.
+
+
+
+@section @file{machine.h}
+
+This section describes the contents of the file @file{machine.h}.
+Note that
+some optional macros/declaration may be described someplace else in this
+manual.
+
+@table @code
+
+@item #include "dt.h"
+This should be the first statement in @file{machine.h}.
+
+@item struct AddressingMode @{ ... @};
+If machine-specific addressing modes (@pxref{addressingmodes}) are used,
+an appropriate structure can be specified here. Otherwise, just enter
+the following code:
+@example
+struct AddressingMode @{
+ int never_used;
+@};
+@end example
+
+@item #define MAXR <n>
+Insert the number of available registers.
+
+@item #define MAXGF <n>
+Insert the number of command line flags that can be used to
+configure the behaviour of the code generator. This must be at least one
+even if you do not use any flags.
+
+@item #define USEQ2ASZ <0/1>
+If this is set to zero, @command{vbcc} will not generate ICs with the
+target operand being 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.
+
+@item #define MINADDI2P <type>
+Insert the smallest integer type
+that can be added to a pointer. Smaller types will be automatically converted
+to type @code{MINADDI2P} when they are to be added to a pointer.
+This may be subsumed by @code{shortcut()} in the future.
+
+@item #define MAXADDI2P <type>
+Insert the largest integer type
+that can be added to a pointer. Larger types will be automatically converted
+to type @code{MAXADDI2P} when they are to be added to a pointer.
+This may be subsumed by @code{shortcut()} in the future.
+
+@item #define BIGENDIAN <0/1>
+Insert 1 if integers are represented in big endian, i.e. the
+most significant byte is at the lowest memory address, the least significant
+byte at the highest.
+
+@item #define LITTLEENDIAN <0/1>
+Insert 1 if integers are represented in little endian, i.e.
+the least significant byte is at the lowest memory address, the most
+significant byte at the highest.
+
+@item #define SWITCHSUBS <0/1>
+Insert 1 if switch-statements should be compiled into a
+series of @code{SUB/TEST/BEQ} instructions rather than @code{COMPARE/BEQ}.
+This may be useful if the target has a more efficient @code{SUB}-instruction
+which sets condition codes (e.g. 68k).
+
+@item #define INLINEMEMCPY <n>
+Insert the largest size in bytes allowed for inline memcpy.
+In optimizing compilation, certain library memcpy/strcpy-calls
+with length known at compile-time will be inlined using an
+@code{ASSIGN} IC if the size is less or equal to @code{INLINEMEMCPY}.
+The type used for the @code{ASSIGN} IC will be @code{UNSIGNED|CHAR}.
+
+This may be replaced by a variable of type @code{zmax} in the future.
+
+@item #define ORDERED_PUSH <0/1>
+Insert 1 if @code{PUSH} ICs for function arguments shall
+be generated from left to right instead right to left.
+
+@item #define HAVE_REGPARMS 1
+Insert this line if the backend supports register parameters
+(@pxref{regparm}).
+
+@item #define HAVE_REGPAIRS 1
+Insert this line if the backend supports register pairs
+(@pxref{regpairs}).
+
+@item #define HAVE_INT_SIZET 1
+Insert this line if @code{size_t} shall be of type @code{unsigned int}
+rather than @code{unsigned long}.
+
+@item #define EMIT_BUF_LEN <n>
+Insert the maximum length of a line of code output.
+
+@item #define EMIT_BUF_DEPTH <n>
+Insert the number of output lines that should be buffered. This
+can be useful for peephole-optimizing the assembly output (see
+below).
+
+@item #define HAVE_TARGET_PEEPHOLE <0/1>
+Insert 1 if the backend provides an @code{asm_peephole()}
+function (@pxref{asmpeephole}).
+
+@item #define HAVE_TARGET_ATTRIBUTES 1
+Insert this line if the backend provides old target-specific
+variable-attributes (@pxref{targetattributes}).
+
+@item #define HAVE_TARGET_PRAGMAS 1
+Insert this line if the backend provides target-specific
+@code{#pragma}-directives (@pxref{targetpragmas}).
+
+@item #define HAVE_REGS_MODIFIED 1
+Insert this line if the backend supports inter-procedural
+register-allocation (@pxref{regsmodified}).
+
+@item #define HAVE_TARGET_RALLOC 1
+Insert this line if the backend supports context-sensitive
+register-allocation (@pxref{targetralloc}).
+
+@item #define HAVE_TARGET_EFF_IC 1
+Insert this line if the backend provides a @code{mark_eff_ics()}
+function (@pxref{markeffics}).
+
+@item #define HAVE_EXT_IC 1
+Insert this line if the backend provides a @code{struct ext_ic}
+(@pxref{extic}).
+
+@item #define HAVE_EXT_TYPES 1
+Insert this line if the backend supports additional types
+(@pxref{exttypes}).
+
+@item #define HAVE_TGT_PRINTVAL 1
+Insert this line if the backend provides an own @code{printval} function
+@pxref{tgtprintval}).
+
+@item #define JUMP_TABLE_DENSITY <float>
+@item #define JUMP_TABLE_LENGTH <int>
+These values controls the creation of jump-tables (@pxref{jumptables}).
+
+
+@item #define ALLOCVLA_REG <reg>
+@item #define ALLOCVLA_INLINEASM <inline-asm>
+@item #define FREEVLA_REG <reg>
+@item #define FREEVLA_INLINEASM <inline-asm>
+@item #define OLDSPVLA_INLINEASM <inline-asm>
+@item #define FPVLA_REG <reg>
+Necessary defines for C99 variable-length-arrays (@pxref{vlas}).
+
+@item #define HAVE_LIBCALLS 1
+Insert this line if the backend wants certain ICs to be replaced with
+calls to library functions (@pxref{libcalls}).
+
+@item #define AVOID_FLOAT_TO_UNSIGNED 1
+@item #define AVOID_UNSIGNED_TO_FLOAT 1
+Insert these lines to tell the frontend not to generate @code{CONVERT} ICs
+that convert between unsigned integers and floating point. In those cases,
+additional intermediate code will be generated that implements the
+conversion using only signed integers.
+
+@end table
+
+@section @file{machine.c}
+
+This is the main part of the code generator. The first statement
+should be @code{#include "supp.h"} which will include all necessary
+declarations.
+
+The following variables and functions must be provided by machine.c.
+
+@subsection Name and Copyright
+
+ The codegenerater must define a zero-terminated character array
+ @code{char cg_copyright[];} containing name and copyright-notice of
+ the code-generator.
+
+@subsection Command Line Options
+
+ You can use code generator specific commandline options.
+ The number of flags is specified as @code{MAXGF} in @file{machine.h}.
+ Insert the names for the flags as @code{char *g_flags_name[MAXGF]}.
+ If an option was specified @code{(g_flags[i]&USEDFLAG)} is not zero.
+ In @code{int g_flags[MAXGF]} you can choose how the options are to be
+ used:
+@table @code
+ @item 0
+ The option can only be specified. E.g. if
+ @code{g_flags_name[2]=="myflag"}, the commandline may contain
+ @option{-myflag} and @code{(g_flags[2]&USEDFLAG)!=0}.
+ @item VALFLAG
+ The option must be specified with an integer constant, e.g.
+ @option{-myflag=1234}. This value can be found in
+ @code{g_flags_val[2].l}.
+ @item STRINGFLAG
+ The option must be specified with a string, e.g.
+ @option{-myflag=Hallo}. The pointer to the string can be found in
+ @code{g_flags_val[2].p}.
+@end table
+
+@subsection Data Types
+
+The following variables have to be initialized to describe the
+representation of the data types.
+
+@table @code
+@item MAX_TYPE
+ This macro contains the number of different types. In case of target-specific
+ extended types (@pxref{exttypes}) this is set by the backend, otherwise the
+ frontend will use a default.
+
+@item zmax char_bit;
+ The number of bits in a @code{char} on the target (usually 8).
+
+@item zmax align[MAX_TYPE+1];
+ This array must contain the necessary alignments for every
+ type in bytes. Some of the entries in this array are not actually
+ used, but @code{align[type&NQ]} must yield the correct alignment for every type.
+ @code{align[CHAR]} must be 1.
+
+ The alignment of a structure depends not only on @code{sizetab[STRUCT]}
+ but also on the alignment of the members. The maximum of the alignments
+ of all members and @code{sizetab[STRUCT]} is the alignment of any
+ particular structure, i.e. @code{sizetab[STRUCT]} is only a minimum
+ alignment.
+
+ The same applies to unions and arrays.
+
+@item zmax maxalign;
+ This variable must be set to an alignment in bytes that is used when
+ pushing arguments on the stack. (FIXME: describe stackalign)
+
+@item zmax sizetab[MAX_TYPE+1];
+ This array must contain the sizes of every type in bytes.
+
+@item zmax t_min[MAX_TYPE+1];
+ This array must contain the smallest representable number for every
+ signed integer type.
+
+@item zumax t_max[MAX_TYPE+1];
+ This array must contain the largest representable number for every
+ signed integer type.
+
+@item zumax tu_max[MAX_TYPE+1];
+ This array must contain the largest representable number for every
+ unsigned integer type.
+
+@end table
+
+ As @code{zmax} and @code{zumax} may be no elementary types on the host
+ machine, those arrays have to be initialized dynamically (in
+ @code{init_cg()}). It is recommended to use explicit typenames, e.g.
+ @code{sizetab[INT]=l2zm(4L);} to keep it portable and allow
+ later extensions of the type system.
+
+ Also note that those values
+ may not be representable as constants by the host architecture and have to
+ be calculated using the functions for arithmetic on the target's data
+ types. E.g. the smallest representable value of a 32bit twos-complement
+ data type is not guaranteed to be valid on every ANSI C implementation.
+
+ You may not use simple operators on the target data types
+ but you have to use the functions or convert them to an elementary
+ type of the host machine before (if you know that it is representable
+ as such).
+
+@subsection Register Set
+
+The following variables have to be initialized to describe the
+register set of the target.
+
+@table @code
+@item MAXR
+ The valid registers are numbered from 1..@code{MAXR}.
+ @code{MAXR} must be @code{#define}d in @file{machine.h}.
+
+@item char *regnames[MAXR+1]
+This array must contain the names for every register. They do not
+necessarily have to be used in the assembly output but are used for
+explicit register arguments.
+
+@item zmax regsize[MAXR+1]
+This array must contain the size of each register in bytes.
+ It is used to create storage if registers have to be saved.
+
+@item int regscratch[MAXR+1]
+This array must contain information whether a register is
+ a scratchregister, i.e. may be destroyed during a function call (1 or 0).
+ vbcc will generate code to save/restore all scratch-registers which are
+ assigned a value when calling a function (unless it knows the register
+ will not be modified). However, if the code generator
+ uses additional scratch-registers it has to take care to save/restore
+ them.
+
+ Also, the code generator must take care that used non-scratch-registers
+ are saved/restored on function entry/exit.
+
+@item int regsa[MAXR+1]
+This array must contain information whether a register is in use
+ or not at the beginning of a function (1 or 0).
+ The compiler will not use any of those registers for register variables
+ or temporaries, therefore this can be used to mark special registers
+ like a stack- or frame-pointer and to reserve registers to the
+ code-generator. The latter may
+ be reasonable if for many ICs code cannot be generated without using
+ additional registers.
+
+ You must set @code{regsratch[i] = 0} if @code{regsa[i] == 1}. If you
+ want it to be
+ saved across function calls the code generator has to take care of this.
+
+@item int reg_prio[MAXR+1];
+This array must contain a priority (>=0) for every register. When the
+register allocator has to choose between several registers which seem
+to be equal, it will choose the one with the highest priority (if
+several registers have the same priority it is undefined which one
+will be taken).
+
+Note that this priority is only the last decision factor if everything
+else seems to be equal. If one register seems to give a higher cost saving
+(according to the estimation of the register allocator) but has a lower
+priority, it will nevertheless be used. The priority can be used to
+fine-tune the register selection. Some guidelines:
+@itemize @minus
+@item Scratch registers might have a higher priority than non-scratch
+ registers (although the register-allocator will usually handle
+ this anyway).
+@item Registers which are more restricted should have a higher priority
+ (if they seem to give the same saving it is usually better to use
+ the restricted registers and try to keep the more versatile ones
+ for situation in which they can give better savings).
+@item Registers which are used for argument-passing should have lower
+ priority than registers not used for arguments. The priority
+ within the argument-registers should decrease as the frequency
+ of usage as argument increases (typically the register for the first
+ argument is used most frequently, etc.).
+@end itemize
+
+@end table
+
+Note that for the array @code{zmax regsize[]} the same comments mentioned
+in the section on data types regarding initialization apply.
+
+
+@subsection Functions
+
+The following functions have to be implemented by the code generator.
+There may be optional additional functions described in other sections.
+
+@table @code
+@item int init_cg(void);
+ This function is called after the commandline arguments are parsed.
+ It can set up certain internal data, etc. The arrays regarding the
+ data types and the register set can be set up at this point rather
+ than with a static initialization, however the arrays regarding the
+ commandline options have to be static initialized.
+ The results of the commandline options are available at this point.
+
+ If something goes wrong, 0 has to be returned, otherwise 1.
+
+@item void cleanup_cg(FILE *f);
+ This function is called before the compiler exits. @code{f} is the output
+ file which must be checked against 0 before using.
+
+@item int freturn(struct Typ *t);
+ This function has to return the number of the register return
+ values of type @code{t} are passed in. If the type is not passed in a
+ register, 0 must be returned. Usually the decision can be made
+ only considering @code{t->flags}, ignoring the full type
+ (@pxref{compositetypes}).
+
+@item int regok(int r, int t, int mode);
+ Check whether the type t can be stored in register @code{r} and whether
+ the usual operations (for this type) can be generated. Return 0, if not.
+
+ If @code{t} is a pointer and @code{mode==0} the register only has to be
+ able to store the pointer and do arithmetic, but if @code{mode!=0} it has
+ to be able to dereference the pointer.
+
+ @code{mode==-1} is used with context-sensitive register-allocation
+ (@pxref{targetralloc}). If the backend does not support it, this case
+ can be handled equivalent to @code{mode==0}.
+
+ If @code{t==0} return whether the register can be used to store condition codes.
+ This is only relevant if @code{multiple_ccs} is set to 1.
+
+@item int dangerous_IC(struct IC *p);
+ Check if this IC can raise exceptions or is otherwise dangerous.
+ Movement of ICs which are dangerous is restricted to preserve the
+ semantics of the program.
+
+ Typical dangerous ICs are divisions or pointer dereferencing. On certain
+ targets floating point or even signed integer arithmetic can raise
+ exceptions, too.
+
+@item int must_convert(int from,int to,int const_expr);
+ Check if code must be generated to convert from type @code{from} to
+ type @code{to}. E.g. on
+ many machines certain types have identical representations (integers
+ of the same size or pointers and integers of the same size).
+
+ If @code{const_expr != 0} return if a conversion was necessary in
+ a constant expression.
+
+ For example, a machine may have identical
+ pointers and integers, but different sets of registers (one set
+ supports integer operations and the other pointer operations).
+ Therefore, @code{must_convert()} would return 1 (we need a
+ @code{CONVERT} IC to move the value from one register set to the
+ other).
+
+ This would imply that @command{vbcc} would not allow a
+ cast from a pointer to an integer or vice-versa in constant expressions
+ (as it will not
+ generate code for static initializations). However, in this
+ case, a static initialization would be ok as the representation is
+ identical and registers are not involved. Therefore, the backend
+ can return 1 if @code{const_expr == 0} and 0 otherwise.
+
+@item int shortcut(int code, int t);
+ In C no operations are done with chars and shorts because of integral
+ promotion. However sometimes @command{vbcc} might see that an operation could
+ be performed with the short types yielding the same result.
+
+ Before generating such an instruction with short types @command{vbcc} will ask
+ the code generator by calling @code{shortcut()} to find out whether it
+ should do so. Return true iff it is a win to perform the operation
+ @code{code} with
+ type @code{t} rather than promoting the operands and using e.g. @code{int}.
+
+@item void gen_code(FILE *f, struct IC *p, struct Var *v, zmax offset);
+ This function has to emit code for a function to stream @code{f}.
+ @code{v} is the function being generated,
+ @code{p} is a pointer to the list of ICs, that has to be converted.
+ @code{offset} is the space needed for local variables in bytes.
+
+ This function has to take care that only scratchregisters are destroyed
+ by this function. The array @code{regused} contains information about the
+ registers that have been used by @command{vbcc} in this function. However if the
+ code generator uses additional registers it has to take care of them,
+ too.
+
+ The @code{regs[]} and @code{regused[]} arrays may be overwritten by @code{gen_code()} as well
+ as parts of the list of ICs. However the list of ICs must still be a
+ valid list of ICs after @code{gen_code()} returns.
+
+ All assembly output should be generated using the available
+ @code{emit} functions. These functions are able to keep several
+ lines of assembly output buffered and allow peephole optimizations
+ on assembly output (@pxref{asmpeephole}).
+
+@item void gen_ds(FILE *f, zmax size, struct Typ *t);
+ Has to emit output that generates @code{size} bytes of type @code{t}
+ initialized with proper 0.
+
+ @code{t} is a pointer to a @code{struct Typ} which contains the precise type of
+ the variable. On machines where every type can be initialized to 0
+ by setting all bits to zero, the type does not matter. Otherwise
+ @pxref{compositetypes}.
+
+ All assembly output should be generated using the available
+ @code{emit} functions.
+
+
+@item void gen_align(FILE *f, zmax align);
+ Has to emit output that ensures the following data to be aligned to
+ @code{align} bytes.
+
+ All assembly output should be generated using the available
+ @code{emit} functions.
+
+@item void gen_var_head(FILE *f, struct Var *v);
+ Has to print the head of a static or external variable @code{v}. This includes
+ the label and necessary information for external linkage etc.
+
+ Typically variables will be generated by a call to @code{gen_align()} followed
+ by @code{gen_var_head()} and (a series of) calls to @code{gen_dc()} and/or @code{gen_ds()}. It may be necessary to keep track of the information passed
+ to @code{gen_var_head()}.
+
+ All assembly output should be generated using the available
+ @code{emit} functions.
+
+@item void gen_dc(FILE *f, int t, struct const_list *p);
+ Emit initialized data. @code{t} is the basic type that has to be
+ emitted. @code{p} points to a @code{struct const_list}.
+
+ If @code{p->tree != 0} then @code{p->tree->o} is a @code{struct obj}
+ which has to be emitted. This will usually be the address of a
+ variable of storage class static or unsigned, possibly with an offset
+ added (@pxref{operands} for further details).
+
+ if @code{p->tree == 0} then @code{p->val} is a @code{union atyps}
+ which contains (in the member corresponding to @code{t}) the constant
+ value to be emitted.
+
+ All assembly output should be generated using the available
+ @code{emit} functions.
+
+@item void init_db(FILE *f);
+ If debug-information is requested, this functions is called after
+ @code{init_cg()}, but before any code is generated.
+ See also @ref{debuginfo}.
+
+@item void cleanup_db(FILE *f);
+ If debug-information is requested, this functions is called prior to
+ @code{cleanup_cg()}.
+ See also @ref{debuginfo}.
+
+@end table
+
+@section Available Support Functions, Macros and Variables
+
+This section lists a series of general variables, macros and functions
+which are available to the backend and may prove useful. Note that there
+may be additional support specific to certain features which will be mentioned
+at appropriate sections in this manual.
+
+@table @code
+@item MAXINT
+A constant for the largest target integer type (@code{zmax}). It is outside
+the range of the other types and cannot be accessed by an application
+(although there will usually be an accessible type with the same
+representation).
+
+@item MAX_TYPE
+The type number of the last type.
+
+@item NQ
+A mask. @code{t & NQ} will delete all type-qualifiers of a type.
+
+@item NU
+A mask. @code{t & NU} will delete all type-qualifiers but
+@code{UNSIGNED} of a type.
+
+@item q1typ(p)
+Yields the type of the first source operand of IC @code{p}.
+Undefined if the operand is not used!
+
+@item q2typ(p)
+Yields the type of the second source operand of IC @code{p}.
+Undefined if the operand is not used!
+
+@item ztyp(p)
+Yields the type of the destination operand of IC @code{p}.
+Undefined if the operand is not used!
+
+@item iclabel(p)
+Returns the label of an IC. Only defined if @code{p->code} is
+@code{LABEL, BEQ, BNE, BLT, BGT, BLE} or @code{BGE}.
+
+@item opsize(p)
+Returns the size of the operand of an @code{ASSIGN} or @code{PUSH}
+IC as @code{zmax}.
+
+@item pushsize(p)
+Returns the stack-adjustment value of a @code{PUSH} IC as @code{zmax}.
+It is always greater or equal than @code{opsize(p)}.
+
+@item pushedargsize(p)
+Returns the space occupied by arguments passed on the stack
+as parameters for a function call. Only valid for @code{CALL} ICs.
+
+@item isstatic(sc)
+Tests whether the storage-class @code{sc} denotes a variable with
+static storage and no external linkage.
+
+@item isextern(sc)
+Tests whether the storage-class @code{sc} denotes a variable with
+static storage and external linkage.
+
+@item isauto(sc)
+Tests whether the storage-class @code{sc} denotes a variable with
+automatic storage-duration.
+
+@item t_min(t)
+@itemx t_max(t)
+These macros yield the smallest and largest representable value of any
+target integer type, e.g. @code{t_min(INT)} or @code{t_max(UNSIGNED|LONG)}.
+
+@item ISPOINTER(t)
+@item ISINT(t)
+@item ISFLOAT(t)
+@item ISFUNC(t)
+@item ISSTRUCT(t)
+@item ISUNION(t)
+@item ISARRAY(t)
+@item ISSCALAR(t)
+@itemx ISARITH(t)
+These macros test whether the simple type @code{t} is a pointer type,
+an integral type, a floating point type, a function, a structure type,
+a union type, an array type, a scalar (integer, floating point or pointer)
+and an arithmetic type (integer or floating point), respectively.
+
+@item int label;
+The number of the last label used so far. For a new label number, use
+@code{++label}.
+
+@item zmax falign(struct Typ *t);
+This function returns the alignment of a full type. Contrary to the
+@code{align[]} array provided by the backend (which is used by this function),
+it will yield correct values for composite types like structures and arrays.
+
+@item zmax szof(struct Typ *t);
+This function returns the size in bytes of a full type. Contrary to the
+@code{sizetab[]} array provided by the backend (which is used by this function),
+it will yield correct values for composite types like structures and arrays.
+
+@item void *mymalloc(size_t size);
+@item void *myrealloc(void *p,size_t size);
+@itemx void myfree(void *p);
+Memory allocation functions similar to @code{malloc(), realloc()} and
+@code{free}. They will automatically
+clean up the exit in the case an allocation fails. Also, some debug
+possibilities are available.
+
+@item void emit(FILE *f,const char *fmt,...);
+@item void emit_char(FILE *f,int c) ;
+@item void emitval(FILE *f,union atyps *p,int t);
+@item void emitzm(FILE *f,zmax x);
+@item void emitzum(FILE *f,zumax x);
+All output produced by the backend should be produced using these
+functions. @code{emit()} uses a format like @code{printf()},
+@code{emitval(), emitzm()} and @code{emitzum()} are suitable to
+output target integers as decimal text. Currently emitting floating
+point constants has to be done by the backend.
+
+@item int is_const(struct Typ *);
+Tests whether a full type is constant (e.g. to decide whether it can be
+put into a ROM section).
+
+@item int is_volatile_obj(struct obj *);
+@itemx int is_volatile_ic(struct IC *);
+Tests whether an object or IC is volatile. Only of interest to the backend
+in rare cases.
+
+@item int switch_IC(struct IC *p);
+This function checks whether @code{p->q2} and @code{p->z} use the
+same register (including register pairs). If they do, it will try
+to swap @code{p->q1} and @code{p->q2} (only possible if the IC is
+commutative). It is often possible to generate
+better code if @code{p->q2} and @code{p->z} do not collide. Note
+however, that it is not always possible to eliminate a conflict and
+the code generator still has to be able to handle such a case.
+
+The function returns 0 if no modification took place and non-zero if
+the IC has been modified.
+
+@item union atyps gval;
+@item void eval_const(union atyps *p,int t);
+@itemx void insert_const(union atyps *p,int t);
+For every target data type there is a corresponding global variable
+of that type, e.g. @code{zchar vchar, zuchar vuchar, zmax vmax} etc.
+These two functions simplify handling of target data types by transferring
+between a @code{union atyps} and these variables.
+
+@code{eval_const()} reads the member of the union corresponding to the
+type @code{t} and converts it into all the global variables while
+@code{insert_const()} takes the global variable according to @code{t}
+and puts it into the appropriate member of the @code{union atyps}.
+
+The global variable @code{gval} may be used as a temporary
+@code{union atyps} by the backend.
+
+@item void printzm(FILE *f,zmax x);
+@item void printzum(FILE *f,zumax x) ;
+@item void printval(FILE *f,union atyps *p,int t);
+@item void printtype(FILE *o,struct Typ *p);
+@item void printobj(FILE *f,struct obj *p,int t);
+@item void printic(FILE *f,struct IC *p);
+@itemx void printiclist(FILE *f,struct IC *first);
+This is a series of functions which print a more or less human
+readable version of the corresponding type to a stream. These functions
+are to be used only for debugging purposes, not for generating code.
+Also, the arguments must contain valid values.
+
+@item bvtype
+@itemx BVSIZE(n)
+@command{vbcc} provides macros and functions for handling bit-vectors
+which may also be used by the backend. @code{bvtype} is the basic type
+to create bit-vectors of. @code{BVSIZE(n)} yields the number of
+bytes needed to implement a bit-vector with @code{n} elements.
+@example
+bvtype *mybv = mymalloc(BVSIZE(n));
+@end example
+
+@item BSET(bv,n)
+@item BCLR(bv,n)
+@itemx BTST(bv,n)
+Macros which set, clear and test the @code{n}-th bit in bit-vector @code{bv}.
+
+@item void bvunite(bvtype *dest,bvtype *src,size_t len);
+@item void bvintersect(bvtype *dest,bvtype *src,size_t len);
+@itemx void bvdiff(bvtype *dest,bvtype *src,size_t len);
+These functions calculate the union, intersection and difference of two
+bit-vectors. @code{dest} is the first operand as well as the destination.
+@code{len} is the length of the bit-vectors in bytes, not in bits.
+
+@item void bvcopy(bvtype *dest,bvtype *src,size_t len);
+@item void bvclear(bvtype *dest,size_t len);
+@itemx void bvsetall(bvtype *dest,size_t len);
+These functions copy, clear and fill bit-vectors.
+
+@item int bvcmp(bvtype *bv1,bvtype *bv2,size_t len);
+@itemx int bvdointersect(bvtype *bv1,bvtype *bv2,size_t len);
+These functions test whether two bit-vectors are equal or
+have a non-empty intersection, respectively. The do not modify the
+bit-vectors.
+
+@end table
+
+
+@section Hints for common Optimizations
+
+While it is no easy job to produce a stable code generator for a new target
+architecture, there is a huge difference between a simple backend and
+a highly optimized code generator which produces small and efficient
+high quality code. Although @command{vbcc} is able to do a lot machine
+independent global optimizations for every target automatically, it is still
+common for an optimized backend to produce code up to twice as fast on
+average as a simple one.
+
+Sometimes, a simple backend is sufficient and the
+work required to produce high-quality code is not worthwhile. However,
+this section lists a series of common backend optimizations which are
+often done in case that good code-quality is desired. Note that neither are
+all of these optimizations applicable (without modifications or at all)
+to all architectures nor is
+this an exhaustive list. It is just a list of recommendations to consider.
+You have to make sure that the optimization is safe and beneficial for
+the architecture you are targetting.
+
+
+@subsection Instruction Combining
+
+While ICs are often a bit more powerful than instructions of a typical
+microprocessor, sometimes several of them can be implemented by a single
+instruction or more efficient code can be generated when looking at a
+few of them rather than at each one separately.
+
+In the simple case, this can be done by looking at the current IC,
+deciding whether it is a candidate for combining and then test whether
+the next IC (or ICs) are suitable for combining. This is relatively easy
+to perform, however some care has to be taken to verify that the
+combination is indeed legal (e.g. what happens if the first IC modifies
+a value which is used by the following IC).
+
+A more sophisticated implementation might look at a larger sequence of
+instructions to find more possibilities for optimization. Detecting
+whether the combination is legal becomes much more difficult then.
+
+Sometimes the IC migh compute a temporary result which would be eliminated by
+the complex machine instruction. Then it is necessary to verify that it
+was indeed a temporary result which is not used anywhere else. As long as
+the result is in a register, this can be done by checking for a
+@code{FREEREG} IC.
+
+Examples for instruction combining are multiply-and-add or bit-test
+instructions which are available on many architectures.
+Special cases are complex
+addressing modes and instructions which can automatically set condition
+codes which are described in the following sections.
+
+
+@node addressingmodes
+@subsection Addressing Modes
+
+The intermediate code generated by vbcc does not use any
+addressing-modes a target might offer. Therefore the code generator
+must find a way to combine several statements if it wants to make use
+of these modes. E.g. on the m68k the intermediate code
+@example
+ ADDI2P int a0,#20->a1
+ ASSIG int #10->(a1)
+ FREEREG a1
+@end example
+could be translated to
+@example
+ move.l #10,20(a0)
+@end example
+(notice the @code{FREEREG} which is important).
+
+To aid in this there is a pointer to a @code{struct AddressingMode} in every
+@code{struct obj}. A code generator could e.g. do a pass over the intermediate
+code, find possible uses for addressing-modes, allocate a
+@code{struct AddressingMode} and store a pointer in the
+@code{struct obj}, effectively replacing the obj.
+
+If the code generator supports extended addressing-modes, you have to think
+of a way to represent them and define the @code{struct AddressingMode} so that
+all modes can be stored in it. The machine independent part of
+@command{vbcc} will
+not use these modes, so your code generator has to find a way to combine
+several statements to make use of these modes.
+
+A possible implementation of a structure to handle the addressing mode
+described above as well as a register-indirect mode could be:
+@example
+#define IMM_IND 1
+#define REG_IND 2
+
+struct AddressingMode @{
+ int flags; /* either IMM_IND or REG_IND */
+ int base; /* base register */
+ zmax offset; /* offset in case of IMM_IND */
+ int idx; /* index register in case of REG_IND */
+@}
+@end example
+
+When the code generator is done that pointer in every @code{struct obj} must
+either be zero or point to a @code{mymalloc}ed @code{struct AddressingMode}
+which will be free'd by @command{vbcc}.
+
+Following is an example of a function which traverses a list of ICs and
+inserts addressing modes with constant offsets where possible.
+@example
+/* search for possible addressing-modes */
+static void find_addr_modes(struct IC *p)
+@{
+ int c,c2,r;
+ struct IC *p2;
+ struct AddressingMode *am;
+
+ for(;p;p=p->next)@{
+ c=p->code;
+
+ if(IMM_IND&&(c==ADDI2P||c==SUBIFP)&&
+ isreg(z)&&(p->q2.flags&(KONST|DREFOBJ))==KONST)@{
+ /* we have found addi2p q1,#const->reg */
+ int base;zmax of;struct obj *o;
+
+ eval_const(&p->q2.val,p->typf);
+ /* handle sub instead of add */
+ if(c==SUBIFP)
+ of=zmsub(l2zm(0L),vmax);
+ else
+ of=vmax;
+
+ /* Is the offset suitable for an addressing mode? */
+ if(ISVALID_OFFSET(vmax))@{
+ r=p->z.reg;
+ /* If q1 is a register, we use it as base-register,
+ otherwise q1 is loaded in the temporary register
+ and this one used as base register. */
+ if(isreg(q1))
+ base=p->q1.reg;
+ else
+ base=r;
+
+ o=0;
+ /* Now search the following instructions. */
+ for(p2=p->next;p2;p2=p2->next)@{
+ c2=p2->code;
+
+ /* End of a basic block. We have to abort. */
+ if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
+
+ /* The temporary register is used. We have to abort. */
+ 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)@{
+ /* See, if we find a valid use (dereference) of the
+ temporary register. */
+ if(!p->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&
+ p2->q1.reg==r)@{
+ if(o) break;
+ o=&p2->q1;
+ @}
+ if(!p->q1.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&
+ p2->q2.reg==r)@{
+ if(o) break;
+ o=&p2->q2;
+ @}
+ if(!p->q1.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)@{
+ /* The value of the temporary register is not used any more
+ (either due to FREEREG or because it is overwritten).
+ If we have found exactly one dereference, we can use
+ a target addressing mode. */
+ if(o)@{
+ o->am=am=mymalloc(sizeof(*am));
+ am->flags=IMM_IND;
+ am->base=base;
+ am->offset=zm2l(of);
+ if(isreg(q1))@{
+ /* The base already was in a register. We can
+ eliminate the ADDI2P IC. */
+ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
+ @}else@{
+ /* The base was not in a register.
+ We have to load it . */
+ 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;
+ @}
+ @}
+ @}
+ @}
+ @}
+@}
+@end example
+
+@subsection Implicit setting of Condition Codes
+
+Many architectures have instruction that automatically set the
+condition codes according to the computed result. For these architectures
+it is generally a good idea to keep track of the setting of condition
+codes (e.g. if they reflect the state of some object or register). A
+subsequent @code{TEST} or @code{COMPARE} instruction can then often be
+eliminated.
+
+Care has to be taken to delete this information if either the condition
+codes may be modified or the object they represent is modified. Also,
+this optimization is usually hard to do across labels.
+
+Some architectures provide versions of instructions which set condition
+codes as well as versions which do not. This obviously enable more
+optimizations, but it is more difficult to make use of this. One
+possibility is to search the list of ICs backwards starting from
+every suitable @code{TEST} or @code{COMPARE} instruction. If an IC
+is found which computes the tested object, the IC can be marked
+(extended ICs can be used for marking, @pxref{extic}).
+
+
+@node regparm
+@subsection Register Parameters
+
+While passing of arguments to functions can be done by pushing them on
+the stack, it is often more efficient to pass them in registers if the
+architecture has enough registers.
+
+To use register parameters you have to add the line
+@example
+#define HAVE_REGPARMS 1
+@end example
+to @file{machine.h} and define a
+@example
+ struct reg_handle @{...@}
+@end example
+This struct is used by the compiler to find out which register should be used
+to pass an argument. @file{machine.c} has to contain an initialized
+variable
+@example
+ struct reg_handle empty_reg_handle;
+@end example
+which represents the default state, and a function
+@example
+ int reg_parm(struct reg_handle *, struct Typ *, int vararg, struct Typ *);
+@end example
+which returns the number of the register the next argument will be
+passed in (or 0 if the argument is not passed in a register). Also,
+it has to update the reg_handle in a way that successive calls to
+@code{reg_parm()}
+yield the correct register for every argument.
+
+@code{vararg} is different from zero, if the argument is part of the variable
+arguments of a function accepting a variable number of arguments.
+
+It is also possible to return a negative number @code{x}. In this case,
+the argument will be passed in register number @code{-x}, but also a
+stack-slot will be reserved for this argument (i.e. a @code{PUSH} IC
+without an operand will be generated). If @option{-double-push} is
+specified, the argument will also be written to the stack-slot (i.e.
+it will be passed twice, in a register and on the stack).
+
+@node regpairs
+@subsection Register Pairs
+
+Often, there are types which cannot be stored in a single machine register,
+but it may be more efficient to store them in two registers rather than
+in memory. Typical examples are integers which are bigger than the
+register size or architectures which combine two floating point registers
+into one register of double precision.
+
+To make use of register pairs, the line
+@example
+#define HAVE_REGPAIRS 1
+@end example
+has to be added to @file{machine.h}. The register pairs are declared
+as normal registers (each register pair counts as an own register and
+@code{MAXR} has to be adjusted). Usually only adjacent registers are
+declared as register pairs. Note that @code{regscratch} must be identical
+for both registers of a pair.
+
+Now the function
+@example
+int reg_pair(int r,struct rpair *p);
+@end example
+must be implemented. If register @code{r} is a register pair, the function
+has to set @code{p->r1} and @code{p->r2} to the first and second register
+which comprise the pair and return 1. Otherwise, zero has to be returned.
+
+
+@subsection Elimination of Frame-Pointer
+
+Local variables on the stack can usually be addressed via a so-called
+frame-pointer which is set set to current stack-pointer at the entry
+of a function. However, in the code generated by @command{vbcc}, the
+difference between the stack-pointer and the frame-pointer is fixed
+at any instruction.
+
+Therefore it is possible to keep track of this offset (by counting the
+bytes every time code for pushing or popping from the stack is generated).
+Using this offset, local variables can perhaps be addressed using the
+stack-pointer directly. Benefit would be smaller function entry/exit code
+as well as an additional free register which can be used for other
+purposes.
+
+Note that only few debuggers can handle such a situation.
+
+@subsection Delayed popping of Stack-Slots
+
+In most ABIs arguments which are pushed on the stack are not popped
+by the called function but the caller pops them by adjusting the stack
+after the callee returns (otherwise variable arguments would be hard
+to implement).
+
+If several functions are called in sequence, it is not necessary to
+adjust the stack after each call but the arguments for several calls
+can be popped at once. It can be implemented by keeping track of the
+size to be popped and deferring popping to a point where it has to be
+done (e.g. a label or a branch). Also, in the case of nested calls,
+care has to be taken to pop arguments at the right time.
+
+Note that this usually saves code-size and execution time but will
+increase stack-usage. Therefore, it may not be advisable for small systems.
+
+@subsection Optimized Return
+
+Return instructions are not explicitly represented in ICs. Rather, they are
+branches to a label which is the last IC in the list (except possible
+@code{FREEREG}s).
+
+It is possible to generate working code by translating
+these branches normally, but directly inserting the function exit code
+instead of a branch is often faster. It is most recommendable if the
+exit code is small (e.g. no registers have to be restored and no
+stack-frame removed).
+
+Another common possibility for optimization is a function call as the last
+IC. If return addresses are pushed on the stack and no function exit code
+is needed, it is usually possible to generate a jump-instruction, i.e.
+replace
+@example
+ call somefunc
+ ret
+@end example
+by
+@example
+ jmp somefunc
+@end example
+
+@node jumptables
+@subsection Jump Tables
+
+An important optimization is the creation of jump-tables for a series of
+comparisons with constants. Such series are usually created by a C
+@code{switch} construct, but vbcc can also recognize some of them if they
+are created through @code{if}-sequences.
+
+@file{supp.c} provides the function @code{calc_case_table(<IC>,<density>)}
+to check for constructs that can be replaced by a jump table. The arguments
+are the start IC to look for (it has to be a @code{COMPARE}-IC with a
+constant as @code{q2}) and a minimal density. The density reflects the
+number of cases that are used divided by the range of cases. If the density
+is high, vbcc will use jump-tables only for sequences that have few unused
+cases inside. If the case tables occupy multiple ranges, vbcc is able to split
+them up and create multiple jump-tables.
+
+@code{calc_case_table} returns a pointer to a @code{struct case_table} with
+the following content:
+
+@table @code
+@item num
+The number of cases.
+
+@item typf
+The type of the case IDs.
+
+@item next_ic
+The first IC after the list of ICs that can be replaced by the jump-table.
+
+@item density
+The case density.
+
+@item vals
+The values of the case IDs (array containing @code{num} entries).
+
+@item labels
+The labels of the code corresponding to the case IDs
+(array containing @code{num} entries).
+
+@item min
+The lowest case ID.
+
+@item max
+The highest case ID.
+
+@item diff
+@code{max-min}.
+
+@end table
+
+If the backend decides to emit a jump-table, it has to generate code that
+will check that the control expression lies between @code{min} and @code{max}.
+If not, the jump-table must not be executed. Code for the computed jump
+must then be generated. The actual table can be emitted using
+@code{emit_jump_table()}. Processing can then continue with @code{next_ic}.
+
+@node targetralloc
+@subsection Context-sensitive Register-Allocation
+
+The @code{regok()} function is only a simple means of telling the
+register allocator which registers to use. It works fairly well with
+orthogonal register and instruction sets. However, it does not really
+care about the operations performed and it allocates variables to registers
+only according to their type, not according to the operations performed.
+
+Some architectures provide different kinds of registers which are able to
+store a type, but not all of them are able to perform all operations or some
+operations are more expensive with some registers. To do good register
+allocation for these systems, the operations which are used on variables
+have to be considered.
+
+If the backend wants to support this kind of register allocation, it has
+to define @code{HAVE_TARGET_RALLOC} and provide the following functions
+or macros:
+
+@table @code
+@item int cost_move_reg(int x,int y);
+The cost of copying register @code{x} to register @code{y}.
+@item int cost_load_reg(int r,struct Var *v);
+The cost of loading register @code{r} from variable @code{v}.
+@item int cost_save_reg(int r,struct Var *v);
+The cost of storing register @code{r} into variable @code{v}.
+@item int cost_pushpop_reg(int r);
+The cost of storing register @code{r} during function prologue and
+restoring it in the epilogue.
+@item int cost_savings(struct IC *p,int r,struct obj *o);
+Estimate the savings which would be obtained if the object @code{o}
+in IC @code{p} would be assigned to register @code{r} (in this IC). If the
+backend was not able
+to emit code in this case, @code{INT_MIN} must be returned.
+
+If @code{(o->flags & VKONST) != 0}, the register allocator is thinking
+about putting a constant (or address of a static variable) in a register.
+In this case, the real object which would be put in a register is found
+in @code{o->v->cobj}.
+@end table
+
+The unit of the costs can be chosen by the backend, but should be some
+reasonable small values.
+
+If @code{regok()} is called with a third parameter of -1, it is possible
+to return non-zero for a register which cannot perform all operations.
+The register allocator will call @code{cost_savings()} and returning
+@code{INT_MIN} can be used to prevent this register from being allocated,
+if the register is not suitable for a certain operation.
+
+
+@node regsmodified
+@subsection Inter-procedural Register-Allocation
+
+To support inter-procedural register allocation, the backend must tell the
+optimizer which registers are used by a function. As the backend might use
+some registers internally, the frontend can not know this.
+
+Apart from defining @code{HAVE_REGS_MODIFIED} in @file{machine.h}, the
+backend has to mark all registers that are modified in the bitfield
+@code{regs_modified}. A register can be marked with
+@code{BSET(regs_modified,<reg>)}. For a call IC, the function @code{calc_regs()}
+(from @file{supp.h}) can be called to mark the registers used by a call IC.
+It will return 1 if it was able to determine all registers used by this IC.
+
+If the register usage could be determined for the entire function, the
+backend can set the bit @code{ALL_REGS} in the fi-member of the function
+variable (@code{v->fi->flags|=ALL_REGS;}).
+
+
+@subsection Conditional Instructions
+
+FIXME: To be written.
+
+@node extic
+@subsection Extended ICs
+
+If the backend defines @code{HACE_EXT_IC}, it has to define a
+@code{struct ext_ic} in @file{machine.h}. This structure will be added
+to each IC and can be used by the backend for private use.
+
+@node asmpeephole
+@subsection Peephole Optimizations on Assembly Output
+
+Some optimizations are easier to do on the generated assembly code rather
+than doing them before emitting code. Therefore it is possible to do
+peephole optimizations on the emitted code before it is really
+written to a file.
+
+@code{EMIT_BUF_DEPTH} lines will be stored in a ring buffer and are available
+to examination and modification by a function @code{emit_peephole()}. The
+actual assembly output is stored in @code{emit_buffer}, the index of
+the first line to be output in @code{emit_f} and the index of the last one
+in @code{emit_l} (note that you have to calculate modulo @code{EMIT_BUF_DEPTH}
+- it is a ring buffer).
+
+The output may be modified in memory and the first line may be removed
+using @code{remove_asm()}. If a modification took place, a non-zero value
+has to be returned (0 otherwise). The following example code would combine
+two consecutive additions to the same register:
+@example
+int emit_peephole(void)
+@{
+ int entries,i,r1,r2;
+ long x,y;
+ /* pointer to the lines in order of output */
+ char *asmline[EMIT_BUF_DEPTH];
+ i=emit_l;
+ /* compute number of entries in ring buffer */
+ if(emit_f==0)
+ entries=i-emit_f+1;
+ else
+ entries=EMIT_BUF_DEPTH;
+ /* the first line */
+ asmline[0]=emit_buffer[i];
+ if(entries>=2)@{
+ /* we have at least two line sin the buffer */
+ /* calculate the next line (modulo EMIT_BUF_DEPTH) */
+ i--;
+ if(i<0) i=EMIT_BUF_DEPTH-1;
+ asmline[1]=emit_buffer[i];
+ if(sscanf(asmline[0],"\tadd\tR%d,#%ld",&r1,&x)==2&&
+ sscanf(asmline[1],"\tadd\tR%d,#%ld",&r2,&y)==2&&
+ r1==r2)@{
+ sprintf(asmline[1],"\tadd\tR%d,#%ld\n",r1,x+y);
+ remove_asm();
+ return 1;
+ @}
+ @}
+ return 0;
+@}
+@end example
+
+Be very careful when doing such optimizations. Only perform optimizations
+which are really legal. Especially assembly code often has side effects
+like setting of flags.
+
+Depending on command line flags inline assembly code may or may not be
+passed through this peephole optimizer. By default, it will be done,
+enabling optimizations between generated code and inline assembly.
+
+
+@node markeffics
+@subsection Marking of efficient ICs
+
+If the backend sets @code{HAVE_EFF_ICS} in @file{machine.h}, it has to
+provide a function @code{void mark_eff_ics(void)}. This function will be
+called (possibly multiple times) by the frontend. The function has to set
+or clear the bit @code{EFF_IC} in the member @code{flags} of every IC.
+
+The flag should be set when the operation is in a context that suggests
+it will translate to efficient machine code. The optimizer will transform
+this IC less aggressively.
+
+As this is all happens before register allocation, the decision is of a very
+heuristic nature.
+
+@subsection Function entry/exit Code
+
+At entry and exit of function, there is usually some code to set up
+the new environment for this function. For example, registers will
+have to be saved/restored, a frame pointer may be set up and a stack
+frame will be created. It is generally worthwile to optimize this
+entry/exit code. For example, if no registers need to be saved and no
+local variables are used on the stack, it may not be necessary to
+create a stack frame.
+
+The exact possibilities for optimization depend on the architecture and the
+ABI.
+
+
+@subsection Multiplication/division with Constants
+
+Many architectures do not provide instruction for multiplication,
+division or modulo calculation. And on most architectures providing
+such instructions they are rather slow. Therefore, it is recommended
+to emit cheaper instructions, if possible.
+
+Usually, this can only be done if one operand of the operation is a
+constant. Multiplications may be replaced by a series of shift and
+add instructions, for example. The simplest and most important cases
+to replace are multiplication, division and modulo with a power of two.
+Multiplication by x can be replaced by a left shift of log2(x),
+unsigned division of x can be replaced by logical right shift of log2(x)
+and unsigned modulo by x can be replaced by anding with x-1.
+
+Note that
+signed division and modulo can usually not be replaced that simple because
+most division instructions give different results for some negative
+values. An additional adjustment would be necessary to get correct results.
+Whether this is still an improvement, depends on the architecture details.
+
+The following function can be used to test whether a value is a power of
+two:
+@example
+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;
+@}
+@end example
+
+@subsection Block copying
+
+There are many cases of copying of larger data. For the backend, those
+will mostly be used in @code{PUSH} and @code{ASSIGN} ICs. It is very
+important to implement those as efficient as possible.
+
+Some things to consider:
+
+@itemize @minus
+@item When alignment is known, use word-copy instead of byte-copy.
+
+@item Copy small blocks by a series of copy instructions.
+
+@item For larger blocks, loading addresses in registers may help.
+
+@item For large blocks, use a loop. Implement it efficiently and try to
+unroll the loop a few times.
+
+@item For very large blocks, calling a library function may be useful. While
+this creates some overhead, the function can dynamically check the alignment
+or perhaps even use special hardware, if available.
+
+@item Set @code{INLINEMEMCOPY} to reasonable values. Set it to a very high
+value if you implement very good block copying.
+
+@end itemize
+
+
+@subsection Optimized Library Functions
+
+FIXME: To be written.
+
+@subsection Instruction Scheduler
+
+FIXME: To be written.
+
+
+@section Hints for common Extensions
+
+This section lists some common extensions to the C language which are
+often very helpful when using a compiler in practice. Depending on the
+kind of target system they may range from nobody-really-cares to
+absolutely essential. For example, consider the ability to specify the section
+within an object file a variable or function should be placed in. This is
+rarely of any interest when targeting a Unix-like operating system. On
+a stand-alone embedded system, however, it may be absolutely necessary.
+
+Therefore, consider this list as a recommendation of ideas that might
+be helpful.
+
+@subsection Inline Assembly
+
+The possibility to insert assembly code into C source is very handy in
+many cases. It can be used in headers to implement specially optimized
+versions of time-critical library routines or enable access to CPU
+features which are not otherwise accessible by normal C constructs.
+
+In general, almost all work is done by the frontend and only a few lines
+have to be inserted in the backend to make it work. Therefore, it is
+recommended to always support this important feature.
+
+Everything that has to be done is to check a certain condition when code for
+a @code{CALL} IC is generated. Instead of emitting a normal call instruction,
+call the @code{emit_inline_asm()} function:
+@example
+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");
+ @}
+@end example
+Note that argument-passing, adjusting the stack after a @code{CALL} IC etc.
+is not affected. Only the actual emitting of call code is changed in the
+case of inline assembly.
+
+@subsection -speed/-size
+
+Often it is desired to generate code which runs as fast as possible
+but sometimes small code is needed. The command line options
+@option{-speed} and @option{-size} are provided for the user to specify
+his intention.
+
+These options already may change the intermediate code produced by the
+frontend, but the backend should also respect these switches, if possible.
+The variables @code{optspeed} and @code{optsize} can be queried to see
+if these options were specified.
+
+If e.g. @code{optspeed} was specified, the backend should choose faster
+code-sequences, even if code-size is increased significantly. Vice-versa,
+if @code{optsize} is specified, it should always choose the shorter code
+if there is a trade-off between size and speed.
+
+Typical cases for such tradeoffs are for example, block-copy (@code{ASSIGN}
+and @code{PUSH}) ICs. Often it is possible to call a library function or
+generate a simple short loop for small code, but an unrolled inlined loop
+for fast code.
+
+@node targetmacros
+@subsection Target-specific Macros
+
+A backend is able to provide macro definitions which are automatically
+active. It is recommended to define macros which allow applications to
+query the target architecture and the selected chip (if possible).
+Also, it is recommended to provide internal macros for backend specific
+attributes using the @code{__attr()} and @code{__vattr()} attributes.
+
+The definition of these macros can be done in @code{init_cg()} (the
+results of command line parsing are available at this point). There is
+a variable
+@example
+char **target_macros;
+@end example
+which can be set to an array of pointers to strings which contain the
+macro definitions. The array has to be terminated by a null pointer and
+the syntax of the macro definitions is similar to the command line
+option @option{-D}:
+@example
+static char *marray[] = @{
+ "__TARGET_ARCH__",
+ "__section(x)=__vattr(\"section(\"#x\")\")",
+ 0
+@};
+...
+target_macros = marray;
+@end example
+
+@subsection stdarg.h
+
+FIXME: To be written.
+
+
+@subsection Section Specifiers
+
+Especially for embedded systems it can be very important to be able to
+place variables and functions in specific section to override default
+placement. This can relatively easily be done using variable attributes
+(@pxref{targetattributes}).
+
+
+@node targetattributes
+@subsection Target-specific Attributes
+
+There are two ways of adding target-specific attributes to variables and
+functions. A general way is the use of @code{__vattr()} which will add
+the string argument to the @code{vattr} member of the corresponding
+@code{struct Var}, separating it by a semi-colon. The backend can use
+this information by parsing the string. The frontend will just build
+the string, it will not interpret it. If a backend offers attributes
+using the @code{__vattr()} mechanism, it is recommended to provide
+target-specific macros (@pxref{targetmacros}) which expand to the
+appropriate @code{__vattr()}-syntax. Only these macros should be
+documented.
+
+A second way to specify attributes is enabled by adding
+@example
+#define HAVE_TARGET_PRAGMAS 1
+@end example
+to @file{machine.h} and adding an array
+@example
+char *g_attr_name[];
+@end example
+to @file{machine.c}. This array should point to the strings used
+for the attributes, terminated by a null-pointer, e.g.:
+@example
+char *g_attr_name[] = @{
+ "__far",
+ "__near",
+ "__interrupt",
+ 0
+@};
+@end example
+These attributes can be queried in the member
+@example
+unsigned long tattr;
+@end example
+of a @code{struct Var}. The first attribute is represented by bit 1, the
+second by bit 2 and so on. Using this mechanism, the frontend will check for
+redeclarations with different setting of attributes or multiple specification
+of attributes. However, only boolean attributes are possible. If parameters
+have to be specified, the @code{__vattr()}-mechanism has to be used.
+
+@node targetpragmas
+@subsection Target-specific @code{#pragma}s
+
+FIXME: To be written.
+
+@node exttypes
+@subsection Target-specific extended Types
+
+FIXME: To be written.
+
+@node tgtprintval
+@subsection Target-specific @code{printval}
+
+FIXME: To be written.
+
+@node debuginfo
+@subsection Debug Information
+
+Debug information which enables (source level) debugging of compiled
+programs is an important feature to improve the user-friendliness of a
+compiler. Depending on the object format and debugger used, the format
+and capabilities of debug information can vary widely. Therefore, it is
+the responsibility of each backend to generate debug information. However,
+for common debug standards there will be modules which can be used by
+the backends and will do most of the work. Currently there is one such
+module for the DWARF2 debug standard.
+
+The compiler frontend provides a variable @code{debug_info} which can
+be queried to test whether debug information is desired. Also, the
+functions @code{init_db()} and @code{cleanup_db()} are helpful.
+
+Each @code{struct Var} contains the members @code{char *dfilename} and
+@code{int dline} which specify the file and line number of the variable's
+definition. Also, every IC contains the members @code{char *file} and
+@code{int line} with the file name and line number this IC belongs to. Note
+however, that there may be ICs with @code{file == 0} - not all ICs can
+be assigned a certain code location. Also, ICs do not always have increasing
+line numbers and line numbers may repeat. Not all debuggers may be able
+to deal with this.
+
+@subsubsection DWARF2
+
+There is support for the DWARF2 debug standard which can be added to a backend
+rather easily. The following additions are necessary:
+
+@enumerate
+@item Add the line
+@example
+#include "dwarf2.c"
+@end example
+to @file{machine.c}.
+@item Add the following lines to @code{init_db()}:
+@example
+dwarf2_setup(sizetab[POINTER],
+ ".byte",
+ ".2byte",
+ ".4byte",
+ ".4byte",
+ labprefix,
+ idprefix,
+ ".section");
+dwarf2_print_comp_unit_header(f);
+@end example
+The arguments to @code{dwarf2_setup()} have the following meanings:
+@enumerate
+@item The size of an address on the target.
+@item An assembler directive to create one byte of initialized storage.
+@item An assembler directive to create two bytes of initialized storage
+ (without any padding for alignment).
+@item An assembler directive to create four bytes of initialized storage
+ (without any padding for alignment).
+@item An assembler directive to create initialized storage representing
+ a target address (without any padding for alignment).
+@item A prefix which is used for emitting numbered labels (or empty string).
+@item A prefix which is used for emitting external identifiers
+ (or empty string).
+@item An assembler directive to switch to a new named section.
+@end enumerate
+@item Add the line
+@example
+dwarf2_cleanup(f);
+@end example
+to @code{cleanup_db()}.
+@item Write the function
+@example
+static int dwarf2_regnumber(int r);
+@end example
+which
+ returns the DWARF2 regnumber for a @command{vbcc} register number.
+@item Write the function
+@example
+static zmax dwarf2_fboffset(struct Var *v);
+@end example
+ which returns the offset of variable @code{v} from the DWARF2
+ frame-pointer.
+@item Write the function
+@example
+static void dwarf2_print_frame_location(FILE *f,struct Var *v);
+@end example
+which prints a DWARF2 location of the frame pointer. It can use the
+function
+@example
+void dwarf2_print_location(FILE *f,struct obj *o);
+@end example
+to output the location. For example, if the frame pointer is a simple
+register, it might look like this:
+@example
+static void dwarf2_print_frame_location(FILE *f,struct Var *v)
+@{
+ struct obj o;
+ o.flags=REG;
+ o.reg=frame_pointer_register;
+ o.val.vmax=l2zm(0L);
+ o.v=0;
+ dwarf2_print_location(f,&o);
+@}
+@end example
+@item Before emitting code for an IC @code{p}, execute the code
+@example
+if(debug_info)
+ dwarf2_line_info(f,p);
+@end example
+@item After emitting code for a function @code{v}, a new numbered label
+ has to be emitted after the function code and the function
+@example
+void dwarf2_function(FILE *f,struct Var *v,int endlabel);
+@end example
+must be called.
+
+@end enumerate
+
+Note that the DWARF2 standard supports use of location lists which can be
+used to describe a variable whose location changes during the program (e.g.
+in a register for some time, then in memory and again in a register) as well
+as a moving frame pointer (very useful if no separate frame pointer is used
+but all local variables are accessed through a moving stack pointer).
+Unfortunately, none of the debuggers I have tried so far could handle these
+location lists. Therefore, the current DWARF2 module does not output
+location lists, but future version will probably offer them as an option.
+
+Without location lists, accessing local variables will only work with
+a fixed frame pointer and no register variables. Even with these restrictions,
+function parameters which are passed in registers will not be correctly
+displayed during the function entry code.
+
+@subsection Interrupt Handlers
+
+Especially for embedded systems, support for writing interrupt handlers in
+C is a common feature. Variable attributes (@pxref{targetattributes}) can
+be used to mark functions which are used as interrupt handlers.
+
+Typical changes which might be necessary for interrupt handlers are:
+@itemize @minus
+@item Using a different return instruction.
+@item Saving all modified registers, including scratch-registers.
+@item Creating an entry in the interrupt vector table.
+@end itemize
+
+
+@subsection Stack checking
+
+Dynamic checking of the stack used (or possibly extending the stack size
+if possible) is another useful feature. If the variable @code{stack_check}
+is set, stack-checking code should be emitted, if possible. Every function
+should call a library function (usually called @code{__stack_check}) and
+pass the maximum size of stack used in this function as argument. This
+obviously has to be done before allocating the stack-frame.
+
+The library function is responsible to take into account its own
+stack-frame.
+
+@subsection Profiling
+
+FIXME: To be written.
+
+@node{vlas}
+@subsection Variable-length Arrays
+
+With the @code{-c99} option, vbcc supports variable-length arrays that
+are allocated on the stack. The backend has to take several steps to
+support this:
+
+@table @code
+@item vlas
+When this variable is non-zero, the current function uses variable-length
+arrays. The backend may take necessary steps to support this. For example,
+if local variables are usually addressed via stackpointer, switching to a
+separate framepointer may be necessary.
+
+@item ALLOCVLA_INLINEASM
+This define must contain inline code that is called when a vla is
+allocated. It has to create additional room on the stack and return a
+pointer to the beginning of the new space.
+
+@item ALLOCVLA_REG
+The register in which to pass the size to be allocated on the stack. 0 will
+pass on the stack.
+
+@item FREEVLA_INLINEASM
+This define must contain inline code that is called when a vla is
+freed. It has to restore the old stack pointer.
+
+@item FREEVLA_REG
+The register in which to pass the old stack pointer. 0 will
+pass on the stack.
+
+@item OLDSPVLA_INLINEASM
+This define must contain inline code that is called before the first vla is
+allocated. It has to return the current stack pointer before any vla has
+been allocated.
+
+@item FPVLA_REG
+An additional register used in functions containing vlas. The backend can
+specify a register (usually framepointer) that can not be used in functions
+with vlas. Therefore, it is possible to use this register in other functions
+(for example, if local variables are usually addressed directly through the
+stackpointer).
+
+@end table
+
+@node{libcalls}
+@subsection Library Calls
+
+Sometimes operations may be very complicated to generate code for (e.g.
+floating-point operations for machines without FPU, multiplication/division
+on some architectures or big data types like @code{long long}). Those are
+usually implemented by calling library functions.
+
+vbcc can be told to generate calls to library functions for certain ICs. When
+defining @code{HAVE_LIBCALLS}, the backend must provide the function
+@code{char *use_libcall(<code>,<typf>,<typf2>)}. This function gets
+called with the elements @code{code}, @code{typf} and @code{typf2} of an IC.
+If @code{use_libcall} returns a name, this library function will be called
+instead of the IC. Otherwise, 0 must be returned.
+
+All library functions have to be declared in @code{init_cg()} with
+@code{declare_builtin()}, supporting the following arguments:
+
+@table @code
+
+@item name
+The name of the library function. Usually, a reserved identifier should be
+chosen (e.g. starting with @code{__}).
+
+@item ztyp
+The return type of the function (only integral and float types are supported).
+
+@item q1typ
+The type of the first parameter (only integral and float types are supported).
+
+@item q1reg
+The register to pass the first argument in (0 passes via stack).
+
+@item q2typ
+The type of the second parameter (only integral and float types are supported).
+For functions with a single parameter, use 0.
+
+@item q2reg
+The register to pass the second argument in (0 passes via stack).
+
+@item nosidefx
+If this is non-zero, the function will be declared to have no side-effects
+and allow some more optimizations.
+
+@item inline_asm
+Inline assembly can be specified for the function.
+
+@end table
+
+Note that not all ICs can be converted to library calls.
+
+
+@section Changes from 0.7 Interface
+
+The backend interface has changed in several ways since @command{vbcc} 0.7.
+The following list mentions most(all?) differences between the old
+and new interfaces (not including new optional features which do not have
+to be used):
+
+@itemize @minus
+@item There are more types (@code{LLONG, LDOUBLE, MAXINT}). Therefore
+ the @code{align[]} and @code{sizetab[]} arrays have dimension
+ @code{MAX_TYPES+1} rather than 16.
+@item The representation and access of @code{t_min[]} and @code{t_max[]}
+ has been changed.
+@item @code{zmax} replaces @code{zlong} as largest integer target
+ type. @code{zlong} is only used when actually referring to a
+ @code{long} on the target. Also, the macros for target arithmetic
+ are available for @code{zmax/zumax} instead of @code{zlong/zulong}.
+@item @code{PUSH} ICs contain a second size (actual stack-adjustment).
+@item The second argument of @code{SHIFT} ICs has an own type.
+@item @code{DREFOBJ} objects contain the type of the dereferenced pointer
+ (only meaningful if there are different pointer types).
+@item The new @code{CONVERT} IC replaces the series of old ICs
+ (@code{CONVINT} etc.).
+@item @code{emit()}-functions have to be used to generate output rather
+ than @code{fprintf()}.
+@item The functions @code{init_db()} and @code{cleanup_db()} have to be
+ provided (they do not have do to anything).
+@item A new array @code{reg_prio[]} is needed and controls the order
+ in which registers are allocated.
+@item The parameters of @code{must_convert()} have changed.
+@item Static functions must not use identifiers, but have to use numbered
+ labels.
+
+@end itemize
+
+Volker Barthelmann vb@@compilers.de
+
diff --git a/doc/ucpp.texi b/doc/ucpp.texi
new file mode 100755
index 0000000..6a8821d
--- /dev/null
+++ b/doc/ucpp.texi
@@ -0,0 +1,40 @@
+vbcc contains the C preprocessor ucpp by Thomas Pornin.
+
+Attached is the copyright notice from the ucpp-distribution (note that
+apart from ucpp no other part of this distribution falls under this
+license).
+
+
+Volker Barthelmann vb@compilers.de
+
+
+--------------
+
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
diff --git a/doc/vbcc.texi b/doc/vbcc.texi
new file mode 100644
index 0000000..1ccfeaa
--- /dev/null
+++ b/doc/vbcc.texi
@@ -0,0 +1,461 @@
+\ifx\pdfminorversion\undefined
+ \pdfoptionpdfminorversion=3
+\else
+ \pdfminorversion=3
+\fi
+\input texinfo
+
+@setfilename index.texi
+@settitle vbcc manual
+@setchapternewpage odd
+@set UPDATED February 2022
+
+@ifinfo
+
+This is the manual for the vbcc compiler system.
+
+Copyright 1995-2022 Volker Barthelmann
+
+@end ifinfo
+
+@titlepage
+@title vbcc compiler system
+@author Volker Barthelmann
+@subtitle @value{UPDATED}
+
+@page
+
+@end titlepage
+
+@paragraphindent 0
+
+@contents
+
+@chapter General
+
+@section Introduction
+
+ vbcc is a highly optimizing portable and retargetable ISO C compiler.
+ It supports ISO C according to ISO/IEC 9899:1989 and a subset of the
+ new standard ISO/IEC 9899:1999 (C99).
+
+ It is split into a target-independent and a target-dependent part, and
+ provides complete abstraction of host- and target-arithmetic. Therefore,
+ it fully supports cross-compiling for 8, 16, 32 and 64bit architectures.
+
+ Embedded systems are supported by features like different pointer-sizes
+ (e.g. differently sized function- and object-pointers or near- and
+ far-pointers), ROM-able code, inline-assembly, bit-types,
+ interrupt-handlers, section-attributes, stack-calculation and many
+ others (depending on the backend).
+
+ vbcc provides a large set of aggressive high-level optimizations
+ (@pxref{Optimizations})
+ as well as target-specific optimizations to produce faster or smaller
+ code. Rather than restricting analysis and optimization to single
+ functions or files, vbcc is able to optimize across functions and
+ even modules. Target-independent optimizations include:
+
+@itemize @minus
+ @item cross-module function-inlining
+ @item partial inlining of recursive functions
+ @item inter-procedural data-flow analysis
+ @item inter-procedural register-allocation
+ @item register-allocation for global variables
+ @item global common-subexpression-elimination
+ @item global constant-propagation
+ @item global copy-propagation
+ @item dead-code-elimination
+ @item alias-analysis
+ @item loop-unrolling
+ @item induction-variable elimination
+ @item loop-invariant code-motion
+ @item loop-reversal
+@end itemize
+
+
+@section Legal
+
+ vbcc is copyright in 1995-2022 by Volker Barthelmann.
+
+ This archive may be redistributed without modifications and used
+ for non-commercial purposes.
+
+ An exception for commercial usage is granted, provided that the target
+ CPU is M68k and the target OS is AmigaOS. Resulting binaries may be
+ distributed commercially without further licensing.
+
+ An exception for commercial usage is granted, provided that the target
+ CPU is 6502 with MEGA65 extensions and the target HW is MEGA65.
+ Resulting binaries may be
+ distributed commercially without further licensing.
+
+ In all other cases you need my written consent.
+
+ This copyright applies to vc, vbcc, vsc and vcpr.
+
+ This archive may contain other tools (e.g. assemblers or linkers)
+ which do not fall under this license. Please consult the corresponding
+ documentation of these tools.
+
+ vbcc contains the preprocessor ucpp by Thomas Pornin. Included is the
+ copyright notice of ucpp (note that this license does not apply to vbcc
+ or any other part of this distribution):
+
+@example
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+@end example
+
+
+@section Installation
+
+The vbcc directory tree looks as follows:
+
+@table @file
+
+@item vbcc/bin
+ The executables.
+
+@item vbcc/config
+ Config files for the frontend.
+
+@item vbcc/targets/<target>
+ Subdirectory containing all files specific to a certain
+ target (e.g. m68k-amigaos or ppc-eabi).
+@end table
+
+@subsection Installing for Unix
+
+ @enumerate
+
+ @item Extract the archive.
+
+ @item Set the environment variable @env{VBCC} to the vbcc directory.
+ Depending on your shell this might be done e.g. by
+
+ @example
+ VBCC=<prefix>/vbcc
+ @end example
+
+ or
+
+ @example
+ setenv VBCC <prefix>/vbcc
+ @end example
+
+ @item Include <prefix>/vbcc/bin to your search-path. Depending on your
+ shell this might be done e.g. by
+
+ @example
+ PATH=<prefix>/vbcc/bin:"$PATH"
+ @end example
+
+ or
+
+ @example
+ setenv PATH <prefix>/vbcc/bin:"$PATH"
+ @end example
+
+ @end enumerate
+
+
+@subsection Installing for DOS/Windows
+
+ @enumerate
+
+ @item Extract the archive.
+
+ @item Set the environment variable @env{VBCC} to the vbcc directory.
+
+ @example
+ set VBCC=<prefix>\vbcc
+ @end example
+
+ @item Include <prefix>/vbcc/bin to your search-path.
+
+ @example
+ set PATH=<prefix>\vbcc\bin;%PATH%
+ @end example
+
+ @end enumerate
+
+
+@subsection Installing for AmigaOS
+
+ There is an Amiga Installer, which lets
+ you install the binary and target archives with a simple mouse click.
+ @command{vbcc} for AmigaOS/MorphOS is divided into the following
+ packages:
+
+ @table @file
+ @item vbcc_bin_amigaos68k
+ Binaries for AmigaOS 2.x/3.x (68020+).
+ @item vbcc_bin_amigaosppc
+ Binaries for AmigaOS 4.x (PowerPC).
+ @item vbcc_bin_morphos
+ Binaries for MorphOS (PowerPC).
+ @item vbcc_bin_powerup
+ Additional PPC-native binaries using the PowerUp kernel for
+ AmigaOS 3.x.
+ @item vbcc_bin_warpos
+ Additional PPC-native binaries using the WarpOS kernel for
+ AmigaOS 3.x.
+ @item vbcc_target_m68k-kick13
+ Header files and libraries for AmigaOS 1.x/M68k.
+ @item vbcc_target_m68k-amigaos
+ Header files and libraries for AmigaOS 2.x/3.x/M68k.
+ @item vbcc_target_ppc-amigaos
+ Header files and libraries for AmigaOS 4.x.
+ @item vbcc_target_ppc-morphos
+ Header files and libraries for MorphOS.
+ @item vbcc_target_ppc-powerup
+ Header files and libraries for PowerUp.
+ @item vbcc_target_ppc-warpos
+ Header files and libraries for WarpOS.
+ @end table
+
+ Usually you will install the binary archive for your host architecture
+ of choice, then add as many target archives you need.
+
+ When installing manually it is recommended to add the following
+ assigns to your @file{s:User-Startup} file (only do the assignments
+ required for the installed targets):
+
+@example
+assign >NIL: vbcc: <path to vbcc directory>
+assign >NIL: C: vbcc:bin add
+
+assign >NIL: vincludeos1: vbcc:targets/m68k-kick13/include
+assign >NIL: vincludeos1: <path to your Kickstart 1.x header files> ADD
+assign >NIL: vlibos1: vbcc:targets/m68k-kick13/lib
+
+assign >NIL: vincludeos3: vbcc:targets/m68k-amigaos/include
+assign >NIL: vincludeos3: <path to your AmigaOS3 header files> ADD
+assign >NIL: vlibos3: vbcc:targets/m68k-amigaos/lib
+
+assign >NIL: vincludeos4: vbcc:targets/ppc-amigaos/include
+assign >NIL: vincludeos4: <path to your AmigaOS4 header files> ADD
+assign >NIL: vlibos4: vbcc:targets/ppc-amigaos/lib
+
+assign >NIL: vincludemos: vbcc:targets/ppc-morphos/include
+assign >NIL: vincludemos: <path to your MorphOS header files> ADD
+assign >NIL: vlibmos: vbcc:targets/ppc-morphos/lib
+
+assign >NIL: vincludepup: vbcc:targets/ppc-powerup/include
+assign >NIL: vincludepup: <path to your PowerUp header files> ADD
+assign >NIL: vincludepup: <path to your AmigaOS3 header files> ADD
+assign >NIL: vlibpup: vbcc:targets/ppc-powerup/lib
+
+assign >NIL: vincludewos: vbcc:target/ppc-warpos/include
+assign >NIL: vincludewos: <path to your WarpOS header files> ADD
+assign >NIL: vincludewos: <path to your AmigaOS3 header files> ADD
+assign >NIL: vlibwos: vbcc:target/ppc-warpos/lib
+
+@end example
+
+ Also, the stack-size has to be increased from the default, for those
+ binaries which don't do that automatically (e.g. AmigaOS4).
+ 64KB is a sensible value, for very large projects higher
+ values might be necessary.
+
+ For writing AmigaOS/MorphOS programs you will need the appropriate
+ system header files. Please use NDK 3.9 or later for AmigaOS 2.x/3.x, as
+ the proto/inline headers have been created with it.
+
+ For AmigaOS 1.x you should use the old Kickstart 1.x headers from that
+ time. It makes sure that you don't use a feature of later OS releases.
+
+ There are different configuration files provided in the
+ @file{config}-subdirectory to choose different targets (i.e.
+ the system you want to generate programs for) and hosts
+ (i.e. the system you want the compiler an tools to run on).
+ The general naming-scheme for these files is <target>_<host>.
+
+ Available config files, when all targets are installed, are
+@table @file
+@item aos68k
+ AmigaOS 2.x/3.x.
+@item aos68km
+ AmigaOS 2.x/3.x with minimal startup code.
+@item aos68kr
+ AmigaOS 2.x/3.x for resident programs.
+@item kick13
+ AmigaOS 1.x.
+@item kick13m
+ AmigaOS 1.x with minimal startup code.
+@item kick13r
+ AmigaOS 1.x for resident programs.
+@item aosppc
+ AmigaOS 4.x on PPC using vclib.
+@item newlib
+ AmigaOS 4.x on PPC using newlib.
+@item morphos
+ PPC systems running MorphOS.
+@item powerup
+ PPC boards using the PowerUp system.
+@item warpos
+ PPC boards using the WarpOS system.
+@end table
+
+ You can choose one of these systems using the @option{+}-option
+ of @command{vc}, e.g.
+
+@example
+ vc +aos68k_powerup ...
+@end example
+
+ will compile for AmigaOS/68k using the compiler running on PowerUp.
+
+ You may choose to create copies of some of these configuration
+ files with simpler names. E.g. if you usually want the compiler
+ to run on WarpOS you could copy @file{aos68k_warpos} to @file{aos68k},
+ @file{warpos_warpos} to @file{warpos} and so on. Then you can just specify
+ the target and your preferred host system will be chosen automatically.
+
+ Additionally, you may copy the configuration file for your preferred
+ host/target-combination to
+ @file{vc.config}. This configuration will be chosen by default if
+ you do not specify anything.
+
+ By default, the target-only-specifications use 68020-native tools on
+ AmigaOS 2.x/3.x - e.g. @option{+warpos} will create code for WarpOS,
+ but the compiler and tools will run on the 68k. The default
+ @file{vc.config} will then create code for 68k using tools running
+ on 68k. Having installed the MorphOS-native binary archive instead,
+ the default @file{vc.config} will create PPC code for MorphOS using
+ tools running on MorphOS.
+
+@section Tutorial
+
+ Now you should be able to use vbcc. To compile and
+ link the program @file{hello.c}, type
+
+@example
+ vc hello.c
+@end example
+
+ The file @file{hello.c} will be compiled and linked, using the
+ default configuration from @file{vc.config}, to create
+ the executable a.out in the current directory.
+
+@example
+ vc hello.c -o hello
+@end example
+
+ will do the same, but the created executable will be called @file{hello}.
+
+@example
+ vc -c t1.c t2.c
+@end example
+
+ will compile @file{t1.c} and @file{t2.c} without linking, creating the
+ object files @file{t1.o} and @file{t2.o}.
+
+@example
+ vc t1.o t2.o -o tt
+@end example
+
+ will link them together and create the executable @file{tt}.
+
+ If your program uses floating point, you may have to link with a
+ math-library. The details are dependent on the target, but usually
+ @option{-lm} will be suitable (for AmigaOS on m68k choose one of
+ @option{-lmieee}, @option{-lm881}, @option{-lm040} or @option{-lm060}).
+
+@example
+ vc calc.c -o calc -lm
+@end example
+
+
+@node The Frontend
+@chapter The Frontend
+@include vc.texi
+
+@node The Compiler
+@chapter The Compiler
+@include vbcc_main.texi
+
+
+@node M68k/Coldfire Backend
+@chapter M68k/Coldfire Backend
+@include vbccm68k.texi
+
+@node PowerPC Backend
+@chapter PowerPC Backend
+@include vbccppc.texi
+
+@node DEC Alpha Backend
+@chapter DEC Alpha Backend
+@include vbccalpha.texi
+
+@node i386 Backend
+@chapter i386 Backend
+@include vbcci386.texi
+
+@node c16x Backend
+@chapter c16x Backend
+@include vbccc16x.texi
+
+@node 68hc12 Backend
+@chapter 68hc12 Backend
+@include vbcchc12.texi
+
+@node VideoCore IV Backend
+@chapter VideoCore IV Backend
+@include vbccvidcore.texi
+
+@node 6502 Backend
+@chapter 6502 Backend
+@include vbcc6502.texi
+
+
+@node Instruction Scheduler
+@chapter Instruction Scheduler
+@include vsc.texi
+
+@node Code Compressor
+@chapter Code Compressor
+@include vcpr.texi
+
+@node C Library
+@chapter C Library
+@include vclib.texi
+
+@node List of Errors
+@chapter List of Errors
+
+@enumerate 0
+@include errors.texi
+@end enumerate
+
+@chapter Backend Interface
+@include interface.texi
+
+@bye
diff --git a/doc/vbcc6502.texi b/doc/vbcc6502.texi
new file mode 100644
index 0000000..e79bdaa
--- /dev/null
+++ b/doc/vbcc6502.texi
@@ -0,0 +1,517 @@
+This chapter documents the backend for the 6502
+processor family.
+
+@section Additional options
+
+This backend provides the following additional options:
+
+@table @option
+
+ @item -c02
+ @item -65c02
+ Generate code using 65C02 extensions.
+
+ @item -ce02
+ Generate code using CSG 65CE02/4510 extensions.
+
+ @item -mega65
+ Generate code using the MEGA65 extensions.
+
+ @item -m65io
+ When using the MEGA65 multiplier/divider, assume that the IO area
+ is directly accessible to generate smaller and faster code.
+
+ @item -div-bug
+ Do not generate code using the MEGA65 divider as this is buggy in
+ early versions.
+
+ @item -std-syntax
+ Generate code for the std syntax module of vasm rather than
+ the default oldstyle syntax module.
+
+ @item -cbmascii
+ Convert string-constants and character-constants to CBM ASCII.
+
+ @item -atascii
+ Convert string-constants and character-constants to Atari ASCII.
+
+ @item -ieee
+ Use 32/64bit IEEE format for floating point rather than wozfp format.
+
+ @item -softstack
+ Try to use the hardware stack as little as possible. Use this if your
+ hardware stack is overflowing.
+
+ @item -mainargs
+ Some targets may need special initializations when using the command
+ line arguments to main(). vbcc will emit a call to a library function
+ when those are used and @code{-mainargs} is specified.
+
+ @item -no-bank-vars
+ Do not automatically handle accesses to banked variables, but only
+ function calls. See chapter on banking.
+
+ @item -manual-banking
+ Do not automatically handle banking. Useful if you want to use the
+ section mapping of the @code{__bank}-attribute or @code{#pragma bank}
+ but you prefer handle bank switching yourself.
+
+ @item -avoid-bank-switch
+ Prefer calling @code{__bankload/__bankstore} instead of @code{__bankswitch}.
+ Useful for banking mechanisms that do not provide quick switching
+ of an entire bank (e.g. the C64 REU).
+
+ @item -common-banknr=<n>
+ Specify the bank number of the common bank. See chapter on banking. The
+ default number is 0.
+
+ @item -large
+ Use large memory model. All pointers will be far pointers. A corresponding
+ library is required. This feature is experimental.
+
+ @item -glob-acc
+ By default, the register allocator will only assign temporary
+ variables to the accumulator register or @code{a/x} register pair.
+ Usually this reduces necessary storing/loading of the accumulator
+ as it is needed during most operations. This option allows the
+ register allocator to assign variables with bigger live ranges to
+ the accumulator. This option is likely to create worse code in
+ most cases. Use only for experimentation.
+
+@end table
+
+@section ABI
+
+ The current version generates assembler output for use with
+ @command{vasm6502_oldstyle} or @command{vasm6502_std}.
+ The option @command{-opt-branch} is needed.
+
+ The register names provided by this backend are:
+
+@example
+ a, sp, r0..r31, btmp0..btmp3
+@end example
+
+ @code{a} is the accumulator. It can be used for type @code{char}.
+
+ @code{r0} ... @code{r31} are 8bit variables that can be used for type
+ @code{char}. They have to be mapped
+ to zero page during linking. The compiler expects registers that can
+ be used as register pairs (see below) to be mapped to contiguous
+ memory locations. Some library routines may have additional requirements.
+
+ @code{sp} is a 16bit variable that has to be mapped to zero page. It is
+ used by the compiler and not available for use. @code{sp} must be
+ initialized to a suitable memory area. This stack is used for local variables,
+ saved registers etc. The hardware stack is used mainly for return addresses
+ and sometimes saved registers.
+
+ @code{btmp0}..@code{btmp3} are 32bit variables. The code generated by vbcc
+ does not require them in zero page, but the current library implementation
+ expects them to be located to contiguous zero page locations.
+
+ The following register pairs can be used for
+ 16bit values.
+
+@example
+ a/x, r0/r1, r2/r3 ... r30/r31
+@end example
+
+ @code{a/x} can be used for types @code{short} and @code{int}, the other
+ register pairs can also be used for pointer types.
+
+ The following register pairs can be used for
+ 64bit values (IEEE doubles or long long).
+
+@example
+ btmp0/btmp1, btmp2/btmp3
+@end example
+
+
+ Registers @code{a, r0..r15, r28..r31, btmp0..btmp3} are volatile
+ (i.e. they can be destroyed in function calls). @code{r16..r27} are
+ preserved across function calls.
+
+ @code{r0..r7} are used for passing function arguments of type
+ @code{char, short, int} and pointer types. @code{btmp0..btmp3} are
+ used for passing arguments of type @code{long, long long, float, double,
+ long double} and far pointers. All other types are passed on the stack.
+
+ For functions with a variable-argument-list, arguments that are part
+ of the variable-argument-list are always passed on the stack. It is
+ therefore required that a prototype is in scope when calling such functions
+ (as required by C).
+
+ Scalar types are returned as follows:
+@example
+ type registers
+
+ char a
+ short a/x
+ int a/x
+ long btmp0
+ long long n/a
+ pointers a/x
+ far-pointer btmp0
+ float btmp0
+ double btmp0 or btmp0/btmp1 (IEEE)
+ long double btmp0 or btmp0/btmp1 (IEEE)
+@end example
+
+ All other types are returned by passing the function the address
+ of the result as a hidden argument - such a function must not be called
+ without a proper declaration in scope.
+
+The basic data types are represented like this:
+
+@example
+ type size in bits alignment in bytes
+
+ char 8 1
+ short 16 1
+ int 16 1
+ long 32 1
+ long long 64 1 (currently not supported)
+ near pointers 16 1
+ far pointers 24 1
+ float 32 1 see below
+ double 32/64 1 see below
+ long double 32/64 1 see below
+@end example
+
+
+@section Math
+
+
+ For certain operations @code{vbcc} will emit calls to routines that have
+ to be provided by a library.
+ For integer code, the following operations are handled by library routines
+ (some special cases involving constants may be handled by inline code).
+
+@example
+ __mulint16 16x16=>16 multiplication
+ __mulint32 32x32=>32 multiplication
+ __divint16 16x16=>16 signed division
+ __divint32 32x32=>32 signed division
+ __divuint16 16x16=>16 unsigned division
+ __divuint32 32x32=>32 unsigned division
+ __modint16 16x16=>16 signed modulo
+ __modint32 32x32=>32 signed modulo
+ __moduint16 16x16=>16 unsigned modulo
+ __moduint32 32x32=>32 unsigned modulo
+@end example
+
+@subsection Floating Point
+
+ By default, all floating point types are implemented as 32bit values.
+ The format used by the floating point routines published by Roy Rankin
+ and Steve Wozniak is used. While this does work for many use cases, it
+ is not fully C compliant by any means. Calculation of constants in the
+ compiler is not done in that format. Therefore, the results of
+ calculations done at compile-time may be different from those at run-time.
+ The corresponding math library must be linked using @code{-lm}.
+
+ As an alternative, @code{vbcc} can use IEEE format by specifying
+ @code{-ieee}. This will solve the problems mentioned above and provide
+ accurate results using the SANE floating point environment. However,
+ these routines are slower and much bigger. Also, you may have to clarify
+ their legal status before using them. The IEEE routines will likely not
+ work when running from ROM.
+
+ In addition to @code{-ieee}, the SANE library has to be linker using
+ @code{-lmieee}.
+
+ When using floating point, the following library routines are needed
+ (without @code{-ieee}):
+
+@example
+ __addflt32 floating point addition
+ __subflt32 floating point subtraction
+ __mulflt32 floating point multiplication
+ __divflt32 floating point division
+ __negflt32 floating point negation (-x)
+ __cmpsflt32 floating point comparison
+ (sets @code{a} to pos., neg. or zero, depending on
+ the comparison result)
+ __sint16toflt32 convert signed 16bit integer to floating point
+ __uint16toflt32 convert unsigned 16bit integer to floating point
+ __sint32toflt32 convert signed 32bit integer to floating point
+ __uint32toflt32 convert unsigned 32bit integer to floating point
+ __flt32tosint16 convert floating point value to signed 16bit integer
+ __flt32touint16 convert floating point value to unsigned 16bit integer
+ __flt32tosint32 convert floating point value to signed 32bit integer
+ __flt32touint32 convert floating point value to unsigned 32bit integer
+@end example
+
+ Further math library functions may be needed by user code or the C library.
+
+
+
+@section Target-Specific Variable Attributes
+
+ This backend offers the following variable attributes:
+
+@table @code
+ @item __interrupt
+ Used for writing interrupt handlers. All used registers
+ (including volatiles and accumulator) are saved/restored and
+ @code{rti} is used to leave the function. Also, the user stack
+ pointer is set to @code{__isrstack}. This value for the interrupt
+ stack has to be provided e.g. by the linker script.
+
+ @item __zpage
+ Place variable in section @code{zpage} and instruct @code{vbcc}
+ to use it with zero-page addressing.
+
+ @item __nocpr
+ Turn off code compression for this function even if @code{-size} is used.
+ Useful for time-critical functions.
+
+ @item __bank(<n>)
+ Place the variable/function in bank n. See chapter on banking for details.
+
+@end table
+
+@section Target-Specific #pragmas
+
+ This backend offers the following #pragmas
+
+@table @code
+ @item #pragma section <sec>
+ The following functions and variables are placed in section <sec>.
+
+ @item #pragma section default
+ The following functions and variables are placed in default sections.
+
+ @item #pragma bank <n>
+ The following functions and variables are placed in bank <n>. See the
+ chapter on banking for details.
+
+ @item #pragma bank -1
+ The following functions and variables are placed in the default bank. See the
+ chapter on banking for details.
+
+@end table
+
+
+@section Predefined Macros
+
+ This backend defines the following macros:
+
+@table @code
+ @item __6502__
+
+ @item __SIZE_T_INT
+
+@end table
+
+
+@section Stack
+
+ Local variables and function arguments are put on the user stack. It
+ can be up to 64KB, but accessing variables outside the lower 256 bytes
+ is significantly slower. @code{vbcc} will put small variables on lower
+ offsets to increase the number of variables that can be addressed fast.
+ However, accessing the stack is always rather slow on the 6502.
+
+ The stack pointer is adjusted once during function entry/exit to avoid
+ multiple costly adjustments to the stack pointer.
+
+ Variable-length-arrays as specified in c99 should be fully supported.
+
+
+@section Banking
+
+ Many 6502 systems offer/need different banking mechanisms. vbcc offers different
+ levels of support for those schemes. Depending on the target integration, more
+ or less support is offered.
+
+@subsection Manual Banking
+
+ Banking can usually be implemented manually if there is no suitable target
+ integration or if manual optimization is preferred.
+
+ For manual banking, functions and/or data can be mapped to sections using
+ the @code{section} attribute or the @code{#pragma section} directive. Note that
+ string constants will be mapped to banked memory only when using the @code{#pragma}
+ approach.
+
+ After placing the objects in suitable sections, they have to be located using a
+ linker command file. See the documentation on vlink. Switching between banks has
+ to done manually in a system-specific way.
+
+ If initialized variables are mapped into banked sections, be aware that you may have
+ to provide means to initialize them on startup. It is probably not handled by
+ startup code for non-banked systems. This is not relevant for systems that only
+ provide banked ROM.
+
+
+@subsection Automated Banking
+
+ If a suitable target integration is available, vbcc is able to automatically
+ handle bank switching.
+
+@subsubsection Memory Model
+
+ vbcc assumes a memory model which provides non-banked
+ memory for code and data that is always visible. Additionally there can be a
+ number of up to 255 memory banks, one of which can be visible at a time.
+
+ If several banks can be visible at the same time, this will also work, but vbcc
+ does not make use of this feature.
+
+@subsubsection Mapping
+
+ Code/data can be put into banks using the @code{bank}-attribute or
+ @code{#pragma bank}. Note that string constants will be mapped to banked memory only
+ when using the @code{#pragma} approach. Code/data not mapped to a bank will be
+ mapped to the always visible non-banked area.
+
+ Banked objects will be mapped to sections suffixed with the bank number, e.g. in
+
+@example
+__bank(0) int i = 1;
+__bank(1) void f() { }
+@end example
+
+ @code{i} will be put into section @code{data0} and @code{f} will be put
+ into section @code{text1}.
+
+@subsubsection Bank Switching
+
+ vbcc will try to determine when a bank switch has to
+ be made and it will call library functions to map in the required data. This
+ requires that when accessing an object, vbcc has to know which bank the object is
+ assigned to. Therefore a declaration specifying the correct bank number (either
+ using the @code{__bank()}-attribute or @code{#pragma bank}). If an object is
+ accessed which has not been declared with a bank number, it is assumed that it
+ can be accessed without bank switching.
+
+@subsubsection Far Pointers
+
+ When accessing an object through a normal pointer, the bank number is not known.
+ All accesses through normal pointers assume that the target is always visible.
+ For all other cases, far-ointers have to be used. Far-pointers contain the bank number
+ as additional information, resulting in a size of 3 bytes.
+
+ They are declared using the @code{__far}-qualifier. @code{__far} is used like a type
+ qualifier, similar to @code{const}.
+
+@example
+ __bank(0) i0;
+ __bank(1) i1;
+ __far int *fp;
+ ...
+
+ if(..)
+ fp = &i0;
+ else
+ fp = &i1;
+@end example
+
+ Converting a far-pointer to a normal pointer will loose the bank information.
+ Converting a normal pointer to a far-pointer will insert the bank number of the current
+ function. Care must be taken not to loose bank information when working with
+ pointers.
+
+@subsubsection Performance Considerations
+
+ Accessing objects through bank switching generates much slower and larger code than
+ direct accesses. Therefore it is crucial to organize your objects in a way that
+ reduces task switches as much as possible. Following is a list of hints and
+ explanations.
+
+@itemize
+@item Using far pointers will always incur overhead. Try to use them only when
+ necessary.
+
+@item Accessing objects from the non-banked area is always fast (unless done through
+ far-pointers).
+
+@item Accessing objects from the same bank the function is mapped to is usually fast
+ (unless done through far-pointers).
+
+@item Accessing banked objects from non-banked code is usually faster than accessing
+ them from banked code in another bank.
+
+@item Calling functions in another bank is a reasonably small overhead on systems with a
+ fast bank switch. It can be much more overhead on RAM expansions that have to
+ copy code.
+
+@item Be careful when using function inlining. Inlined code will be executed in
+ the bank of the caller.
+@end itemize
+
+In general, try to reduce cross-bank accesses and far-pointer usage as much as possible.
+For best performance you can always only use the @code{section}-features to map everything
+and handle all bank-switching yourself.
+
+@subsubsection Library
+
+To use the automated bank switching, a series of library functions must be available
+(TODO: add more detailed information, may change):
+
+
+@table @code
+@item ___bankswitch
+ Make the bank in @code{y} accessible.
+
+@item ___bankjsr
+ Call the function pointer @code{r30/r31} in bank @code{y}. Return to the caller
+ in bank @code{a}.
+
+@item ___bankload<n> (n=1,2,3,4,8)
+ Copy <n> bytes from @code{r30/r31} in bank @code{y} to non-banked variable
+ @code{___bankv} with offset @code{x}. Caller bank in @code{a}.
+
+@item ___bankstore<n> (n=1,2,3,4,8)
+ Copy <n> bytes from non-banked variable @code{___bankv} with offset @code{x} to
+ @code{r30/r31} in bank @code{y}. Caller bank in @code{a}.
+
+@item ___bankcopy
+ Copy @code{___bankcopy_len/___bankcopy_len+1} bytes from @code{r28/r29} in bank @code{y} to
+ @code{r30/r31} in bank @code{x}. Caller bank in @code{a}.
+@end table
+
+
+@section Debugging
+
+ The 6502 backend has some limited support for debugging.
+
+ When using vlink, the @code{-vicelabels} options can be used to output symbol
+ values in a format that can be read by the vice emulator/debugger.
+
+ With the @code{-g} option, line numbers and file names of source code will
+ be added to the assembly output. Using some tools, it should be possible to
+ create a mixed C/assembly file for inspection.
+ Depending on the optimization level, the
+ results may be more or less usable, see section Debugging Optimized Code.
+ Note that the added comments will affect the assembly peephole
+ optimizer, resulting in worse code than without @code{-g}.
+
+
+@section Code compressor
+
+ The @code{vcpr6502} code compressor supports the 6502 target. It should
+ be called automatically on higher optimization levels when using the
+ frontend @code{vc}. As the code will be slowed down when using compression,
+ the 6502 backend will only enable compression when using the @code{-size}
+ option.
+
+ TODO: manual overriding
+
+
+@section Known problems
+
+@itemize @minus
+ @item @code{long long} not yet supported
+
+ @item return value of cross-bank function calls may not work
+
+ @item banking not tested very much
+
+
+@end itemize
+
+
+
diff --git a/doc/vbcc_main.texi b/doc/vbcc_main.texi
new file mode 100644
index 0000000..b58722f
--- /dev/null
+++ b/doc/vbcc_main.texi
@@ -0,0 +1,1990 @@
+This chapter describes the target-independent part of the compiler. It
+documents the options and extensions which are not specific to a certain
+target. Be sure to also read the chapter on the backend you are using. It will
+likely contain important additional information like data-representation
+or additional options.
+
+@node General Compiler Options
+@section General Compiler Options
+
+ Usually @command{vbcc} will be called by @command{vc}. However, if called
+ directly it expects the following syntax:
+
+@example
+ @command{vbcc<target> [options] file}
+@end example
+
+ The following options are supported by the machine independent part
+ of @command{vbcc} (and will be passed through by @command{vc}):
+
+@table @option
+
+ @item -quiet
+ Do not print the copyright notice.
+
+ @item -ic1
+ Write the intermediate code before optimizing to file.ic1.
+
+ @item -ic2
+ Write the intermediate code after optimizing to file.ic2.
+
+ @item -debug=n
+ Set the debug level to n.
+
+ @item -o=ofile
+ Write the generated assembler output to <ofile> rather than
+ the default file.
+
+ @item -noasm
+ Do not generate assembler output (only for testing).
+
+ @item -O=n
+ Turns optimizing options on/off; every bit set in n turns
+ on an option. Usually the predefined optimization options
+ by the compiler driver should be used.
+ @xref{Optimizations}.
+
+ @item -speed
+ Turns on optimizations which improve speed even if they
+ increase code-size quite a bit.
+
+ @item -size
+ Turns on optimizations which improve code-size even if
+ they have negative effect on execution-times.
+
+ @item -final
+ This flag is useful only with higher optimization levels.
+ It tells the compiler that all relevant files have been
+ provided to the compiler (i.e. it is the link-stage).
+ The compiler will try to eliminate all functions and
+ variables which are not referenced.
+
+ @xref{Unused Object Elimination}.
+
+ @item -wpo
+ Create a high-level pseudo object for cross-module
+ optimization (@pxref{Cross-Module Optimizations}).
+
+
+ @item -g
+ Create debug output. Whether this is supported as well as the
+ format of the debug information depends on the backend.
+ Some backends may offer additional options to control the
+ generation of debug output.
+
+ Usually DWARF2-output will be generated by default, if
+ possible.
+
+ Also, options regarding optimization and
+ code-generation may affect the debug output
+ (@pxref{Debugging Optimized Code}).
+
+
+ @item -cmd=<file>
+ A file containing additional command line options can
+ be specified using this command. This may be useful for
+ very long command lines.
+
+ @item -c89
+ @item -c99
+ Set the C standard to be used.
+ The default is the 1999 ISO C standard (ISO/IEC9899:1999).
+ Currently the following changes of C99 are handled:
+@itemize @minus
+ @item long long int (not supported by all backends)
+ @item flexible array members as last element of a struct
+ @item mixed statements and declarations
+ @item declarations within for-loops
+ @item @code{inline} function-specifier
+ @item @code{restrict}-qualifier
+ @item new reserved keywords
+ @item @code{//}-comments
+ @item vararg-macros
+ @item @code{_Pragma}
+ @item implicit int deprecated
+ @item implicit function-declarations deprecated
+ @item increased translation-limits
+ @item designated initializers
+ @item non-constant initializers for automatic aggregates
+ @item compound literals
+ @item variable-length arrays (incomplete)
+@end itemize
+
+ @item -unsigned-char
+ Make the unqualified type of @code{char} unsigned.
+
+ @item -maxoptpasses=n
+ Set maximum number of optimizer passes to n.
+ @xref{Optimizations}.
+
+ @item -inline-size=n
+ Set the maximum 'size' of functions to be inlined.
+ @xref{Function Inlining}.
+
+
+ @item -inline-depth=n
+ Inline functions up to n nesting-levels (including recursive
+ calls). The default value is 1. Be careful with values greater
+ than 2.
+ @xref{Function Inlining}.
+
+ @item -unroll-size=n
+ Set the maximum 'size' of unrolled loops.
+ @xref{Loop Unrolling}.
+
+ @item -unroll-all
+ Unroll loops with a non-constant number of iterations if
+ the number can be calculated at runtime before entering
+ the loop. @xref{Loop Unrolling}.
+
+ @item -no-inline-peephole
+ Some backends provide peephole-optimizers which perform
+ simple optimizations on the assembly code output by @command{vbcc}.
+ By default, these optimizations will also be performed
+ on inline-assembly code of the application. This switch
+ turns off this behaviour. @xref{Inline-Assembly Functions}.
+
+ @item -fp-associative
+ Floating point operations do not obey the law of
+ associativity, e.g. @code{(a+b)+c==a+(b+c)} is not true for all
+ floating point numbers @code{a},@code{b},@code{c}. Therefore
+ certain optimizations
+ depending on this property cannot be performed on floating
+ point numbers.
+
+ This option tells @command{vbcc} to treat floating point
+ operations as associative and perform those optimizations
+ even if that may change the results in some cases (not
+ ISO conforming).
+
+ @item -no-alias-opt
+ Do not perform type-based alias analysis.
+ @xref{Alias Analysis}.
+
+ @item -no-multiple-ccs
+ If the backend supports multiple condition code
+ registers, @command{vbcc} will try to use them when optimizing.
+ This flag prevents @command{vbcc} from using them.
+
+ @item -double-push
+ On targets where function-arguments are passed in registers
+ but also stack-slots are left empty for such arguments,
+ pass those arguments both in registers and on the stack.
+
+ This generates less efficient code but some broken code
+ (e.g. code which calls varargs functions without correct
+ prototypes in scope) may work.
+
+ @item -short-push
+ In the presence of a prototype, no promotion will be done
+ on function arguments. For example, <char> will be passed
+ as <char> rather than <int> and <float> will not be
+ promoted to <double>. This may be more efficient on small
+ targets.
+
+ However, please note that this feature may not be
+ supported by all backends and that using this option
+ breaks ANSI/ISO conformance. For example, a function
+ with a <char> parameter must never be called without a
+ prototype in scope.
+
+ @item -soft-float
+ On targets supporting this flag, software floating point
+ emulation will be used rather than a hardware FPU. Please
+ consult the corresponding backend documentation when
+ using this flag.
+
+ @item -stack-check
+ Insert code for dynamic stack checking/extending if the
+ backend and the environment support this feature.
+
+ @item -ansi
+ @itemx -iso
+ Switch to ANSI/ISO mode.
+
+
+@itemize @minus
+@item In ISO mode warning 209 will be printed by default.
+@item Inline-assembly functions are not recognized.
+@item Assignments between pointers to <type> and pointers
+ to unsigned <type> will cause warnings.
+@end itemize
+
+ @item -maxerrors=n
+ Abort the compilation after n errors; do not stop if n==0.
+
+ @item -dontwarn=n[,n...]
+ Suppress warning number n; suppress all warnings if n<0.
+ Multiple warnings may be separated by commas.
+ @xref{Errors and Warnings}
+
+ @item -warn=n
+ Turn on warning number n; turn on all warnings if n<0.
+ @xref{Errors and Warnings}
+
+ @item -no-cpp-warn
+ Turn off all preprocessor warnings.
+
+ @item -warnings-as-errors
+ Treat all enabled warnings as errors.
+
+ @item -strip-path
+ Strip the path of filenames from error messages.
+ Error messages may look more convenient that
+ way, but message browsers or
+ similar programs might need full paths.
+
+ @item -no-include-stack
+ Do not display the include stack in error messages.
+
+
+ @item -+
+ @itemx -cpp-comments
+ Allow C++ style comments (not ISO89 conforming).
+
+ @item -no-trigraphs
+ Do not recognize trigraphs (not ISO conforming).
+
+ @item -E
+ Write the preprocessor output to <file>.i.
+
+ @item -deps
+ Write a make-style dependency-line to <file>.dep.
+
+ @item -deps-for-libs
+ By default, @code{-deps} will not include files that are
+ included using the syntax @code{#include <...>}. Specify this option
+ to add those files as well.
+
+ @item -depobj=<file>
+ Use the specified filename as target in the generated dependency
+ file instead of basing it on the input file name.
+
+ @item -reserve-reg=<register>
+ Reserve that register not to be used by the backend.
+ This option is dangerous and must only be used for registers
+ otherwise available for the register allocator. If it used
+ for special registers or registers used internally by the
+ backend, it may be ignored, lead to corrupt code or even
+ cause internal errors from the compiler.
+
+ Only use if you know what you are doing!
+
+ @item -dontkeep-initialized-data
+ By default @command{vbcc} keeps all data of initializations in memory
+ during the whole compilation (it can sometimes make use
+ of this when optimizing). This can take some amount of
+ memory, though. This options tells @command{vbcc} to
+ keep as little of this data in memory as possible.
+ This has not yet been tested very well.
+
+ @item -prefer-statics
+ Assign auto variables to static memory rather than the stack if it
+ can be deduced that the function is not called recursively, i.e. the
+ behaviour is still C compliant. This may be more efficient on targets
+ that can access static data faster than stack. While stack-usage is
+ reduced, total memory consumption is usually increased.
+
+ Functions will not be re-entrant any more.
+
+ This option only has effect on higher optimization levels (@code{-O3}).
+
+ @item -force-statics
+ Like @code{-prefer-statics}, but assume all functions as non-recursive.
+ This will break C compliance.
+
+ This option only has effect on higher optimization levels (@code{-O}).
+
+ @item -range-opt
+ Perform additional optimizations based on value range analysis. This
+ option is under development and considered experimental. The following
+ optimizations are currently implemented:
+
+ @itemize @minus
+ @item Induction variables of some loops are transformed to smaller
+ types if it can be determined that they will only get assigned
+ values that fit into a smaller type.
+ @end itemize
+
+ @item -merge-strings
+ Overlay identical string-constants to save memory. Currently
+ only strings identical to string-constants on top-level are
+ recognized.
+
+ @item -sec-per-obj
+ Tells the backend to put every function/object into its own
+ separate section. This allows more fine-grained elimination
+ of unused functions/objects by the linker. On the other hand,
+ it may prevent some optimizations by the assembler.
+
+ This option only has effect if it is supported by the backend.
+
+ @item -mask-opt
+ Perform mask optimizations on suitable library function. This
+ will create calls to optimized versions of e.g. the printf/scanf
+ family of functions.
+
+@end table
+
+
+ The assembler output will be saved to @file{file.asm}
+ (if @file{file} already contained
+ a suffix, this will first be removed; same applies to .ic1/.ic2)
+
+
+@node Errors and Warnings
+@section Errors and Warnings
+
+ @command{vbcc} knows the following kinds of messages:
+
+@table @asis
+
+ @item Fatal Errors
+ Something is badly wrong and further compilation is
+ impossible or pointless. @command{vbcc} will abort.
+ E.g. no source file or really corrupt source.
+
+ @item Errors
+ There was an error and @command{vbcc} cannot generate useful
+ code. Compilation continues, but no code will be
+ generated.
+ E.g. unknown identifiers.
+
+ @item Warnings (1)
+ Warnings with ISO-violations. The program is not
+ ISO-conforming, but @command{vbcc} will generate code that
+ could be what you want (or not).
+ E.g. missing semicolon.
+
+ @item Warnings (2)
+ The code has no ISO-violations, but contains some
+ strange things you should perhaps look at.
+ E.g. unused variables.
+@end table
+
+ Errors or the first kind of warnings are always displayed and cannot
+ be suppressed.
+
+ Only some warnings of the second kind are turned on by default.
+ Many of them are very useful for some but annoying to others, and
+ their usability may depend on programming style.
+ Everybody is recommended to find their own preferences.
+
+ A good way to do this is starting with all warnings turned on by
+ @option{-warn=-1}. Now all possible warnings will be issued. Everytime
+ a warning that is not considered useful appears, turn that one off with
+ @option{-dontwarn=n}.
+
+ See @ref{List of Errors} for a list of all diagnostic messages available.
+
+ See @ref{The Frontend} to find out how to configure @command{vc} to your
+ preferences.
+
+
+@section Data Types
+
+ @command{vbcc} can handle the following atomic data types:
+
+@table @code
+@item signed char
+@item unsigned char
+@item signed short
+@item unsigned short
+@item signed int
+@item unsigned int
+@item signed long int
+@item unsigned long int
+@item signed long long int
+ (with @option{-c99})
+@item unsigned long long int
+ (with @option{-c99})
+@item float
+@item double
+@item long double
+@end table
+
+The default signedness for integer types is @code{signed}.
+
+Depending on the backend, some of these types can have identical
+representation. The representation (size, alignment etc.) of these types
+usually varies between different backends. @command{vbcc} is able to support
+arbitrary implementations.
+
+Backends may be restricted and omit some types (e.g. floating point on small
+embedded architectures) or offer additional types. E.g. some backends
+may provide special bit types or different pointer types.
+
+
+@node Optimizations
+@section Optimizations
+
+ @command{vbcc} offers different levels of optimization, ranging from fast
+ compilation with straight-forward code suitable for easy debugging
+ to highly aggressive cross-module optimizations delivering very
+ fast and/or tight code.
+
+ This section describes the general phases of compilation and gives
+ a short overview on the available optimizations.
+
+ In the first compilation phase every function is parsed into a tree
+ structure one expression after the other. Type-checking and some
+ minor optimizations like constant-folding or some algebraic
+ simplifications are done on the trees.
+ This phase of the translation is identical in optimizing and
+ non-optimizing compilation.
+
+ Then intermediate code is generated from the trees. In non-optimizing
+ compilation temporaries needed to evaluate the expression are
+ immediately assigned to registers while in optimizing
+ compilation, a new variable is generated for each temporary.
+ Slightly different intermediate code
+ is produced in optimizing compilation.
+ Some minor optimizations are performed while generating the intermediate
+ code (simple elimination of unreachable code, some optimizations on
+ branches etc.).
+
+ After intermediate code for the whole function has been generated,
+ simple register allocation may be done in non-optimizing compilation
+ if bit 1 has been set in the @option{-O} option.
+ Afterwards, the intermediate code is passed to the code generator and
+ then all memory for the function, its variables etc. is freed.
+
+ In optimizing compilation flowgraphs are constructed, data flow analysis
+ is performed and many passes are made over the function's intermediate
+ code. Code may be moved around, new variables may be added, other
+ variables removed etc. etc. (for more detailed information on the
+ optimizations look at the description for the
+ @option{-O} option below).
+
+ Many of the optimization routines depend on each other. If one
+ routine finds an optimization, this often enables other routines to
+ find further ones. Also, some routines only do a first step and let
+ other routines 'clean up' afterwards. Therefore @command{vbcc} usually
+ makes many passes until no further optimizations are found.
+ To avoid possible extremely long optimization times, the number of
+ those passes can be limited with @option{-maxoptpasses} (the
+ default is max. 10 passes).
+ @command{vbcc} will display a warning if more passes might be useful.
+
+ Depending on the optimization level, a whole translation-unit or
+ even several translation-units will be read at once. Also, the
+ intermediate code for all functions may be kept in memory during
+ the entire compilation. Be aware that higher optimization levels
+ can take much more time and memory to complete.
+
+ The following table lists the optimizations which are activated by
+ bits in the argument of the @option{-O} option. Note that not all
+ combinations are valid. It is heavily recommended not to fiddle with
+ this option but just use one of the settings provided by @command{vc}
+ (e.g. @option{-O0} - @option{-O4}). These options also automatically
+ handle actions like invoking the scheduler or cross-module optimizer.
+
+@table @asis
+
+@item Bit 0 (1)
+ Perform Register allocation. @xref{Register Allocation}.
+
+@item Bit 1 (2)
+ This flag turns on the optimizer. If it is set to zero, no global
+ optimizations will be performed, no matter what the other flags are set
+ to.
+ Slightly different intermediate code will be generated
+ by the first translation phases and a flowgraph will be constructed.
+ @xref{Flow Optimizations}.
+
+@item Bit 2 (4)
+ Perform common subexpression elimination
+ (@pxref{Common Subexpression Elimination}) and copy propagation
+ (@pxref{Copy Propagation}).
+ This can be done globally or only within basic blocks
+ depending on bit 5.
+
+@item Bit 3 (8)
+ Perform constant propagation (@pxref{Constant Propagation}).
+ This can be done globally or only within basic blocks
+ depending on bit 5.
+
+@item Bit 4 (16)
+ Perform dead code elimination (@pxref{Dead Code Elimination}).
+
+
+@item Bit 5 (32)
+ Some optimizations are available in local and global versions. This
+ flag turns on the global versions. Several major optimizations
+ will not be performed and only one optimization pass is done unless
+ this flag is set.
+
+@item Bit 6 (64)
+ Reserved.
+
+@item Bit 7 (128)
+ @command{vbcc} will try to identify loops and perform some loop optimizations.
+ See @ref{Strength Reduction} and @ref{Loop-Invariant Code Motion}.
+ These only work if bit 5 (32) is set.
+
+
+@item Bit 8 (256)
+ @command{vbcc} tries to place variables at the same memory addresses if possible
+ (see @ref{Unused Object Elimination}).
+
+
+@item Bit 9 (512)
+ Reserved.
+
+@item Bit 10 (1024)
+ Pointers are analyzed and more precise alias-information is generated
+ (@pxref{Alias Analysis}).
+ Using this information, better data-flow analysis is possible.
+
+ Also, @command{vbcc} tries to place global/static variables and variables which
+ have their address taken in registers, if possible
+ (@pxref{Register Allocation}).
+
+
+@item Bit 11 (2048)
+ More aggressive loop optimizations are performed (see
+ @ref{Loop Unrolling} and @ref{Induction Variable Elimination}).
+ Only works if bit 5 (32) and bit 7 (128) are set.
+
+@item Bit 12 (4096)
+ Perform function inlining (@pxref{Function Inlining}).
+
+@item Bit 13 (8192)
+ Reserved.
+
+@item Bit 14 (16384)
+ Perform inter-procedural analysis (@pxref{Inter-Procedural Analysis})
+ and cross-module optimizations (@pxref{Cross-Module Optimizations}).
+
+@end table
+
+ Also look at the documentation for the target-dependent part of @command{vbcc}.
+ There may be additional machine specific optimization options.
+
+
+@node Register Allocation
+@subsection Register Allocation
+
+This optimization tries to assign variables or temporaries into machine
+registers to save time and space. The scope and details of this optimization
+vary on the optimization level.
+
+With @option{-O0} only temporaries during expression-evaluation are put
+into registers. This may be useful for debugging.
+
+At the default level (without the optimizer), additionally local variables
+whose address has not been taken may be put into registers for a whole
+function. The decision which variables to assign to registers is based
+on very simple heuristics.
+
+In optimizing compilation a different algorithm will be used which uses
+hierarchical live-range-splitting. This means that variables may be assigned
+to different registers at different time. This typically allows to put the
+most used variables into registers in all inner loops. Note that this
+means that a variable can be located in different registers at different
+locations. Most debuggers can not handle this.
+
+Also, the use of
+registers can be guided by information provided by the backend, if
+available. For architectures which are not very orthogonal this allows
+to choose registers which are better suited to certain operations.
+Constants can also be assigned to registers, if this is beneficial for
+the architecture.
+
+The options @option{-speed} and @option{-size} change the behaviour of the
+register-allocator to optimize for speed or size of the generated code.
+
+On low optimization levels, only local variables whose address has not
+been taken will be assigned to registers. On higher optimization levels,
+@command{vbcc} will also try to assign global/static variables and variables which
+had their address taken, to registers. Typically, this occurs during
+loops. The variables will be loaded into a register before entering a loop
+and stored back after the loop. However, this can only be done if @command{vbcc}
+can detect that the variable is not modified in unpredictable ways.
+Therefore, alias-analysis is crucial for this optimization.
+
+During register-allocation @command{vbcc} will use information on
+register usage of functions to minimize loading/saving of registers between
+function-calls. Therefore, other optimizations will affect register
+allocation.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Flow Optimizations
+@subsection Flow Optimizations
+
+When optimizing @command{vbcc} will construct a flowgraph for every function and
+perform optimizations based on control-flow. For example, code which is
+unreachable will be removed and branches to other branches or branches
+around branches will be simplified.
+
+Also, unused labels will be removed and basic blocks united to allow further
+optimizations.
+
+For example, the following code
+
+@example
+void f(int x, int y)
+@{
+ if(x > y)
+ goto label1;
+ q();
+label1:
+ goto label2;
+ r();
+label2:
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int x, int y)
+@{
+ if(x <= y)
+ q();
+@}
+@end example
+
+Identical code at the beginning or end of basic blocks will be moved to
+the successors/predecessors under certain conditions.
+
+
+@node Common Subexpression Elimination
+@subsection Common Subexpression Elimination
+
+If an expression has been computed on all paths leading to a second
+evaluation and @command{vbcc} knows that the operands have not been changed,
+then the result of the original evaluation will be reused instead of
+recomputing it. Also, memory operands will be loaded into registers and
+reused instead of being reloaded, if possible.
+
+For example, the following code
+
+@example
+void f(int x, int y)
+@{
+ q(x * y, x * y);
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int x, int y)
+@{
+ int tmp;
+
+ tmp = x * y;
+ q(tmp, tmp);
+@}
+@end example
+
+Depending on the optimization level, @command{vbcc} will perform this optimization
+only locally within basic blocks or globally across an entire function.
+
+As this optimization requires detecting whether operand of an expression
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Copy Propagation
+@subsection Copy Propagation
+
+If a variable is assigned to another one, the original variable will be
+used as long as it is not modified. This is especially useful in
+conjunction with other optimizations, e.g. common subexpression elimination.
+
+For example, the following code
+
+@example
+int y;
+
+int f()
+@{
+ int x;
+ x = y;
+ return x;
+@}
+@end example
+
+will be optimized like:
+
+@example
+int y;
+
+int f()
+@{
+ return y;
+@}
+@end example
+
+Depending on the optimization level, @command{vbcc} will perform this optimization
+only locally within basic blocks or globally across an entire function.
+
+As this optimization requires detecting whether a variable
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Constant Propagation
+@subsection Constant Propagation
+
+If a variable is known to have a constant value (this includes addresses
+of objects) at some use, it will be replaced by the constant.
+
+For example, the following code
+
+@example
+int f()
+@{
+ int x;
+ x = 1;
+ return x;
+@}
+@end example
+
+will be optimized like:
+
+@example
+int f()
+@{
+ return 1;
+@}
+@end example
+
+Depending on the optimization level, @command{vbcc} will perform this optimization
+only locally within basic blocks or globally across an entire function.
+
+As this optimization requires detecting whether a variable
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Dead Code Elimination
+@subsection Dead Code Elimination
+
+If a variable is assigned a value which is never used (either because it
+is overwritten or its lifetime ends), the assignment will be removed.
+This optimization is crucial to remove code which has become dead due
+to other optimizations.
+
+For example, the following code
+
+@example
+int x;
+
+void f()
+@{
+ int y;
+ x = 1;
+ y = 2;
+ x = 3;
+@}
+@end example
+
+will be optimized like:
+
+@example
+int x;
+
+void f()
+@{
+ x = 3;
+@}
+@end example
+
+As this optimization requires detecting whether a variable
+may be read, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+@node Loop-Invariant Code Motion
+@subsection Loop-Invariant Code Motion
+
+If the operands of a computation within a loop will not change
+during iterations, the computation will be moved outside of the
+loop.
+
+For example, the following code
+
+@example
+void f(int x, int y)
+@{
+ int i;
+
+ for (i = 0; i < 100; i++)
+ q(x * y);
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int x, int y)
+@{
+ int i, tmp = x * y;
+
+ for (i = 0; i < 100; i++)
+ q(tmp);
+@}
+@end example
+
+As this optimization requires detecting whether operands of an expression
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Strength Reduction
+@subsection Strength Reduction
+
+This is an optimization applied to loops in order to replace more costly
+operations (usually multiplications) by cheaper ones (typically additions).
+Linear functions of an induction variable (a variable which is changed by
+a loop-invariant value in every iteration) will be replaced by new
+induction variables. If possible, the original induction variable will be
+eliminated.
+
+As array accesses are actually composed of multiplications and additions,
+they often benefit significantly by this optimization.
+
+For example, the following code
+
+@example
+void f(int *p)
+@{
+ int i;
+
+ for (i = 0; i < 100; i++)
+ p[i] = i;
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int *p)
+@{
+ int i;
+
+ for (i = 0; i < 100; i++)
+ *p++ = i;
+@}
+@end example
+
+As this optimization requires detecting whether operands of an expression
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Induction Variable Elimination
+@subsection Induction Variable Elimination
+
+If an induction variable is only used to determine the number of
+iterations through the loop, it will be removed. Instead, a new variable
+will be created which counts down to zero. This is generally faster
+and often enables special decrement-and-branch or decrement-and-compare
+instructions.
+
+For example, the following code
+
+@example
+void f(int n)
+@{
+ int i;
+
+ for (i = 0; i < n; i++)
+ puts("hello");
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int n)
+@{
+ int tmp;
+
+ for(tmp = n; tmp > 0; tmp--)
+ puts("hello");
+
+@}
+@end example
+
+As this optimization requires detecting whether operands of an expression
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Loop Unrolling
+@subsection Loop Unrolling
+
+@command{vbcc} reduces the loop overhead by replicating the loop body
+and reducing the number of iterations. Also, additional optimizations between
+different iterations of the loop will often be enabled by creating larger
+basic blocks. However, code-size as well as compilation-times can
+increase significantly.
+
+This optimization can be controlled by @option{-unroll-size} and
+@option{-unroll-all}. @option{-unroll-size} specifies the maximum number
+of intermediate instructions for the unrolled loop body. @command{vbcc} will try
+to unroll the loop as many times to suit this value.
+
+If the number of iterations is constant and the size of the loop body
+multiplied by this number is less or equal to the value specified by
+@option{-unroll-size}, the loop will be unrolled completely. If
+the loop is known to be executed exactly once, it will always be unrolled
+completely.
+
+For example, the following code
+
+@example
+void f()
+@{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ q(i);
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f()
+@{
+ q(0);
+ q(1);
+ q(2);
+ q(3);
+@}
+@end example
+
+If the number of iteration is constant the loop will be unrolled as many
+times as permitted by the size of the loop and @option{-unroll-size}. If the
+number of iterations is not a multiple of the number of replications, the
+remaining iterations will be unrolled separately.
+
+For example, the following code
+
+@example
+void f()
+@{
+ int i;
+
+ for (i = 0; i < 102; i++)
+ q(i);
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f()
+@{
+ int i;
+ q(0);
+ q(1);
+ for(i = 2; i < 102;)@{
+ q(i++);
+ q(i++);
+ q(i++);
+ q(i++);
+ @}
+@}
+@end example
+
+By default, only loops with a constant number of iterations will be
+unrolled. However, if @option{-unroll-all} is specified, @command{vbcc} will also
+unroll loops if the number of iterations can be calculated at entry to
+the loop.
+
+For example, the following code
+
+@example
+void f(int n)
+@{
+ int i;
+
+ for (i = 0; i < n; i++)
+ q(i);
+@}
+@end example
+
+will be optimized like:
+
+@example
+void f(int n)
+@{
+ int i, tmp;
+
+ i = 0;
+ tmp = n & 3;
+ switch(tmp)@{
+ case 3:
+ q(i++);
+ case 2:
+ q(i++);
+ case 1:
+ q(i++);
+ @}
+ while(i < n)@{
+ q(i++);
+ q(i++);
+ q(i++);
+ q(i++);
+ @}
+@}
+@end example
+
+As this optimization requires detecting whether operands of an expression
+may have changed, it will be affected by other optimizations.
+See @ref{Alias Analysis}, @ref{Inter-Procedural Analysis} and
+@ref{Cross-Module Optimizations}.
+
+
+@node Function Inlining
+@subsection Function Inlining
+
+To reduce the overhead, a function call can be expanded inline. Passing
+parameters can be optimized as the arguments can be directly accessed
+by the inlined function. Also, further optimizations are enabled, e.g.
+constant arguments can be evaluated or common subexpressions between
+the caller and the callee can be eliminated. An inlined function call is
+as fast as a macro. However (just as with using large macros), code size and
+compilation time can increase significantly.
+
+Therefore, this optimization can be controlled with @option{-inline-size} and
+@option{-inline-depth}. @command{vbcc} will only inline functions which contain
+less intermediate instructions than specified with this option.
+
+For example, the following code
+
+@example
+int f(int n)
+@{
+ return q(&n,1);
+@}
+
+void q(int *x, int y)
+@{
+ if(y > 0)
+ *x = *x + y;
+ else
+ abort();
+@}
+@end example
+
+will be optimized like:
+
+@example
+int f(int n)
+@{
+ return n + 1;
+@}
+
+void q(int *x, int y)
+@{
+ if(y > 0)
+ *x = *x + y;
+ else
+ abort();
+@}
+@end example
+
+If a function to be inlined calls another function, that function can also be
+inlined. This also includes a recursive call of the function.
+
+For example, the following code
+
+@example
+int f(int n)
+@{
+ if(n < 2)
+ return 1;
+ else
+ return f(n - 1) + f(n - 2);
+@}
+@end example
+
+will be optimized like:
+
+@example
+int f(int n)
+@{
+ if(n < 2)
+ return 1;
+ else@{
+ int tmp1 = n - 1, tmp2, tmp3 = n - 2, tmp4;
+ if(tmp1 < 2)
+ tmp2 = 1;
+ else
+ tmp2 = f(tmp1 - 1) + f(tmp2 - 2);
+ if(tmp3 < 2)
+ tmp4 = 1;
+ else
+ tmp4 = f(tmp3 - 1) + f(tmp3 - 2);
+ return tmp2 + tmp4;
+ @}
+@}
+@end example
+
+By default, only one level of inlining is done. The maximum nesting of
+inlining can be set with @option{-inline-depth}. However, this option
+should be used with care. The code-size can increase very fast and in
+many cases the code will be slower. Only use it for fine-tuning after
+measuring if it is really beneficial.
+
+
+At lower optimization levels a function must be defined in the same
+translation-unit as the caller to be inlined. With cross-module
+optimizations, @command{vbcc} will also inline functions which are defined in
+other files. @xref{Cross-Module Optimizations}.
+
+
+See also @ref{Inline-Assembly Functions}.
+
+
+
+@node Intrinsic Functions
+@subsection Intrinsic Functions
+
+This optimization will replace calls to some known functions
+(usually library functions) with calls to different functions or
+special inline-code. This optimization usually depends on the
+arguments to a function. Typical candidates are the @code{printf}
+family of functions and string-functions applied to string-literals.
+
+For example, the following code
+
+@example
+int f()
+@{
+ return strlen("vbcc");
+@}
+@end example
+
+will be optimized like:
+
+@example
+int f()
+@{
+ return 4;
+@}
+@end example
+
+Note that there are also other possibilities of providing specially
+optimized library functions. See @ref{Inline-Assembly Functions} and
+@ref{Function Inlining}.
+
+
+@node Unused Object Elimination
+@subsection Unused Object Elimination
+
+Depending on the optimization level, @command{vbcc} will try to eliminate different
+objects and reduce the size needed for objects.
+
+Generally, @command{vbcc} will try to use common storage for local non-static variables
+with non-overlapping live-ranges .
+
+At some optimization levels and with @option{-size} specified, @command{vbcc} will try to
+order the placement of variables with static storage-duration to minimize
+padding needed due to different alignment requirements. This optimization
+generally benefits from an increased scope of optimization.
+@xref{Cross-Module Optimizations}.
+
+At higher optimization levels objects and functions which are not
+referenced are eliminated. This includes functions which have always
+been inlined or variables which have always been replaced by constants.
+
+When using separate compilation, objects and functions with external
+linkage usually cannot be eliminated, because they might be referenced
+from other translation-units. This precludes also elimination of anything
+referenced by such an object or function.
+
+However, unused objects and functions with
+external linkage can be eliminated if @option{-final} is specified.
+In this case @command{vbcc} will assume that basically the entire program is presented
+and eliminate everything which is not referenced directly or indirectly
+from main(). If some objects are not referenced but must not be
+eliminated, they have to be declared with the @code{__entry} attribute.
+Typical examples are callback functions which are called from a library
+function or from anywhere outside the program, interrupt-handlers or
+other data which should be preserved.
+@xref{Cross-Module Optimizations}.
+
+
+
+@node Alias Analysis
+@subsection Alias Analysis
+
+Many optimizations can only be done if it is known that two expressions
+are not aliased, i.e. they do not refer to the same object.
+If such information is not available, worst-case assumptions have to be
+made in order to create correct code. In the C
+language aliasing can occur by use of pointers. As pointers are generally
+a very frequently used feature of C and also array accesses are just
+disguised pointer arithmetic, alias analysis is very important.
+
+@command{vbcc} uses the following methods to obtain aliasing information:
+
+@itemize @minus
+@item The C language does not allow accessing an object using an lvalue
+ of a different type. Exceptions are accessing an object using a
+ qualified version of the same type and accessing an object using
+ a character type. In the following example @code{p1} and @code{p2}
+ must not point to the same object:
+
+@example
+f(int *p1, long *p2)
+@{
+ ...
+@}
+@end example
+
+ @command{vbcc} will assume that the source is correct and does not break
+ this requirement of the C language. If a program does break this
+ requirement and cannot be fixed, then @code{-no-alias-opt} must be
+ specified and some performance will be lost.
+
+@item At higher optimization levels, @command{vbcc} will try to keep track of all
+ objects a pointer can point to. In the following example, @command{vbcc}
+ will see that @code{p1} can only point to @code{x} or @code{y}
+ whereas @code{p2} can only point to @code{z}. Therefore it
+ knows that @code{p1} and @code{p2} are not aliased.
+
+@example
+int x[10], y[10], z[10];
+
+int f(int a, int b, int c)
+@{
+ int *p1, *p2;
+
+ if(a < b)
+ p1 = &x[a];
+ else
+ p1 = &y[b];
+
+ p2 = &z[c];
+
+ ...
+@}
+@end example
+
+ As pointers itself may be aliased and function calls might
+ modify pointers, this analysis sometimes benefits from a larger
+ scope of optimization.
+ See @ref{Inter-Procedural Analysis} and
+ @ref{Cross-Module Optimizations}.
+
+ This optimization will alter the behaviour of broken code which uses
+ pointer arithmetic to step from one object into another.
+
+@item The 1999 C standard provides the @code{restrict}-qualifier to help
+ alias analysis. If a pointer is declared with this qualifier, the
+ compiler may assume that the object pointed to by this pointer is
+ only aliased by pointers which are derived from this pointer.
+ For a formal definition of the rules for @code{restrict} please
+ consult ISO/IEC9899:1999.
+
+ @command{vbcc} will make use of this information at higher optimization
+ levels (@option{-c99} must be used to use this new keyword).
+
+ A very useful application for @code{restrict} are function
+ parameters. Consider the following example:
+
+@example
+void cross_prod(float *restrict res,
+ float *restrict x,
+ float *restrict y)
+@{
+ res[0] = x[1] * y[2] - x[2] * y[1];
+ res[1] = x[2] * y[0] - x[0] * y[2];
+ res[2] = x[0] * y[1] - x[1] * y[0];
+@}
+@end example
+
+ Without @code{restrict}, a compiler has to assume that writing the
+ results through @code{res} can modify the object pointed to by
+ @code{x} and @code{y}. Therefore, the compiler has to reload all
+ the values on the right side twice. With @code{restrict} @command{vbcc}
+ will optimize this code like:
+
+@example
+void cross_prod(float *restrict res,
+ float *restrict x,
+ float *restrict y)
+@{
+ float x0 = x[0], x1 = x[1], x2 = x[2];
+ float y0 = y[0], y1 = x[1], y2 = y[2];
+
+ res[0] = x1 * y2 - x2 * y1;
+ res[1] = x2 * y0 - x0 * y2;
+ res[2] = x0 * y1 - x1 * y0;
+@}
+@end example
+
+
+@end itemize
+
+
+@node Inter-Procedural Analysis
+@subsection Inter-Procedural Analysis
+
+Apart from the number of different optimizations a compiler offers, another
+important point is the scope of the underlying analysis. If a compiler only
+looks at small parts of code when deciding whether to do an optimization,
+it often cannot prove that a transformation does not change the
+behaviour and therefore has to reject it.
+
+Simple compilers only look at single expressions, simple optimizing
+compilers often restrict their analysis to basic blocks or extended basic
+blocks. Analyzing a whole function is common in today's optimizing compilers.
+
+This already allows many optimizations but often worst-case assumptions
+have to be made when a function is called.
+To avoid this, @command{vbcc} will not restrict its analysis to single functions
+at higher optimization levels. Inter-procedural data-flow analysis often
+allows for example to eliminate more common subexpressions or dead code.
+Register allocation and many other optimizations also sometimes benefit
+from inter-procedural analysis.
+
+Further extension of the scope of optimizations is possible by activating
+cross-module optimizations. @xref{Cross-Module Optimizations}.
+
+
+@node Cross-Module Optimizations
+@subsection Cross-Module Optimizations
+
+Separate compilation has always been an important feature of the C language.
+Splitting up an application into several modules does not only reduce
+turn-around times and resource-requirements for compilation, but it also
+helps writing reusable well-structured code.
+
+However, an optimizer has much more possibilities when it has access to the
+entire source code. In order to provide maximum possible optimizations
+without sacrificing structure and modularity of code, @command{vbcc} can do
+optimizations across different translation-units. Another benefit is
+that cross-module analysis also will detect objects which are declared
+inconsistently in different translation-units.
+
+Unfortunately common object-code does not contain enough information to
+perform aggressive optimization, To overcome this problem, @command{vbcc} offers
+two solutions:
+
+@itemize @minus
+@item If cross-module optimizations are enabled and several files are
+ passed to @command{vbcc}, it will read in all files at once, perform
+ optimizations across these files and generate a single object
+ file as output. This file is similar to what would have been
+ obtained by separately compiling the files and linking the
+ resulting objects together.
+
+@item The method described above often requires changes in makefiles and
+ somewhat different handling. Therefore @command{vbcc} also provides means
+ to generate some kind of special pseudo object files which pretain
+ enough high-level information to perform aggressive optimizations
+ at link time.
+
+ If @option{-wpo} is specified (which will automatically be done by
+ @command{vc} at higher optimization levels) @command{vbcc} will generate such files
+ rather than normal assembly or object files. These files can
+ not be handled by normal linkers. However, @command{vc} will detect these
+ files and before linking it will pass all such files to @command{vbcc} again.
+ @command{vbcc} will optimize the entire code and generate real code which
+ is then passed to the linker.
+
+ It is possible to pass @command{vc} a mixture of real and pseudo object
+ files. @command{vc} will detect the pseudo objects, compile them and link
+ them together with the real objects. Obviously, @command{vc} has to be used
+ for linking. Directly calling the linker with pseudo objects will
+ not work.
+
+ Please note that optimization and code generation is deferred to
+ link-time. Therefore, all compiler options related to optimization and
+ code generation have to be specified at the linker command as well.
+ Otherwise they would be ignored. Other options (e.g. setting paths
+ or defining macros) have to be specified when compiling.
+
+ Also, turn-around times will obviously increase as usually everything
+ will be rebuild even if makefiles are used. While only the
+ corresponding pseudo object may be rebuilt if one file is changed,
+ all the real work will be done at the linking stage.
+
+@end itemize
+
+@node Instruction Scheduling
+@subsection Instruction Scheduling
+
+Some backends provide an instruction scheduler which is automatically run
+by @command{vc} at higher optimization levels. The purpose is to reorder
+instructions to make better use of the different pipelines a CPU may
+offer.
+
+The exact details depend heavily on the backend, but in general the
+scheduler will try to place instructions which can be executed in parallel
+(e.g. on super-scalar architectures) close to each other. Also,
+instructions which depend on the result of another instruction will be
+moved further apart to avoid pipeline-stalls.
+
+Please note that it may be crucial to specify the correct derivate of a
+CPU family in order to get best results from the sceduler. Different
+variants of an architecture may have a different number and behaviour of
+pipelines requiring different scheduling decisions.
+
+Consult the backend documentation for details.
+
+
+@node Target-Specific Optimizations
+@subsection Target-Specific Optimizations
+
+In addition to those optimzations which are available for all targets,
+every backend will provide a series of additional optimizations. These
+vary between the different backends, but optimizations frequently done by
+backends are:
+
+@itemize @minus
+@item use of complex or auto-increment addressing-modes
+@item implicit setting of condition-codes
+@item instruction-combining
+@item delayed popping of stack-slots
+@item optimized function entry- and exit-code
+@item elimination of a frame pointer
+@item optimized multiplication/division by constants
+@item inline code for block-copying
+@end itemize
+
+
+
+@node Debugging Optimized Code
+@subsection Debugging Optimized Code
+
+Debugging of optimized code is usually not possible without problems.
+Many compilers turn off almost all optimizations when debugging.
+@command{vbcc} allows debugging output together with optimizations and
+tries to still do all optimizations (some restrictions have to be made
+regarding instruction-scheduling).
+
+However, depending on the debugger and debugging-format used, the
+information displayed in the debugger may differ from the real
+situation. Typical problems are:
+
+@itemize @minus
+
+@item Incorrectly displayed values of variables.
+
+ When optimizing vbcc will often remove certain variables or
+ eliminate code which sets them. Sometimes it is possible, to
+ tell the debugger that a variable has been optimized away, but
+ most of the time the debugger does not allow this and you
+ will just get bogus values when trying to inspect a variable.
+
+ Also, variables whose locations differs at various locations
+ of the program (e.g. a variable is in a register at one place
+ and in memory at another) can only be correctly displayed, if
+ the debugger supports this.
+
+ Sometimes, this can even occur in non-optimized code (e.g.
+ with register-parameters or a changing stack-pointer).
+
+@item Strange program flow.
+
+ When stepping through a program, you may see lines of code
+ be executed out-of-order or parts of the code skipped. This
+ often occurs due to code being moved around or eliminated/combined.
+
+@item Missed break-points.
+
+ Setting break-points (especially on source-lines) needs some
+ care when optimized code is debugged. E.g. code may have been
+ moved or even replicated at different parts. A break-point
+ set in a debugger will usually only be set on one instance of
+ the code. Therefore, a different instance of the code may have been
+ executed although the break-point was not hit.
+
+@end itemize
+
+@node Extensions
+@section Extensions
+
+This section lists and describes all extensions to the C language provided
+by @command{vbcc}. Most of them are implemented in a way which does not break
+correct C code and still allows all diagnostics required by the C standard
+by using reserved identifiers.
+
+The only exception (@pxref{Inline-Assembly Functions}) can be turned off
+using @option{-iso} or @option{-ansi}.
+
+@subsection Pragmas
+
+ @command{vbcc} accepts the following @code{#pragma}-directives:
+
+@table @code
+
+ @item #pragma printflike <function>
+ @itemx #pragma scanflike <function>
+ @command{vbcc} will handle @code{<function>} specially.
+ @code{<function>} has to be an already declared
+ function, with external linkage, that
+ takes a variable number of arguments
+ and a @code{const char *} as the last fixed
+ parameter.
+
+ If such a function is called with a
+ string-constant as format-string, @command{vbcc}
+ will check if the arguments seem to
+ match the format-specifiers in the
+ format-string, according to the rules
+ of printf or scanf.
+ Also, @command{vbcc} will replace the call by a
+ call to a simplified version according
+ to the following rules, if such a
+ function has been declared with external
+ linkage:
+
+@itemize @minus
+ @item If no format-specifiers are used at all,
+ @code{__v0<function>} will be called.
+
+ @item If no qualifiers are used and only
+ @code{d,i,x,X,o,s,c} are used, @code{__v1<function>}
+ will be called.
+
+ @item If no floating-point arguments are used,
+ @code{__v2<function>} will be called.
+@end itemize
+
+ @item #pragma dontwarn <n>
+ Disables warning number n. Must be followed by @code{#pragma popwarn}.
+
+ @item #pragma warn <n>
+ Enables warning number n. Must be followed by @code{#pragma popwarn}.
+
+ @item #pragma popwarn
+ Undoes the last modification done by @code{#pragma warn} or
+ @code{#pragma dontwarn}.
+
+ @item #pragma only-inline on
+ The following functions will be parsed and are available for
+ inlining (@pxref{Function Inlining}), but no out-of-line code
+ will be generated, even if some calls could not be inlined.
+
+ Do not use this with functions that have
+ local static variables!
+
+ @item #pragma only-inline off
+ The following functions are translated
+ as usual again.
+
+ @item #pragma opt <n>
+ Sets the optimization options to <n>
+ (similar to -O=<n>) for the following
+ functions.
+ This is only used for debugging purposes. Do not use!
+
+ @item #pragma begin_header
+ Used to mark the beginning of a system-header. Must be followed
+ by @code{#pragma end_header}. Not for use in applications!
+
+ @item #pragma end_header
+ The counterpart to @code{#pragma begin_header}. Marks the end
+ of a system-header. Not for use in applications!
+
+ @item #pragma pack(n)
+ Set alignment of structure members to a multiple of @code{n} bytes.
+
+ @item #pragma pack()
+ Restores structure alignment to the target's default alignment,
+ which was in effect when the compilation started.
+
+ @item #pragma pack(push[,n])
+ Pushes the current structure alignment onto an internal stack and
+ optionally sets a new alignment to a multiple of @code{n} bytes.
+
+ @item #pragma pack(pop)
+ Restores the topmost structure alignment, saved by @code{pack(push)},
+ from an internal stack. Restores the default alignment, when the
+ stack is empty.
+
+@end table
+
+
+@subsection Register Parameters
+
+ If the parameters for certain functions should be passed in certain
+ registers, it is possible to specify the registers using
+ @code{__reg("<reg>")} in the
+ prototype, e.g.
+
+@example
+ void f(__reg("d0") int x, __reg("a0") char *y) @{ ... @}
+@end example
+
+ The names of the available registers depend on the backend and will
+ be listed in the corresponding part of the documentation.
+ Note that a matching prototype must be in scope when calling such
+ a function - otherwise wrong code will be generated.
+ Therefore it is not useful to use register parameters in an old-style
+ function-definition.
+
+ If the backend cannot handle the specified register for a
+ certain type, this will cause an error. Note that this may happen
+ although the register could store that type, if the backend
+ does not provide the necessary support.
+
+ Also note that this may force @command{vbcc} to create worse code.
+
+
+@node Inline-Assembly Functions
+@subsection Inline-Assembly Functions
+
+ Only use them if you know what you are doing!
+
+ A function-declaration may be followed by '=' and a string-constant.
+ If a function is called with such a declaration in scope, no
+ function-call will be generated but the string-constant will be
+ inserted in the assembly-output.
+ Otherwise the compiler and optimizer will treat this like a
+ function-call, i.e. the inline-assembly must not modify any callee-save
+ registers without restoring them. However, it is also possible to
+ specify the side-effects of inline-assembly functions like
+ registers used or variables used and modified
+ (@pxref{Specifying side-effects}).
+
+ Example:
+
+@example
+ double sin(__reg("fp0") double) = "\tfsin.x\tfp0\n";
+@end example
+
+ There are several issues to take care of when writing inline-assembly.
+
+@itemize @minus
+@item As inline-assembly is subject to loop unrolling or function inlining
+ it may be replicated at different locations. Unless it is absolutely
+ known that this will not happen, the code should not define any
+ labels (e.g. for branches). Use offsets instead.
+
+@item If a backend provides an instruction scheduler, inline-assembly code
+ will also be scheduled. Some schedulers make assumptions about
+ their input (usually compiler-generated code) to improve the
+ code. Have a look at the backend documentation to see if there
+ are any issues to consider.
+
+@item If a backend provides a peephole optimizer which optimizes the
+ assembly output, inline-assembly code will also be optimized
+ unless @option{-no-inline-peephole} is specified.
+ Have a look at the backend documentation to see if there are any
+ issues to consider.
+
+@item @command{vbcc} assumes that inline-assembly does not introduce any new
+ control-flow edges. I.e. control will only enter inline-assembly
+ if the function call is reached and if control leaves
+ inline-assembly it will continue after the call.
+
+@end itemize
+
+ Inline-assembly-functions are not recognized when ANSI/ISO mode is
+ turned on.
+
+
+@node Variable Attributes
+@subsection Variable Attributes
+
+ @command{vbcc} offers attributes to variables or functions. These attributes
+ can be specified at the declaration of a variable or function and
+ are syntactically similar to storage-class-specifiers
+ (e.g. @code{static}).
+
+ Often, these attributes are specific to one backend and will be
+ documented in the backend-documentation (typical attributes would
+ e.g. be @code{__interrupt} or @code{__section}). Attributes may
+ also have parameters. A generally available
+ attribute s @code{__entry} which is used to preserve unreferenced
+ objects and functions (@pxref{Unused Object Elimination}):
+
+@example
+__entry __interrupt __section("vectab") void my_handler()
+@end example
+
+ Additional non-target-specific attributes are available to
+ specify side-effects of functions (@pxref{Specifying side-effects}).
+
+
+ Please note that some common extensions like @code{__far} are
+ variable attributes on some architectures, but actually type
+ attributes (@pxref{Type Attributes}) on others. This is due to
+ significantly different meanings on different architectures.
+
+
+@node Type Attributes
+@subsection Type Attributes
+
+ Types may be qualified by additional attributes, e.g. @code{__far},
+ on some backends. Regarding the availability of type attributes
+ please consult the backend documentation.
+
+ Syntactically type attributes have to be placed like a type-qualifier
+ (e.g. @code{const}).
+ As example, some backends know the attribute @code{__far}.
+
+ Declaration of a pointer to a far-qualified character would be
+
+@example
+ __far char *p;
+@end example
+
+ whereas
+
+@example
+ char * __far p;
+@end example
+
+ is a far-qualified pointer to an unqualified char.
+
+ Please note that some common extensions like @code{__far} are
+ type attributes on some architectures, but actually variable
+ attributes (@pxref{Variable Attributes}) on others. This is due to
+ significantly different meanings on different architectures.
+
+@subsection @code{__typeof}
+
+ @code{__typeof} is syntactically equivalent to sizeof, but its result is of
+ type int and is a number representing the type of its argument.
+ This may be necessary for implementing @file{stdarg.h}.
+
+
+@subsection @code{__alignof}
+
+ @code{__alignof} is syntactically equivalent to sizeof, but its result is of
+ type int and is the alignment in bytes of the type of the argument.
+ This may be necessary for implementing @file{stdarg.h}.
+
+
+@subsection @code{__offsetof}
+
+ @code{__offsetof} is a builtin version of the @code{offsetof}-macro
+ as defined in the C language. The first argument is a structure
+ type and the second a member of the structure type. The result
+ will be a constant expression representing the offset of the
+ specified member in the structure.
+
+@node Specifying side-effects
+@subsection Specifying side-effects
+
+Only use if you know what you are doing!
+
+When optimizing and generating code, @command{vbcc} often has to take
+into account side-effects of function-calls, e.g. which registers might
+be modified by this function and what variables are read or modified.
+
+A rather imprecise way to make assumptions on side-effects is given by
+the ABI of a certain system (that defines which registers have to be
+preserved by functions) or rules derived from the language (e.g. local
+variables whose address has not been taken cannot be accessed by another
+function).
+
+On higher optimization levels (@pxref{Inter-Procedural Analysis} and
+@pxref{Cross-Module Optimizations})) @command{vbcc} will try to analyse
+functions and often gets much more precise informations regarding
+side-effects.
+
+However, if the source code of functions is not visible to @command{vbcc},
+e.g. because the functions are from libraries or they are
+written in assembly (@pxref{Inline-Assembly Functions}), it is obviously
+not possible to analyze the code. In this case, it is possible to specify
+these side-effects using the following special variable-attributes
+(@pxref{Variable Attributes}).
+
+The @code{__regsused(<register-list>)} attribute specifies the volatile
+registers used or modified by a function. The register list is a list of
+register names (as defined in the backend-documentation) separated by
+slashes and enclosed in double-quotes, e.g.
+
+@code{ __regsused("d0/d1") int abs();}
+
+declares a function @code{abs} which only uses registers @code{d0} and
+@code{d1}.
+
+@code{__varsmodified(<variable-list>)} specifies a list of variables with
+external linkage
+which are modified by the function. @code{__varsused} is similar, but
+specifies the external variables read by the function. If a variable is
+read and written, both attributes have to be specified. The variable-list
+is a list of identifiers, separated by slashes and enclosed in double
+quotes.
+
+The attribute @code{__writesmem(<type>)} is used to specify that the
+function accesses memory using a certain type. This is necessary if the
+function modifies memory accessible to the calling function which cannot
+be specified using @code{__varsmodified} (e.g. because it is accessed via
+pointers). @code{__readsmem} is similar, but specifies memory which is
+read.
+
+If one of @code{__varsused}, @code{varsmodified}, @code{__readsmem} and
+@code{__writesmem} is specified, all relevant side-effects must be
+specified. If, for example, only @code{__varsused("my_global")}
+is specified, this implies that the function only reads @code{my_global}
+and does not modify any variable accessible to the caller.
+
+All of these attributes may be specified multiple times.
+
+@subsection Automatic constructor/destructor functions
+
+The linker @command{vlink} provides a feature to collect pointers to
+all functions starting with the names @code{_INIT} or @code{_EXIT} in
+a prioritized array, labeled by @code{__CTOR_LIST__} and
+@code{__DTOR_LIST__}. The C-library (vclib) calls the constructor functions
+before entering @code{main()} and the destructor functions on program
+exit.
+
+The format of these special function names is:
+@example
+ void _INIT[_<pri>][_<name>](void)
+ void _EXIT[_<pri>][_<name>](void)
+@end example
+The optional priority @code{<pri>} may be a digit between 1 and 9, where
+a constructor with a priority of 1 is executed first while a destructor
+with a priority of 1 is executed last. @code{<name>} is an optional name,
+used to differentiate functions of the same level.
+
+@subsection @code{__noinline}
+
+@code{__noinline} will prevent inlining of a given function. The heuristic
+used for deciding whether a function should be inlined generally makes a good
+trade-off between code size and performance, but sometimes it can be useful to override
+this behaviour. Use-cases include keeping "cold" functions out-of line to reduce code
+size, or to allow safe use of inline assembly with labels.
+
+@subsection Predefined macros
+The following macros are defined by the compiler.
+@example
+ #define __VBCC__
+ #define __entry __vattr("entry")
+ #define __str(x) #x
+ #define __asm(x) do{static void inline_assembly()=x;inline_assembly();}while(0)
+ #define __regsused(x) __vattr("regused("x")")
+ #define __varsused(x) __vattr("varused("x")")
+ #define __varsmodified(x) __vattr("varchanged("x")")
+ #define __noreturn __vattr("noreturn()")
+ #define __alwaysreturn __vattr("alwaysreturn()")
+ #define __nosidefx __vattr("nosidefx()")
+ #define __stack(x) __vattr(__str(stack1(x)))
+ #define __stack2(x) __vattr(__str(stack2(x)))
+ #define __noinline __vattr("noinline()")
+ #define __STDC_VERSION__ 199901L
+@end example
+@code{__STDC_VERSION__} is defined in C99-mode only.
+
+@subsection Masked symbols
+Together with vlink, this feature allows to provide a family of specially tailored
+functions in a library.
+
+A symbol can be attached a mask using the @code{__mask} attribute, e.g.
+
+@example
+ __mask(15) void myfunc(void);
+@end example
+
+The symbol of this function will get the suffix @code{.15} attached.
+
+A reference to a masked symbol can either be created by vbcc itself when using the
+option @code{-mask-opt}, or manually by referencing a symbol prefixed with
+@code{__maskm_<mask>}.
+
+@example
+ extern __mask(15) void myfunc(void);
+ ...
+ __maskm_15_myfunc();
+@end example
+
+If there are several masked references to a symbol, the linker will pull the first
+symbol containing a mask that has at least all bits set that are set in any masked
+reference. If no masked symbols matching that requirement are available, the symbol
+without a mask is used. Also, a non-masked reference will only pull a non-masked
+symbol from a library.
+
+Masked objects may only be defined in libraries and zero masks are not allowed.
+
+
+@section Known Problems
+
+ Some known target-independent problems of @command{vbcc} at the moment:
+
+@itemize @minus
+
+ @item Some exotic scope-rules are not handled correctly.
+
+ @item Debugging-infos may have problems on higher optimization-levels.
+
+ @item String-constants are not merged (partially done).
+
+@end itemize
+
+@section Credits
+
+ All those who wrote parts of the @command{vbcc} distribution, made suggestions,
+ answered my questions, tested @command{vbcc}, reported errors or were otherwise
+ involved in the development of @command{vbcc} (in descending alphabetical order,
+ under work, not complete):
+
+@itemize
+ @item Frank Wille
+ @item Gary Watson
+ @item Andrea Vallinotto
+ @item Johnny Tevessen
+ @item Eero Tamminen
+ @item Gabriele Svelto
+ @item Dirk Stoecker
+ @item Ralph Schmidt
+ @item Markus Schmidinger
+ @item Thorsten Schaaps
+ @item Anton Rolls
+ @item Michaela Pruess
+ @item Thomas Pornin
+ @item Joerg Plate
+ @item Gilles Pirio
+ @item Bartlomiej Pater
+ @item Elena Novaretti
+ @item Gunther Nikl
+ @item Constantinos Nicolakakis
+ @item Timm S. Mueller
+ @item Robert Claus Mueller
+ @item Joern Maass
+ @item Aki M Laukkanen
+ @item Kai Kohlmorgen
+ @item Uwe Klinger
+ @item Andreas Kleinert
+ @item Julian Kinraid
+ @item Acereda Macia Jorge
+ @item Dirk Holtwick
+ @item Matthew Hey
+ @item Tim Hanson
+ @item Kasper Graversen
+ @item Jens Granseuer
+ @item Volker Graf
+ @item Marcus Geelnard
+ @item Franta Fulin
+ @item Matthias Fleischer
+ @item Alexander Fichtner
+ @item Olivier Fabre
+ @item Robert Ennals
+ @item Thomas Dorn
+ @item Walter Doerwald
+ @item Aaron Digulla
+ @item Lars Dannenberg
+ @item Sam Crow
+ @item Michael Bode
+ @item Michael Bauer
+ @item Juergen Barthelmann
+ @item Thomas Arnhold
+ @item Alkinoos Alexandros Argiropoulos
+ @item Thomas Aglassinger
+@end itemize
diff --git a/doc/vbccalpha.texi b/doc/vbccalpha.texi
new file mode 100755
index 0000000..a5e9e5c
--- /dev/null
+++ b/doc/vbccalpha.texi
@@ -0,0 +1,132 @@
+This chapter documents the Backend for the DEC Alpha processor family.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+
+ @item -merge-constants
+ Place identical floating point constants at the same
+ memory location. This can reduce program size and increase
+ compilation time.
+
+ @item -const-in-data
+ By default constant data will be placed in the code
+ section (and therefore is accessable with faster pc-relative
+ addressing modes). Using this option it will be placed in the
+ data section.
+ Note that on operating systems with memory protection this
+ option will disable write-protection of constant data.
+
+ @item -no-builtins
+ Do not replace certain builtin functions by inline code.
+ This may be useful if you use this code generator with
+ another frontend than vbcc.
+ stdarg.h will not work with -no-builtins.
+
+ @item -stabs
+ Generate stabs debug infos (if -g is specified) rather than
+ DWARF2 which is the default. Consider this obsolete.
+
+@end table
+
+@section ABI
+
+
+ This backend supports the following registers:
+
+ @itemize @minus
+ @item @code{$0} through @code{$31} for the general purpose registers and
+ @item @code{$f0} through @code{$f31} for the floating point registers.
+ @end itemize
+
+ The current version generates assembly output for use with the GNU
+ assembler. The generated code should work on systems with 21064,
+ 21066, 21164 and higher Alpha CPUs.
+
+ The registers @code{$0-$8, $16-$28, $f0, $f1} and @code{$f10-$f30}
+ are used as scratch registers (i.e. they can be destroyed in function
+ calls), all other registers are preserved. Of course @code{$31} and
+ @code{$f31} cannot be used.
+
+ The first 6 function arguments which have arithmetic or pointer types
+ are passed in registers @code{$16/$f16} through @code{$21/$f21}.
+
+ Integers and pointers are returned in @code{$0}, floats and doubles in
+ @code{$f0}.
+ All other types are returned by passing the function the address
+ of the result as a hidden argument - so when you call such a function
+ without a proper declaration in scope you can expect a crash.
+
+ The elementary data types are represented like:
+
+ @example
+ type size in bits alignment in bytes
+
+ char 8 1
+ short 16 2
+ int 32 4
+ long 64 8
+ long long 64 8
+ all pointers 64 8
+ float 32 4
+ double 64 8
+ @end example
+
+@section Predefined Macros
+
+ This backend defines the following macros:
+
+@table @code
+ @item __ALPHA__
+
+@end table
+
+
+@section Stdarg
+
+ A possible <stdarg.h> could look like this:
+
+@example
+
+ typedef struct @{
+ char *regbase;
+ char *membase;
+ int arg;
+ @} va_list;
+
+ char *__va_start(void);
+ int __va_fixargs(void);
+
+ #define va_start(vl,dummy) \
+ (vl.arg=__va_fixargs(),vl.regbase=__va_start(),vl.membase=vl.regbase+(6-vl.arg)*16)
+
+ #define va_end(vl) (vl.regbase=vl.membase=0)
+
+ #define __va_size(type) ((sizeof(type)+7)/8*8)
+ #define va_arg(vl,type) \
+ ( \
+ ((__typeof(type)&15)<=10&&++vl.arg<=6) ? \
+ ( \
+ ((__typeof(type)&15)>=6&&(__typeof(type)&15)<=8) ? \
+ (vl.regbase+=16,*(type *)(vl.regbase-8)) \
+ : \
+ (vl.regbase+=16,*(type *)(vl.regbase-16)) \
+ ) \
+ : \
+ (vl.membase+=__va_size(type),*(type *)(vl.membase-__va_size(type))) \
+ )
+
+@end example
+
+
+@section Known problems
+
+@itemize @minus
+ @item generated code is rather poor
+ @item several other problems
+@end itemize
+
+
diff --git a/doc/vbccc16x.texi b/doc/vbccc16x.texi
new file mode 100644
index 0000000..99be78e
--- /dev/null
+++ b/doc/vbccc16x.texi
@@ -0,0 +1,258 @@
+This chapter documents the Backend for the c16x/st10 microcontroller family.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+ @item -merge-constants
+ Place identical floating point constants at the same
+ memory location. This can reduce program size and increase
+ compilation time.
+
+ @item -const-in-data
+ By default constant data will be placed in a read-only
+ section. Using this option it will be placed in the
+ data section.
+
+ @item -no-delayed-popping
+ By default arguments of function calls are not always popped
+ from the stack immediately after the call, so that the
+ arguments of several calls may be popped at once.
+ With this option vbcc can be forced to pop them after every
+ function call.
+ This may simplify debugging and very slightly reduce the
+ stack size needed by the compiled program.
+
+ @item -no-peephole
+ Do not perform peephole-optimizations.
+
+ @item -tasking
+ Produce output for the Tasking assembler.
+
+ @item -mtiny
+ Assume all functions are within one code-segment.
+ Shorter instructions for calling functions are used and
+ function-pointers will be only 2 bytes long.
+ This results in shorter and faster code.
+
+ @item -mlarge
+ All objects which are not explicitly qualified are assumed
+ to be far (i.e. they may be in different segments but must
+ not cross one segment-boundary). The default pointer size
+ will be 4.
+
+ @item -mhuge
+ All objects which are not explicitly qualified are assumed
+ to be huge (i.e. they may be in different segments and may
+ cross segment-boundaries). The default pointer size will
+ be 4.
+
+ @item -int32
+ Do not use.
+@end table
+
+@section ABI
+
+ This backend supports the following registers:
+
+ @itemize @minus
+ @item @code{R0} through @code{R15} for the general purpose registers
+ @end itemize
+
+ Additionally, the register pairs
+ @code{R2/R3, R3/R4, R4/R5, R6/R7, R7/R8, R8/R9, R12/R13, R13/R14,}
+ and @code{R15/R15}
+ are available.
+
+ @code{R1, R11} and @code{R12} are reserved by the backend.
+
+ The current version generates assembly output for use with the vasm
+ assembler. Optionally, assembly code for the Tasking
+ assembler can be generated.
+ The default memory model corresponds to the Tasking small-memory
+ model with 16bit data-pointers and 32bit function-pointers.
+ However, the @code{DPPx} registers have to be set up in a way to
+ create a linear 16bit address space (i.e. @code{DPPx=x}).
+ The generated code should work on systems with c161, c163, c164, c165
+ and c167 microcontrollers as well as ST10 derivates. Old versions like
+ the c166 are not supported
+
+ The registers @code{R1-R5} and @code{R10-R15} are used as scratch registers (i.e. they
+ can be destroyed in function calls), all other registers are preserved.
+
+ @code{R0} is used as user stack pointer. Automatic variables and temporaries
+ are put on the user stack. Return addresses are pushed on the system
+ stack.
+
+ The first 4 function arguments which have integer or pointer types
+ are passed in registers @code{R12} through @code{R15}.
+
+ Integers and pointers are returned in @code{R4/R5}.
+ All other types are returned by passing the function the address
+ of the result as a hidden argument - so when you call such a function
+ without a proper declaration in scope you can expect a crash.
+
+ The elementary data types are represented like:
+
+ @example
+ type size in bits alignment in bytes
+
+ char 8 1
+ short 16 2
+ int 16 2
+ long 32 2
+ long long n/a n/a
+ near pointers 16 2
+ far pointers 32 2
+ huge pointers 32 2
+ float n/a n/a
+ double n/a n/a
+ @end example
+
+
+@section Target-specific variable-attributes
+
+ The c16x-backend offers the following variable attributes:
+
+@table @code
+
+ @item __interrupt
+ Return with rfi rather than blr.
+ @code{MDL/MDH} will be saved, however it is recommended
+ to switch to a new register bank as the gprs are
+ not saved.
+ Also, @code{DPP0-DPP3} are not saved (the compiler does not
+ use them).
+
+ @item __interrupt(<vector>)
+ Like @code{__interrupt}, but also places a jump-instruction
+ to the interrupt service at the corresponding vector table
+ address (needs support from library and linker file).
+
+ @item __section(<name>)
+ Place this object/function in section <name>.
+
+ @item __rbank(<bank>)
+ Switch to another register-bank for this function.
+@end table
+
+
+@section Target-specific type-attributes
+
+ The c16x-backend offers the following type attributes:
+
+@table @code
+ @item __near
+ Object resides within the same segment.
+
+ @item __far
+ Object may reside in a different segment, but does not cross
+ a segment-boundary.
+
+ @item __huge
+ Object may reside in a different segment and may cross a
+ segment-boundary
+
+ @item __section(<name>)
+ Place this function or object in section <name>.
+
+ @item __sfr(<addr>)
+ Used to declare a special function register at <addr>.
+
+ Example:
+ @example
+ __sfr(0xff10) volatile unsigned int PSW;
+ @end example
+
+ @item __esfr(<addr>)
+ The same for extended special function registers.
+
+ @item __sfrbit(<addr>,<bit>)
+ Declare a single bit in the bit-addressable area.
+
+ Example:
+ @example
+ __sfr(0xff10,11) volatile __bit IEN;
+ @end example
+
+ @item __esfrbit(<addr>,<bit>)
+ The same for the extended bit-addressable area.
+
+@end table
+
+@section Target-specific types
+
+ The c16x-backend offers the following additional types:
+
+@table @code
+ @item __bit
+ A single bit in the bit-addressable internal RAM-area.
+ Only static and external variables may use this type.
+ It is not allowed for auto or register storage-class.
+ Also, arrays of bits, pointers to bits or bits within
+ aggregates are not allowed.
+ Conversion of a bit to an integral type yields 0 if the
+ bit is cleared and 1 if it is set..
+ Conversion of an integral type to a bit clears the bit if
+ the integer is equal to 0 and sets it otherwise.
+@end table
+
+@section Predefined Macros
+
+ This backend defines the following macros:
+
+@table @code
+ @item __C16X__
+ @item __C167__
+ @item __ST10__
+@end table
+
+
+
+@section Stack
+
+ If the @option{-stack-check} option is used, every function-prologue will
+ call the function @code{__stack_check} with the stacksize needed by this
+ function in register @code{R1}. This function has to consider its own
+ stacksize and must restore all registers.
+
+ Only stack-checking of the user-stack is supported. Checking the
+ system-stack is supported by hardware.
+
+
+
+@section Stdarg
+
+ A possible <stdarg.h> could look like this:
+
+@example
+ typedef char *va_list;
+
+ va_list __va_start(void);
+
+ #define __va_rounded_size(__TYPE) \
+ (((sizeof (__TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
+
+ #define va_start(__AP,__LA) (__AP=__va_start())
+
+ #define va_arg(__AP, __TYPE) \
+ (__AP = ((char *) (__AP) + __va_rounded_size (__TYPE)), \
+ *((__TYPE *)((__AP) - __va_rounded_size (__TYPE))))
+
+ #define va_end(__AP) ((__AP) = 0)
+@end example
+
+
+@section Known Problems
+
+@itemize @minus
+ @item no floating-point
+ @item huge-pointers are sometimes derferenced as far-pointers
+ @item addressing-modes sometimes ignore huge
+ @item initialized data is placed in RAM, bits are not initialized
+ @item struct-copy only works with near-pointers
+ @item near/far-conversion assumes DPP0-DPP3 linear
+@end itemize
+
diff --git a/doc/vbcchc12.texi b/doc/vbcchc12.texi
new file mode 100755
index 0000000..c89224b
--- /dev/null
+++ b/doc/vbcchc12.texi
@@ -0,0 +1,163 @@
+This chapter documents the Backend for the 68hc12 and 6809/6309 microcontroller families.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+ @item -merge-constants
+ Place identical floating point constants at the same
+ memory location. This can reduce program size and increase
+ compilation time. (No fp support yet.)
+
+ @item -const-in-data
+ By default constant data will be placed in a read-only
+ section. Using this option it will be placed in the
+ data section.
+
+ @item -no-delayed-popping
+ By default arguments of function calls are not always popped
+ from the stack immediately after the call, so that the
+ arguments of several calls may be popped at once.
+ With this option vbcc can be forced to pop them after every
+ function call.
+ This may simplify debugging and very slightly reduce the
+ stack size needed by the compiled program.
+
+ @item -no-peephole
+ Do not perform peephole-optimizations.
+
+ @item -mem-cse
+ Try to hold values loaded from memory in registers and
+ reuse them. Due to the small register-set of the hc12
+ this is disabled by default as it increases register-
+ pressure and tends to spill to the stack.
+
+ @item -cpu=<n>
+ Specify the processor family. Currently supported values are:
+@itemize
+@item 6812: Generate code for the Motorola 68hc12 series (default).
+
+@item 6809: Generate code for the Motorola 6809 series.
+
+@item 6309: Generate code for the Hitachi 6309 series (currently identical to 6809).
+@end itemize
+
+
+ @item -acc-glob
+ Make the accumulator available for global register allocation.
+ By default, the accumulator will only be used for register allocation
+ within basic blocks. In many cases, global allocation will result in
+ worse code, because the accumulator has to be pushed/popped many times.
+
+ @item -pcrel
+ Generate PC-relative code. May not fully work with 68hc12.
+
+ @item -drel
+ Generate code that accesses data relative to register @code{u}. Does not
+ work with 68hc12.
+
+@end table
+
+@section ABI
+
+ The current version generates assembly output for use with vasm6809_std or the GNU
+ assembler using the non-banked model.
+
+ This backend supports the following registers:
+
+ @itemize @minus
+ @item @code{d} for the accumulator (also used for byte, i.e. @code{b})
+ @item @code{x} for index register x
+ @item @code{y} for index register y
+ @item @code{u} for index register u (not on 68hc12)
+ @item @code{sp} for the stack-pointer
+ @end itemize
+
+ The accumulator and @code{x} are caller-save. The @code{y} register is callee-save.
+ The @code{u} register is used as data-page pointer with @code{-drel}.
+
+ The first function argument which has integer or pointer type up to 16 bits
+ is passed in the accumulator @code{d}.
+ The remaining arguments are passed on the stack.
+
+ Integers and pointers are returned in @code{d} or @code{d/x} (@code{x} contains the higher bits).
+ All other types are returned by passing the function the address
+ of the result as a hidden argument - so when you call such a function
+ without a proper declaration in scope you can expect a crash.
+
+ The elementary data types are represented like:
+@example
+ type size in bits alignment in bytes
+
+ char 8 1
+ short 16 1
+ int 16 1
+ long 32 1
+ near pointers 16 1
+ far pointers 24 1 (not yet)
+ huge pointers 24 1 (not yet)
+ float 32 1 (not yet)
+ double 64 1 (not yet)
+ long double 64 1 (not yet)
+@end example
+
+
+@section Target-specific variable-attributes
+
+ The 6809/hc12-backend offers the following variable attributes:
+
+@table @code
+ @item __interrupt
+ Return with @code{rti} rather than @code{rts}.
+
+ @item __section("name","attr")
+ Place this function/object in section "section"
+ with attributes "attr".
+
+ @item __dpage
+ Place the variable in section @code{.dpage} and use direct addressing.
+
+@end table
+
+@section Predefined Macros
+
+ This backend defines the following macros:
+
+@table @code
+ @item __HC12__
+ If code for 68hc12 is generated.
+
+ @item __6809__
+ If code for 6809 is generated.
+
+ @item __6309__
+ If code for 6309 is generated.
+@
+@end table
+
+@section Stack
+
+ If the @option{-stack-check} option is used, every function-prologue will
+ call the function @code{__stack_check} with the stacksize needed by this
+ function in register @code{y}. This function has to consider its own
+ stacksize and must restore all registers.
+
+
+@section Stdarg
+
+ Stdarg is supported by the provided include.
+
+@section Known Problems
+
+@itemize @minus
+ @item Support for floating point and long long is still missing.
+ @item U register is not really used yet.
+ @item No support for 6309 extensions yet.
+ @item Many optimizations still missing.
+ @item Some code generation bugs to be fixed.
+
+@end itemize
+
+
diff --git a/doc/vbcci386.texi b/doc/vbcci386.texi
new file mode 100755
index 0000000..3d79d77
--- /dev/null
+++ b/doc/vbcci386.texi
@@ -0,0 +1,123 @@
+This chapter documents the Backend for the Intel i386 processor family.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+ @item -longalign
+ Align multibyte-values on 4-byte-boundaries. Needed by some
+ operating systems.
+
+ @item -elf
+ Do not use a '_'-prefix in front of external identifiers.
+ Use a '.'-prefix for label names.
+
+ @item -merge-constants
+ Place identical floating point constants at the same
+ memory location. This can reduce program size and increase
+ compilation time.
+
+ @item -const-in-data
+ By default constant data will be placed in a read-only
+ section. Using this option it will be placed in the data section
+ Note that on operating systems with memory protection this
+ option will disable write-protection of constant data.
+
+ @item -no-delayed-popping
+ By default arguments of function calls are not always popped
+ from the stack immediately after the call, so that the
+ arguments of several calls may be popped at once.
+ With this option vbcc can be forced to pop them after every
+ function call.
+ This may simplify debugging and very slightly reduce the
+ stack size needed by the compiled program.
+
+ @item -safe-fp
+ Do not use the floating-point-stack for register variables.
+ At the moment this is necessary as vbcci386 still has problems
+ in some cases otherwise.
+@end table
+
+
+@section ABI
+
+ This backend supports the following registers:
+
+ @itemize @minus
+ @item @code{%eax, %ebx, %ecx, %edx}
+ @item @code{%esi, %edi, %ebp, %esp}
+ @end itemize
+
+ (And @code{%st(0)-%st(7)} for the floating point stack but these must not
+ bes used for register variables because they cannot be handled like
+ normal registers.)
+
+ The current version generates assembly output for use with the GNU
+ assembler. The generated code should work on systems with Intel 80386
+ or higher CPUs with FPU and compatible chips.
+
+ The registers @code{%eax, %ecx} and @code{%edx} (as well as the floating point stack)
+ are used as scratch registers (i.e. they can be destroyed in function
+ calls), all other registers are preserved.
+
+ All elementary types up to 4 bytes are returned in register @code{%eax}
+ Floating point values are returned in %st(0).
+ All other types are returned by passing the function the address
+ of the result as a hidden argument - so when you call such a function
+ without a proper declaration in scope you can expect a crash.
+
+ @code{vbcc} uses @code{%eax, %ebx, %ecx, %edx, %esi, %edi, %ebp} and the floating point
+ stack for temporary results and register variables. Local variables
+ are created on the stack and addressed via @code{%esp}.
+
+ The elementary data types are represented like:
+
+ @example
+ type size in bits alignment in bytes (-longalign)
+
+ char 8 1 (1)
+ short 16 2 (4)
+ int 32 2 (4)
+ long 32 2 (4)
+ long long n/a n/a
+ all pointers 32 2 (4)
+ float 32 2 (4)
+ double 64 2 (4)
+ @end example
+
+@section Predefined Macros
+
+ This backend defines the following macros:
+
+@table @code
+ @item __I386__
+ @item __X86__
+
+@end table
+
+
+@section Stdarg
+
+ A possible <stdarg.h> could look like this:
+
+@example
+ typedef unsigned char *va_list;
+
+ #define va_start(ap, lastarg) ((ap) = (va_list)(&lastarg + 1))
+ #define va_arg(ap, type) ((ap) += \
+ (sizeof(type)<sizeof(int)?sizeof(int):sizeof(type)), ((type *)(ap))[-1])
+ #define va_end(ap) ((ap) = 0L)
+@end example
+
+
+@section Known Problems
+
+@itemize @minus
+ @item generated code is rather poor
+ @item functions which return floating-point values sometimes are broken(?)
+ @item in some cases (scare registers) non-reentrant code is generated
+@end itemize
+
+
diff --git a/doc/vbccm68k.texi b/doc/vbccm68k.texi
new file mode 100644
index 0000000..9999f9d
--- /dev/null
+++ b/doc/vbccm68k.texi
@@ -0,0 +1,474 @@
+This chapter documents the backend for the M68k and Coldfire
+processor families.
+
+@section Additional options
+
+This backend provides the following additional options:
+
+@table @option
+
+ @item -a2scratch
+ Allow using @code{A2} as scratch register.
+
+ @item -amiga-softfloat
+ Call AmigaOS MathIEEE library functions via direct inline
+ code, instead of callling stub routines from @file{mieee.lib}.
+ It still requires that you either link with @file{mieee.lib} or
+ define @code{MathIeeeSingBasBase}, @code{MathIeeeDoubBasBase}
+ and @code{MathIeeeDoubTransBase} yourself.
+
+ @item -conservative-sr
+ Restrict strength-reduction. Experimental.
+
+ @item -const-in-data
+ By default constant data will be placed in the code
+ section (and therefore is accessible with faster pc-relative
+ addressing modes). Using this option it will be placed in the
+ data section.
+
+ This could e.g. be useful if you want to use small data and
+ small code, but your code gets too big with all the constant
+ data.
+
+ Note that on operating systems with memory protection this
+ option will disable write-protection of constant data.
+
+ @item -cpu=n
+ Generate code for cpu n (e.g. @option{-cpu=68020}),
+ defaults to 68000.
+
+ @item -d2scratch
+ Allow using @code{D2} as scratch register.
+
+ @item -fastcall
+ Pass function arguments in volatile registers, when possible.
+
+ @item -fp2scratch
+ Allow using @code{FP2} as scratch register.
+
+ @item -fpu=n
+ Generate code for fpu n (e.g. @option{-fpu=68881}), default: 0.
+
+ @item -gas
+ Create output suitable for the GNU assembler.
+
+ @item -hunkdebug
+ When creating debug-output (@option{-g} option) create
+ Amiga debug hunks rather than DWARF2.
+ Does not work with @option{-gas}.
+
+ @item -no-delayed-popping
+ By default arguments of function calls are not always popped
+ from the stack immediately after the call, so that the
+ arguments of several calls may be popped at once.
+ With this option @command{vbcc} can be forced to pop them after every
+ function call.
+ This may simplify debugging and reduce the
+ stack size needed by the compiled program.
+
+ @item -no-fp-return
+
+ Do not return floats and doubles in floating-point registers
+ even if code for an fpu is generated.
+
+ @item -no-intz
+ When generating code for FPU do quick&dirty conversions
+ from floating-point to integer. The code may be somewhat
+ faster but will not correctly round to zero.
+ Only use it if you know what you are doing.
+
+ @item -no-mreg-return
+ Do not use multiple registers to return types that do not
+ fit into a single register. This is mainly for backwards
+ compatibility with certain libraries.
+
+ @item -no-peephole
+ Do not perform peephole-optimizations.
+
+ @item -no-reserve-regs
+ Do not reserve temporary registers for the backend. Can lead to
+ worse code generation.
+
+ @item -old-softfloat
+ Use old libcall mechanism for software floating point.
+ Should not be used, will usually generate worse code.
+
+ @item -old-libcalls
+ Use old libcall mechanism for (some) integer support routines.
+ Should not be used, will usually generate worse code.
+
+ @item -phxass
+ Generate assembly output for the PhxAss assembler.
+
+ @item -prof
+ Insert code for profiling.
+
+ @item -sc
+ Use small code model (see below).
+
+ @item -sd
+ Use small data model (see below).
+
+ @item -use-commons
+ Use real common symbols instead of bss symbols for
+ non-initialized external variables.
+
+ @item -use-framepointer
+ By default automatic variables are addressed through a7
+ instead of a5. This generates slightly better code, because
+ the function entry and exit overhead is reduced and a5 can be
+ used as register variable etc.
+
+ However this may be a bit confusing when debugging and you
+ can force @command{vbcc} to use a5 as a fixed framepointer.
+
+
+
+
+@end table
+
+@section ABI
+
+ The current version generates assembler output for use with the
+ @command{vasmm68k_mot}. Most peephole optimizations are done by the
+ assembler so @command{vbcc} only does some that the assembler cannot make.
+ The generated executables will probably only work with OS2.0 or higher.
+
+ With @option{-gas} assembler output suitable for the GNU assembler is generated
+ (the version must understand the Motorola syntax - some old ones do not).
+ The output is only slightly modified from the @command{vasm}-output and will
+ therefore result in worse code on @command{gas}.
+
+ The register names provided by this backend are:
+
+@example
+ a0, a1, a2, a3, a4, a5, a6, a7
+ d0, d1, d2, d3, d4, d5, d6, d7
+ fp0, fp1, fp2, fp3, fp4, fp5, fp6, fp7
+@end example
+
+ The registers @code{a0} - @code{a7} are supported to hold pointer
+ types. @code{d0} - @code{d7} can be used for integers types
+ excluding @code{long long}, pointers and @code{float} if no
+ FPU code is generated. @code{fp0} - @code{fp7} can be used for
+ all floating point types if FPU code is generated.
+
+ Additionally the following register pairs can be used for
+ @code{long long}:
+
+@example
+ d0/d1, d2/d3, d4/d5, d6/d7
+@end example
+
+ The registers @code{d0, d1, a0, a1, fp0} and @code{fp1} are used as scratch registers
+ (i.e. they can be destroyed in function calls), all other registers are
+ preserved.
+
+ By default, all function arguments are passed on the stack.
+
+ All scalar types up to 4 bytes are returned in register @code{d0},
+ @code{long long} is returned in @code{d0/d1}.
+ If compiled for FPU, floating point values are returned in
+ @code{fp0} unless @option{-no-fpreturn} is specified.
+ Types which are 8, 12 or 16 bytes large will be returned in several
+ registers (@code{d0/d1/a0/a1}) unless @option{-no-mreg-return} is specified.
+ All other types are returned by passing the function the address
+ of the result as a hidden argument - such a function must not be called
+ without a proper declaration in scope.
+
+ Objects which have been compiled with different settings must not be
+ linked together.
+
+ @code{a7} is used as stack pointer. If @option{-sd} is used,
+ @code{a4} will be used as small data pointer. If
+ @option{-use-framepointer} is used, @code{a5} will be used as
+ frame pointer. All other registers will be used by the
+ register allocator and can be used for register parameters.
+
+ The size of the stack frame is limited to 32KB for early members
+ of the 68000 family prior to 68020.
+
+
+The basic data types are represented like:
+
+@example
+ type size in bits alignment in bytes
+
+ char 8 1
+ short 16 2
+ int 32 2
+ long 32 2
+ long long 64 2
+ all pointers 32 2
+ float(fpu) 32 2 see below
+ double(fpu) 64 2 see below
+ long double(fpu) 64 2 see below
+@end example
+
+
+
+@section Small data
+
+ @command{vbcc} can access static data in two ways. By default all such data will
+ be accessed with full 32bit addresses (large data model).
+ However there is a second way. You can set up an address register
+ (@code{a4})
+ to point into the data segment and then address data with a 16bit
+ offset through this register.
+
+ The advantages of the small data model are that the program will
+ usually be smaller (because the 16bit offsets use less space and no
+ relocation information is needed) and faster.
+
+ The disadvantages are that one address register cannot be used by the
+ compiler and that it can only be used if all static data occupies
+ less than 64kb. Also object modules and libraries that
+ have been compiled with different data models must not be mixed
+ (it is possible to call functions
+ compiled with large data model from object files compiled with small
+ data model, but not vice versa and only functions can be called that
+ way - other data cannot be accessed).
+
+ If small data is used with functions which are called from
+ functions which have not been compiled with @command{vbcc} or without the small data
+ model then those functions must be declared with the @code{__saveds} attribute
+ or call @code{geta4()} as the first statement (do not use
+ automatic initializations prior to the call to @code{geta4}).
+ Note that @code{geta4()} must not be called through a function pointer!
+
+
+@section Small code
+
+ In the small code model calls to external functions (i.e. from
+ libraries or other object files) are done with 16bit offsets through
+ the program counter rather than with absolute 32bit addresses.
+
+ The advantage is slightly smaller and faster code.
+ The disadvantages are that all the code (including library functions)
+ must be small enough. Objects/libraries can be linked together if they
+ have been compiled with different code models.
+
+
+@section CPUs
+
+ The values of @option{-cpu=n} have those effects:
+
+@table @option
+
+ @item n<68000
+ Code for the Coldfire family is generated.
+
+ @item n>=68000
+ Code for the 68k family is generated.
+
+ @item n>=68020
+@itemize @minus
+ @item 32bit multiplication/division/modulo is done with the
+ mul?.l, div?.l and div?l.l instructions.
+ @item tst.l ax is used.
+ @item extb.l dx is used.
+ @item 16/32bit offsets are used in certain addressing modes.
+ @item link.l is used.
+ @item Addressing modes with scaling are used.
+@end itemize
+
+ @item n==68040
+@itemize @minus
+ @item 8bit constants are not copied in data registers.
+ @item Static memory is not subject to common subexpression elimination.
+@end itemize
+
+@end table
+
+
+@section FPUs
+
+ At the moment the values of -fpu=n have those effects:
+
+@table @option
+ @item n>68000
+ Floating point calculations are done using the FPU.
+ @item n=68040
+ @itemx n=68060
+ Instructions that have to be emulated on these FPUs
+ will not be used; at the moment this only includes
+ the @code{fintrz} instruction in case of the 040.
+@end table
+
+@section Math
+
+ Long multiply
+ on CPUs <68020 uses inline routines. This may increase code size a bit,
+ but it should be significantly faster, because function call overhead
+ is not necessary.
+ Long division and modulo is handled by calls to library
+ functions.
+ (Some operations involving constants (e.g. powers of two) are always
+ implemented by more efficient inline code.)
+
+ If no FPU is specified floating point math is done using
+ math libraries. 32bit IEEE format is used for float and 64bit IEEE
+ for double and long double.
+
+ If floating point math is done with the FPU
+ floating point values are kept in registers and therefore may
+ have extended precision sometimes. This is not ANSI compliant but
+ will usually cause no harm. When floating point values are stored in
+ memory they use the same IEEE formats as without FPU.
+ Return values are passed in @code{fp0}.
+
+ Note that you must not link object files together if they were not
+ compiled with the same @code{-fpu} settings and that
+ a proper math library must be linked.
+
+
+@section Target-Specific Variable Attributes
+
+ This backend offers the following variable attributes:
+
+@table @code
+ @item __amigainterrupt
+ Used to write interrupt-handlers for AmigaOS. Stack-checking
+ for a function with this attribute will be disabled and if a value
+ is returned in d0, the
+ condition codes will be set accordingly.
+
+ @item __chip
+ Place variable in chip-memory. Only applicable on
+ AmigaOS to variables with static storage-duration.
+
+ @item __far
+ Do not place this variable in the small-data segment
+ in small data mode. No effect in large data mode.
+ Only applicable to variables with static
+ storage-duration.
+
+ @item __interrupt
+ This is used to declare interrupt-handlers. The
+ function using this attribute will save all registers
+ it destroys (including scratch-registers) and return
+ with @code{rte} rather than @code{rts}.
+
+ @item __near
+ Currently ignored.
+
+ @item __regargs
+ Declare function to use the @option{-fastcall} ABI. The
+ first arguments are passed in volatile registers.
+
+ @item __saveds
+ Load the pointer to the small data segment at
+ function-entry. Applicable only to functions.
+
+ @item __section(<string-literal>)
+ Places the variable/function in a section named
+ according to the argument.
+
+ @item __stdargs
+ Declare function to use the standard ABI (default),
+ which passes all arguments on the stack.
+@end table
+
+@section Target-specific pragmas
+
+ This backend offers the following #pragmas:
+
+@table @code
+
+ @item #pragma stdargs-on
+ Automatically declare the following functions with the
+ @code{__stdargs} attribute.
+
+ @item #pragma stdargs-off
+ Stop automatically declaring the following functions with the
+ @code{__stdargs} attribute.
+
+@end table
+
+@section Predefined Macros
+
+ This backend defines the following macros:
+
+@table @code
+ @item __AMIGADATE__
+ This is set to current date as @code{"(DD.MM.YYYY)"},
+ useful with version strings.
+
+ @item __COLDFIRE
+ (If a Coldfire CPU is selected.)
+
+ @item __INTSIZE
+ Is set to the size of the @code{int} type.
+ Either 16 (vbccm68ks) or 32 (vbccm68k).
+
+ @item __M680x0
+ (Depending on the settings of @option{-cpu}, e.g.
+ @code{__M68020}.)
+
+ @item __M68881
+ (If @option{-fpu=68881} is selected.)
+
+ @item __M68882
+ (If code for another FPU is selected;
+ @option{-fpu=68040} or @option{-fpu=68060} will
+ set @code{__M68882}.)
+
+ @item __M68K__
+
+ @item __SMALL_DATA__
+ (If @option{-sd} is selected to enable small data.)
+@end table
+
+
+@section Stack
+
+ If the @option{-stack-check} option is used, every function-prologue will
+ call the function @code{__stack_check} with the stacksize needed by the
+ current function on the stack. This function has to consider its own
+ stacksize and must restore all registers.
+
+ If the compiler is able to calculate the maximum stack-size of a
+ function including all callees, it will add a comment in the
+ generated assembly-output (subject to change to labels).
+
+
+@section Stdarg
+
+ A possible @file{<stdarg.h>} could look like this:
+
+@example
+
+typedef unsigned char *va_list;
+
+#define __va_align(type) (__alignof(type)>=4?__alignof(type):4)
+
+#define __va_do_align(vl,type) ((vl)=(char *)((((unsigned int)(vl))+__va_align(type)-1)/__va_align(type)*__va_align(type)))
+
+#define __va_mem(vl,type) (__va_do_align((vl),type),(vl)+=sizeof(type),((type*)(vl))[-1])
+
+#define va_start(ap, lastarg) ((ap)=(va_list)(&lastarg+1))
+
+#define va_arg(vl,type) __va_mem(vl,type)
+
+#define va_end(vl) ((vl)=0)
+
+#define va_copy(new,old) ((new)=(old))
+
+#endif
+
+
+@end example
+
+@section Known problems
+
+@itemize @minus
+ @item The extended precision of the FPU registers can cause problems if
+ a program depends on the exact precision. Most programs will not
+ have trouble with that, but programs which do exact comparisons
+ with floating point types (e.g. to try to calculate the number
+ of significant bits) may not work as expected (especially if the
+ optimizer was turned on).
+@end itemize
+
+
+
diff --git a/doc/vbccppc.texi b/doc/vbccppc.texi
new file mode 100644
index 0000000..9d7fe3e
--- /dev/null
+++ b/doc/vbccppc.texi
@@ -0,0 +1,349 @@
+This chapter documents the Backend for the PowerPC processor family.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+ @item -amiga-align
+
+ Do not require any alignments greater than 2 bytes.
+ This is needed when accessing Amiga system-structures, but
+ can cause a performance penalty.
+
+ @item -baserel32mos
+
+ Use 32bit base-relative addressing as used by MorphOS.
+
+ @item -baserel32os4
+
+ Use 32bit base-relative addressing as used by AmigaOS 4.
+
+ @item -const-in-data
+
+ By default constant data will be placed in the @code{.rodata}
+ section. Using this option it will be placed in the
+ @code{.data} section.
+ Note that on operating systems with memory protection this
+ option will disable write-protection of constant data.
+
+ @item -eabi
+ Use the PowerPC Embedded ABI (eabi).
+
+ @item -elf
+
+ Do not prefix symbols with '_'. Prefix labels with '.'.
+
+ @item -fsub-zero
+
+ Use fsub to load a floating-point-register with zero.
+ This is faster but requires all registers to always contain
+ valid values (i.e. no NaNs etc.) which may not be the case
+ depending on startup-code, libraries etc.
+
+ @item -gas
+ Create code suitable for the GNU assembler.
+
+ @item -madd
+ Use the @code{fmadd/fmsub} instructions for combining
+ multiplication with addition/subtraction in one instruction.
+ As these instructions do not round between the operations,
+ they have increased precision over separate addition and
+ multiplication.
+
+ While this usually does no harm, it is not ISO conforming
+ and therefore not the default behaviour.
+
+ @item -merge-constants
+
+ Place identical floating point constants at the same
+ memory location. This can reduce program size.
+
+ @item -no-align-args
+
+ Do not align function arguments on the stack stricter
+ than 4 bytes. Default with @option{-poweropen}.
+
+ @item -no-peephole
+
+ Do not perform several peephole optimizations.
+ Currently includes:
+ @itemize @minus
+ @item better use of d16(r) addressing
+ @item use of indexed addressing modes
+ @item use of update-flag
+ @item use of record-flag
+ @item use of condition-code-registers to avoid certain branches
+ @end itemize
+
+ @item -no-regnames
+
+ Do not use register names but only numbers in the assembly
+ output. This is necessary
+ to avoid name-conflicts when using @option{-elf}.
+
+ @item -poweropen
+
+ Generate code for the PowerOpen ABI like used in AIX.
+ This does not work correctly yet.
+
+ @item -sc
+
+ Generate code for the modified PowerOpen ABI used in the
+ StormC compiler (aka WarpOS ABI).
+
+ @item -sd
+ Place all objects in small data-sections.
+
+ @item -setccs
+
+ The V.4 ABI requires signalling (in a bit of the condition code
+ register) when arguments to varargs-functions
+ are passed in floating-point registers.
+ vbcc usually does not make use of this and
+ therefore does not set that bit by default.
+ This may lead to problems when linking objects compiled by
+ vbcc to objects/libraries created by other
+ compilers and calling varargs-functions with floating-point
+ arguments.
+ @option{-setccs} will fix this problem.
+
+ @item -use-commons
+
+ Use real common symbols instead of bss symbols for
+ non-initialized external variables.
+
+ @item -use-lmw
+
+ Use @code{lmw/stmw}-instructions. This can significantly reduce
+ code-size. However these instructions may be slower on
+ certain PPCs.
+
+@end table
+
+@section ABI
+
+ This backend supports the following registers:
+
+ @itemize @minus
+ @item @code{r0} through @code{r31} for the general purpose registers,
+ @item @code{f0} through @code{f31} for the floating point registers and
+ @item @code{cr0} through @code{cr7} for the condition-code registers.
+ @end itemize
+
+ Additionally, the register pairs @code{r3/r4, r5/r6, r7/r8, r9/r10,
+ r14/r15, r16/r17, r18/r19,
+ r20/r21, r22/r23, r24/r25, r26/r27, r28/r29} and @code{r30/r31} are
+ available.
+
+ @code{r0, r11, r12, f0, f12} and @code{f13} are reserved by the
+ backend.
+
+
+
+ The current version generates assembly output for use with @file{vasmppc}
+ or the GNU assembler. The generated code should
+ work on 32bit systems based on a PowerPC CPU using the V.4 ABI or the
+ PowerPC Embedded ABI (eabi).
+
+
+ The registers r0, r3-r12, f0-f13 and cr0-cr1 are used as scratch registers
+ (i.e. they can be destroyed in function calls), all other registers are
+ preserved. r1 is the stack-pointer and r13 is the small-data-pointer if
+ small-data-mode is used.
+
+ The first 8 function arguments which have integer or pointer types
+ are passed in registers r3 through r10 and the first 8 floating-point
+ arguments are passed in registers f1 through f8. All other arguments
+ are passed on the stack.
+
+ Integers and pointers are returned in r3 (and r4 for long long),
+ floats and doubles in f1.
+ All other types are returned by passing the function the address
+ of the result as a hidden argument - so when you call such a function
+ without a proper declaration in scope you can expect a crash.
+
+ The elementary data types are represented like:
+
+ @example
+ type size in bits alignment in bytes (-amiga-align)
+
+ char 8 1 (1)
+ short 16 2 (2)
+ int 32 4 (2)
+ long 32 4 (2)
+ long long 64 8 (2)
+ all pointers 32 4 (2)
+ float 32 4 (2)
+ double 64 8 (2)
+ @end example
+
+@section Target-specific variable-attributes
+
+ The PPC-backend offers the following variable-attributes:
+
+@table @code
+
+ @item __saveds
+ Load the pointer to the small data segment at
+ function-entry. Applicable only to functions.
+
+ @item __chip
+ Place variable in chip-memory. Only applicable on
+ AmigaOS to variables with static storage-duration.
+
+ @item __far
+ Do not place this variable in the small-data segment
+ in small-data-mode. No effect in large-data-mode.
+ Only applicable to variables with static storage-
+ duration.
+
+ @item __near
+ Currently ignored.
+
+ @item __saveall
+ Make sure all registers are saved by this function. On lower
+ optimization levels, all volatile registers will be saved
+ additionally. On higher levels, only the ones that may be
+ destroyed, are saved.
+
+ @item __interrupt
+ Return with en @code{rfi}-instruction rather than @code{blr}.
+
+ @item __section("name","attr")
+ Place this function/object in section "name" with
+ attributes "attr".
+@end table
+
+
+@section Target-specific pragmas
+
+ The PPC-backend offers the following #pragmas:
+
+@table @code
+
+ @item #pragma amiga-align
+ Set alignment like -amiga-alignment option.
+
+ @item #pragma natural-align
+ Align every type to its own size.
+
+ @item #pragma default-align
+ Set alignment according to command-line options.
+
+@end table
+
+@section Predefined Macros
+
+ This backend defines the following macros:
+
+@table @code
+ @item __PPC__
+
+ @item __AMIGADATE__
+ This is set to current date as @code{"(DD.MM.YYYY)"},
+ useful with version strings.
+@end table
+
+@section Stack
+
+ If the @option{-stack-check} option is used, every function-prologue will
+ call the function @code{__stack_check} with the stacksize needed by this
+ function in register r12. This function has to consider its own
+ stacksize and must restore all registers.
+
+@section Stdarg
+
+ A possible <stdarg.h> for V.4 ABI could look like this:
+
+@example
+
+typedef struct @{
+ int gpr;
+ int fpr;
+ char *regbase;
+ char *membase;
+@} va_list;
+
+char *__va_start(void);
+char *__va_regbase(void);
+int __va_fixedgpr(void);
+int __va_fixedfpr(void);
+
+#define va_start(vl,dummy) \
+ ( \
+ vl.gpr=__va_fixedgpr(), \
+ vl.fpr=__va_fixedfpr(), \
+ vl.regbase=__va_regbase(), \
+ vl.membase=__va_start() \
+ )
+
+#define va_end(vl) ((vl).regbase=(vl).membase=0)
+
+#define va_copy(new,old) ((new)=(old))
+
+#define __va_align(type) (__alignof(type)>=4?__alignof(type):4)
+
+#define __va_do_align(vl,type) ((vl).membase=(char *)((((unsigned int)((vl).membase))+__va_align(type)-1)/__va_align(type)*__va_align(type)))
+
+#define __va_mem(vl,type) (__va_do_align((vl),type),(vl).membase+=sizeof(type),((type*)((vl).membase))[-1])
+
+#define va_arg(vl,type) \
+ ( \
+ (__typeof(type)&127)>10? \
+ __va_mem((vl),type) \
+ : \
+ ( \
+ (((__typeof(type)&127)>=6&&(__typeof(type)&127)<=8)) ? \
+ ( \
+ ++(vl).fpr<=8 ? \
+ ((type*)((vl).regbase+32))[(vl).fpr-1] \
+ : \
+ __va_mem((vl),type) \
+ ) \
+ : \
+ ( \
+ ++(vl).gpr<=8 ? \
+ ((type*)((vl).regbase+0))[(vl).gpr-1] \
+ : \
+ __va_mem((vl),type) \
+ ) \
+ ) \
+ )
+
+@end example
+
+ A possible <stdarg.h> for PowerOpen ABI could look like this:
+
+@example
+
+typedef unsigned char *va_list;
+
+#define __va_align(type) (4)
+
+#define __va_do_align(vl,type) ((vl)=(char *)((((unsigned int)(vl))+__va_align(type)-1)/__va_align(type)*__va_align(type)))
+
+#define __va_mem(vl,type) (__va_do_align((vl),type),(vl)+=sizeof(type),((type*)(vl))[-1])
+
+#define va_start(ap, lastarg) ((ap)=(va_list)(&lastarg+1))
+
+#define va_arg(vl,type) __va_mem(vl,type)
+
+#define va_end(vl) ((vl)=0)
+
+#define va_copy(new,old) ((new)=(old))
+
+@end example
+
+
+@section Known problems
+
+@itemize @minus
+ @item composite types are put on the stack rather than passed via pointer
+ @item indication of fp-register-args with bit 6 of cr is not done well
+@end itemize
+
+
+
+
diff --git a/doc/vbccvidcore.texi b/doc/vbccvidcore.texi
new file mode 100644
index 0000000..64430c6
--- /dev/null
+++ b/doc/vbccvidcore.texi
@@ -0,0 +1,157 @@
+This chapter documents the Backend for the VideoCore IV processor family.
+
+The backend is in a very early stage, it is not complete, and it can not
+yet be considered useful!
+
+Also note that it is based on freely available, unofficial, and possibly
+incorrect information on the target processor.
+
+@section Additional options for this version
+
+This backend provides the following additional options:
+
+@table @option
+
+ @item -short-double
+
+ Use native 32bit floating point for double and long double.
+ This is much more efficient, but not ISO C conforming.
+
+ @item -one-section
+
+ Put all code and data in the same section (.text).
+
+
+ @item -no-delayed-popping
+
+ By default arguments of function calls are not always popped
+ from the stack immediately after the call, so that the
+ arguments of several calls may be popped at once.
+ With this option @command{vbcc} can be forced to pop them after every
+ function call.
+ This may simplify debugging and reduce the
+ stack size needed by the compiled program.
+
+ @item -no-peephole
+
+ Disable most backend peephole optimizations.
+ Just for testing.
+
+ @item -noext-regs
+
+ Do not use registers r16-r23. Just for testing.
+
+ @item -cond-limit=<n>
+
+ Set the limit (in number of intermediate code instructions)
+ for the length of code-sequences considered for conditional
+ execution (default: 2).
+
+
+@end table
+
+@section ABI
+
+ This backend supports the following registers:
+
+ @itemize @minus
+ @item @code{r0} through @code{r31} for the general purpose registers
+ @end itemize
+
+ Additionally, the register pairs @code{r0/r1} @code{r2/r3, r4/r5, r6/r7, r8/r9,
+ r10/r11, r12/r13, r14/r15,
+ r16/r17, r18/r19, r20/r21, r22/r23} are
+ available.
+
+ @code{r14, r15, r24-r31} are currently reserved by the
+ backend.
+
+
+
+ The current version generates assembly output for use with @file{vasm}.
+
+
+ The registers r0-r5 and r14-r15 are used as scratch registers
+ (i.e. they can be destroyed in function calls), all other registers are
+ preserved. r25 is the stack-pointer.
+
+ The first 6 function arguments which have integer, float32 or pointer types
+ are passed in registers r0 through r5. All other arguments
+ are passed on the stack.
+
+ Integers, float32 and pointers are returned in r0.
+ All other types are returned by passing the function the address
+ of the result as a hidden argument - so when you call such a function
+ without a proper declaration in scope you can expect a crash.
+
+ The elementary data types are represented like:
+
+ @example
+ type size in bits alignment in bytes
+
+ char 8 1
+ short 16 2
+ int 32 4
+ long 32 4
+ long long 64 8 not yet supported
+ all pointers 32 4
+ float 32 4
+ double 64 (32) 4
+ long double 64 (32) 4
+ @end example
+
+@section Target-specific variable-attributes
+
+ The vidcore-backend offers the following variable-attributes:
+
+@table @code
+
+ @item __section("name","attr")
+ Place this function/object in section "name" with
+ attributes "attr".
+@end table
+
+
+@section Target-specific pragmas
+
+ The vidcore-backend offers the following #pragmas:
+
+@table @code
+
+ @item none at the moment...
+
+@end table
+
+@section Predefined Macros
+
+ This backend defines the following macros:
+
+@table @code
+ @item __VIDEOCORE__
+
+ @item __SHORT_DOUBLE__ (if -short-double is used)
+@end table
+
+@section Stdarg
+
+stdarg-implementation is not yet fully working. One restriction is that
+when calling a varargs function, the prototype must be in scope (this is
+ISO C conforming). Another one is that the stdarg-macros only work as
+long as all fixed arguments are passed in registers.
+
+This will be fixed in the future.
+
+
+@section Known problems
+
+@itemize @minus
+ @item no support for long long
+ @item no support for 64bit floating point
+ @item stdarg problems mentioned above
+ @item suboptimal code quality
+ @item ...
+@end itemize
+
+
+
+
diff --git a/doc/vc.texi b/doc/vc.texi
new file mode 100644
index 0000000..89de471
--- /dev/null
+++ b/doc/vc.texi
@@ -0,0 +1,254 @@
+This chapter describes @command{vc}, the frontend for vbcc. It knows how
+to deal with different file types and optimization settings and will
+call the compiler, assembler and linker.
+It is not recommended to call the different translation-phases directly.
+@command{vc} provides an easy-to-use interface which is mostly compatible to
+Unix @command{cc}.
+
+@section Usage
+
+ The general syntax for calling @command{vc}
+
+@example
+ @command{vc [options] file1 file2 ...}
+@end example
+
+ processes all files according to their suffix and links all objects
+ together (unless any of @option{-E}, @option{-S}, @option{-c} is specified).
+ The following file types are recognized:
+
+@table @file
+ @item .c
+ C source
+ @item .i
+ already preprocessed C source
+ @item .scs
+ assembly source to be fed to the scheduler
+ @item .asm
+ @item .s
+ assembly source
+ @item .obj
+ @item .o
+ object file
+@end table
+
+ Usually pattern matching is supported - however this depends on the
+ port and the host system.
+
+ The options recognized by @command{vc} are:
+
+@table @option
+
+ @item -v
+ Verbose mode. Prints all commands before executing them.
+
+ @item -vv
+ Very verbose. Displays some internals as well.
+
+ @item -Ox
+ Sets the optimization level.@*
+ -O0 is equivalent to -O=0.@*
+ -O will activate some optimizations (at the moment -O=991).@*
+ -O2 will activate most optimizations (at the moment -O=1023 -schedule).@*
+ -O3 will activate all optimizations (at the moment -O=~0 -schedule).@*
+ -O4 will activate full cross-module-optimization.@*
+
+ Also, -O3 will activate cross-module-optimizations. All source
+ files specified on the command line will be passed to the compiler
+ at once. Only one assembly/object-file will be produced (by default
+ the name is the name of the first source file with corresponding
+ suffix).
+
+ When compiling with -O4 and -c vbcc will not produce real object
+ files but special files containing all necessary information to
+ defer optimization and code-generation to link-time. This is
+ useful to provide all files of a project to the optimizer and
+ make full use of cross-module optimizations.
+ Note that you must use vc to do the linking. vc will detect and
+ handle these files correctly. They can not be linked directly.
+ Also, make sure to pass all relevant compiler options also to
+ the linker-command.
+
+ Higher values may or may not activate even more optimizations.
+ The default is -O=1.
+ It is also possible to specify an exact value with -O=n.
+ However, I do not recommend this unless you know exactly what
+ you are doing.
+
+ @item -o file
+ Save the target as @file{file} (default for executables is
+ @file{a.out}).
+
+ @item -E
+ Save the preprocessed C sources with .i suffix.
+
+ @item -S
+ Do not assemble. Save the compiled files with .asm suffix.
+
+ @item -SCS
+ Do not schedule. Save the compiled files with .scs suffix.
+
+ @item -c
+ Do not link. Save the compiled files with .o suffix.
+
+ @item -k
+ Keep all intermediate files. By default all generated files
+ except the source files and the targets are deleted.
+
+ @item -Dstr
+ @code{#define} a preprocessor symbol, e.g. -DAMIGA or -DCPU=68000.
+ The former syntax is equivalent to:
+@example
+ #define AMIGA 1
+@end example
+ The latter form is equivalent to:
+@example
+ #define CPU 68000
+@end example
+
+ @item -Ipath
+ Add @file{path} to the include-search-path.
+ An empty @file{path} adds the current directory.
+
+ @item -lulib
+ Link with library @file{ulib}.
+
+ @item -Lpath
+ Add @file{path} to the library-search-path.
+ This is passed through to the linker.
+
+ @item -static
+ Instruct the linker to link against static libraries.
+ This may override the default to link against dynamic
+ libraries first.
+
+ @item -nostdlib
+ Do not link with standard-startup/libraries. Useful only
+ for people who know what they are doing.
+
+ @item -notmpfile
+ Do not use names from tmpnam() for temporary files.
+
+ @item -schedule
+ Invoke the instruction-scheduler, if available.
+
+ @item -rmcfg-<opt>
+ Ignore all lines from the config file starting with -<opt>.
+
+ @item +file
+ Use @file{file} as config-file.
+
+@end table
+
+
+ All other options are passed through to @command{vbcc}.
+
+
+
+
+
+@section Configuration
+
+ @command{vc} needs a config file to know how to call all the translation
+ phases (compiler, assembler, linker). Unless a different file is
+ specified using the @option{+}-option, it will look for a file
+ @file{vc.config} (@file{vc.cfg} for DOS/Windows).
+
+ On AmigaOS @command{vc} will search in the current
+ directory, in @file{ENV:} and @file{VBCC:}.
+
+ On Unix @command{vc} will search in the current directory followed
+ by @file{/etc/}.
+
+ On DOS/Windows it will search in the current directory.
+
+ If the config file was not found in the default search-paths and
+ an environment variable @env{$VBCC} is set, @command{vc} will also look
+ in @env{$VBCC}@file{/config}.
+
+ Once a config file is found, it will
+ be treated as a collection of additional command line arguments. Every
+ line of the file will be used as one argument. So no quoting shall be
+ used and furthermore must each argument be placed on its own line.
+
+
+ The following options can be used to tell @command{vc} how to call the
+ translation phases (they will usually be contained in the config-file):
+
+@table @option
+
+ @item -pp=string
+ The preprocessor will be called like in
+ @code{printf(string,opts,infile,outfile)}, e.g. the default for @command{vcpp}
+ searching the includes in @file{vinclude:} and defining @code{__STDC__})
+ is @option{-pp=vcpp -Ivinclude: -D__STDC__=1 %s %s %s}.
+ Note that there is an internal preprocessor, called
+ @command{ucpp}, since V0.8, you usually don't need this
+ option any more.
+
+ @item -cc=string
+ For the compiler. Note that you cannot use @command{vc} to call
+ another compiler than @command{vbcc}. But you can call different
+ versions of @command{vbcc} this way, e.g.:
+ @option{-cc=vbccm68k -quiet} or
+ @option{-cc=vbcci386 -quiet}
+
+ @item -isc=string
+ The same for the scheduler, e.g.:
+ @option{-isc=vscppc -quiet %s %s}
+ Omit, if there is no scheduler for the architecture.
+
+ @item -as=string
+ The same for the assembler, e.g.:
+ @option{-as=vasmm68k_mot -quiet -Fhunk -phxass -opt-pea -opt-clr %s -o %s} or
+ @option{-as=as %s -o %s}
+
+ @item -rm=string
+ This is the string for the delete command and takes only
+ one argument, e.g.
+ @option{-rm=delete quiet %s} or
+ @option{-rm=rm %s}
+
+ @item -ld=string
+ This is for the linker and takes three arguments. The first
+ one are the object files (separated by spaces), the second
+ one the user specified libraries and the last one the name
+ of the resulting executable.
+ This has to link with proper startup-code and c-libraries,
+ e.g.:
+ @option{-ld=vlink -x -Bstatic -Cvbcc -nostdlib -Lvlibos3: vlibos3:startup.o %s %s -lvc -o %s} or
+ @option{-ld=ld /usr/lib/crt0.o %s %s -lc -o %s}
+
+ @item -l2=string
+ The same like -ld, but standard-startup and -libraries should
+ not be linked; used when -nostdlib is specified.
+
+ @item -ldnodb=string
+ This option string is inserted in the linker command before
+ specifying the libraries, whenever an executable without
+ debugging information and symbols should be created (AKA
+ as a 'stripped' executable).
+
+ @item -ldstatic=string
+ This option string is inserted in the linker command before
+ specifying the libraries when static linking was requested
+ with option @option{-static}.
+
+@end table
+
+ All those strings should tell the command to omit any output apart from
+ error messages if possible. However for every of those options there
+ exists one with an additional @samp{v}, i.e. @option{-ppv=}, @option{-asv=}, etc. which should
+ produce some output, if possible.
+ If vc is invoked with the @option{-vv} option the verbose commands will be called,
+ if not the quiet ones will be used.
+
+@table @samp
+ @item -ul=string
+ Format for additional libraries specified with @option{-l<lib>}.
+ The result of @code{printf(string,lib)} will be added to the
+ command invoking the linker. Examples are:
+ @option{-ul=vlib:%s.lib} or @option{-ul=-l%s}
+
+@end table
+
diff --git a/doc/vclib.texi b/doc/vclib.texi
new file mode 100644
index 0000000..45dff3f
--- /dev/null
+++ b/doc/vclib.texi
@@ -0,0 +1,2818 @@
+This chapter describes the C library usually provided with @command{vbcc}.
+
+
+@section Introduction
+
+To execute code compiled by @command{vbcc}, a library is needed. It
+provides basic interfaces to the underlying operating system or
+hardware as well as a set of often used functions.
+
+A big part of the library is portable across all architectures. However,
+some functions (e.g. for input/output or memory allocation) are
+naturally dependent on the operating system or hardware. There are
+several sections in this chapter dealing with different versions of
+the library.
+
+The library itself often is split into several parts. A startup-code
+will do useful initializations, like setting up IO, parsing the command
+line or initializing variables and hardware.
+
+The biggest part of the functions will usually be stored in one library file.
+The name and format of this file depends on the conventions of the underlying
+system (e.g. @file{vc.lib} or @file{libvc.a}).
+
+Often, floating point code (if available) is stored in a different file
+(e.g. @file{m.lib} or @file{libm.a}). If floating point is used in an
+application, it might be necessary to explicitly link with this library
+(e.g. by specifying @file{-lm}).
+
+In many cases, the include files provide special inline-code or similar
+optimizations. Therefore, it is recommended to always include the
+corresponding include file when using a library function. Even if it
+is not necessary in all cases, it may affect the quality of the generated
+code.
+
+The library implements the functions specified by ISO9899:1989 as well
+as a part of the new functions from ISO9899:1999.
+
+@section Legal
+
+Most parts of this library are public domain. However, for some systems,
+parts may be under a different license. Please consult the system
+specific documentation. Usually, linking against this library will
+not put any restrictions on the created executable unless otherwise
+mentioned.
+
+Parts of the math library (e.g. transcendental functions) are derived
+from Sun's free math library:
+@example
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+@end example
+
+@node SoftfloatHauser
+The softfloat functions, used by some targets, are derived from John
+Hauser's IEC/IEEE Floating-point Artithmetic Package:
+
+@example
+This C source file is part of the SoftFloat IEC/IEEE Floating-point
+Arithmetic Package, Release 2.
+
+Written by John R. Hauser. This work was made possible in part by the
+International Computer Science Institute, located at Suite 600, 1947 Center
+Street, Berkeley, California 94704. Funding was partially provided by the
+National Science Foundation under grant MIP-9311980. The original version
+of this code was written as part of a project to build a fixed-point vector
+processor in collaboration with the University of California at Berkeley,
+overseen by Profs. Nelson Morgan and John Wawrzynek. More information
+is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
+arithmetic/softfloat.html'.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+
+Derivative works are acceptable, even for commercial purposes, so long as
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these three paragraphs for those parts of
+this code that are retained.
+@end example
+
+
+@section Global Variables
+
+@subsection timezone
+
+On some host operating systems vclib might be unable to determine the
+current time zone, which is required for functions like
+@code{mktime()} or @code{localtime()} to work. Here you can overwrite
+the following variables:
+
+@table @code
+@item long __gmtoffset
+ Offset in minutes, west of Greenwich Mean Time (GMT).
+@item int __dstflag
+ Set to non-zero, when Daylight Saving Time is active.
+@end table
+
+Targets which can determine their current time zone, will do so by
+initializing these variables on startup.
+
+
+@section Embedded Systems
+
+This section describes specifics of the C library for embedded systems.
+
+@subsection Startup
+
+The startup is usually split into two parts. The first part is done by
+assembly code that produces the object file @file{lib/startup.o}. This
+assembly code is usually provided with vbcc and may have to be adapted to
+the hardware you are using. The key actions that have to be performed by this
+code are:
+
+@table @minus
+@item hardware initialization
+ It may be necessary to perform some hardware initialization right
+ at the beginning, e.g. to configure the memory system. This has to
+ be modified by the user.
+
+@item variable initializations
+ When running code from ROM, some memory sections have to be
+ initialized. Usually, the init-values of initialized variables
+ have to be copied from ROM to the data segment and the values of
+ un-initialized variables have to be cleared in the bss segment.
+ This code is usually provided in the startup code.
+
+@item stack pointer
+ The stack pointer has to be set to a suitable memory area.
+ The startup code
+ will set the stack pointer to the value of the pointer @code{__stack}.
+ There is a default stack provided in the C library which will be used
+ unless the application defines its own stack using, for example, the
+ following code (assuming that the stack grows downwards):
+@example
+#define STACKSIZE <whatever>
+
+static long mystack[STACKSIZE/sizeof(long)];
+char *__stack=((char*)mystack)+STACKSIZE;
+@end example
+
+@item calling @code{__main}
+ After all the above initializations have been performed, the function
+ @code{__main()} has to be called. This function is provided by the
+ library and performs high-level initializations, if necessary (mainly
+ it calls constructors created by the linker) and will then call the
+ user @code{main()} function. Note that the library
+ may not work correctly if the user @code{main()} function is called
+ directly from the startup code.
+
+@end table
+
+@subsection Heap
+
+When dynamic memory management is used (e.g. by using the @code{malloc()}
+function), a heap memory area is needed to allocate memory from. The
+@code{malloc()} function assumes that @code{__heapptr} is a variable pointing
+to the beginning of the heap memory and that @code{__heapsize} specifies
+the size of the heap area in bytes. The library will provide a default heap
+memory area that can be replaced by adding, for example, the following file
+to the application:
+@example
+#define HEAPSIZE <whatever>
+
+char __heap[HEAPSIZE],*__heapptr=__heap;
+size_t __heapsize=HEAPSIZE;
+@end example
+
+
+@subsection Input/Output
+
+The standard C input/output functions are provided also for embedded systems.
+Reading/writing to a stream will be directed to void unless the following
+low-level I/O-functions are provided by the application:
+@example
+int __open(const char *name,const char *mode);
+void __close(int h);
+size_t __read(int h,char *p,size_t l);
+size_t __write(int h,const char *p,size_t l);
+off_t __seek(int h,off_t offset,int origin);
+@end example
+
+The @code{__open()} function receives a name and a mode string (as in the C
+@code{fopen()} function) as arguments and has to return a file-descriptor if
+it is possible to open this file. The other functions are equivalent to the
+corresponding POSIX functions. @code{__seek} can be implemented to return
+@code{-1} if the functionality is not needed.
+
+Also, @code{stdin, stdout} and @code{stderr} can be used with the standard
+descriptors.
+
+@subsection CTRL-C Handling
+
+Some targets implement handlers to terminate the program on ctrl-c or a
+similar signal. This usually has the same effect as calling
+@code{exit(20)}.
+
+If you want to change or disable the ctrl-c handling, you can overwrite
+the function @code{void _chkabort(void)}.
+
+@subsection Floating Point
+
+Whether floating point is supported, depends on the target architecture and
+chip. If it is supported, there will usually be a math-library that has to
+be linked (using option @option{-lm}) when floating point is used.
+
+@subsection Useless Functions
+
+Of course, some of the C library functions can not be implemented reasonably on
+embedded systems. These functions are contained in the library but will
+always return an error value. Mainly affected are:
+
+@table @minus
+@item locale
+@item time
+@item signal
+@item filesystem functions
+@end table
+
+Depending on the hardware provided by a system it is possible to implement
+these functions and add them to the application. In this case, the new
+functions will be used rather than the default ones returning only error
+values.
+
+@subsection Linking/Locating
+
+To produce ROM images (e.g. in the form of absolute ELF executables, Intel
+Hex files or Motorola S-Records), the linker is called with a linker script.
+This script can be used to join together different sections of the input files
+and locate them to suitable absolute memory areas. Also, this linker script
+can be used to set symbols that may be used by the application or the startup
+code, e.g. addresses of data sections, initialization values or small data
+pointers.
+
+Code or data that has to reside at special locations can be put into a special
+section using the @code{__section} attribute. This section can then be
+placed at the desired location using the linker script.
+
+Usually, an example linker script will be provided. While this is often not
+suitable for different chips, it may serve as a starting point.
+
+
+@section AmigaOS/68k
+
+This section describes specifics of the C library for AmigaOS/68k
+provided by the target @file{m68k-amigaos}.
+The relevant files are @file{startup.o}, @file{minstart.o}, @file{minres.o},
+@file{vc.lib}, @file{vcs.lib}, @file{mieee.lib}, @file{mieees.lib},
+@file{m881.lib}, @file{m881s.lib}, @file{m040.lib}, @file{m040s.lib},
+@file{m060.lib}, @file{m060s.lib}, @file{msoft.lib}, @file{msofts.lib},
+@file{amiga.lib}, @file{amigas.lib}, @file{auto.lib} and @file{autos.lib},
+@file{reaction.lib}, @file{reactions.lib}.
+
+Note that @file{extra.lib} is no longer part of the vbcc distribution.
+It was replaced by 'PosixLib', available on Aminet
+@file{dev/c/vbcc_PosixLib.lha}, which has a much more comprehensive
+support for POSIX and Unix functions.
+
+The following config files are available:
+@table @code
+@item aos68k
+ Standard startup code (@file{startup.o}) with command line parsing
+ and optional Workbench startup (@xref{Standard Startup}).
+@item aos68km
+ Minimal startup code (@file{minstart.o}) without command line
+ parsing. You have to open all libraries yourself (@xref{Minimal Startup}).
+@item aos68kr
+ Minimal startup code (@file{minres.o}) for resident programs.
+ Always compiles in small data mode and links with @file{vcs.lib}
+ (@xref{Minimal Resident}).
+@end table
+
+@node Standard Startup
+@subsection Startup
+
+ The startup code currently consists of a slightly modified standard
+ Amiga startup (@file{startup.o}). The startup code sets up some
+ global variables and initializes stdin, stdout and stderr.
+ The exit code closes all open files and frees all memory.
+ If you link with a math library the startup/exit code will be taken
+ from there if necessary.
+
+
+@node Floating point
+@subsection Floating point
+
+ Note that you have to link with a math library if you want to use
+ floating point. All math functions, special startup code and
+ printf/scanf functions which support floating point are contained in
+ the math libraries only.
+ At the moment there are five math libraries:
+
+@table @file
+@item mieee.lib
+ This one uses the C= math libraries. The startup code
+ will always open MathIeeeSingBas.library,
+ MathIeeeDoubBas.library and MathIeeeDoubTrans.library.
+ Float return values are passed in d0, double return
+ values are passed in d0/d1.
+ A 68000 is sufficient to use this library.
+ You must not specify @option{-fpu=...}
+ when you use this library.
+ By default all floating point routines are provided via stub functions in
+ @file{mieee.lib}. With the option @option{-amiga-softfloat} you can tell
+ @command{vbccm68k} to generate inline code for calling the
+ MathIeee libraries directly.
+
+@item msoft.lib
+ This one is based on John Hauser's IEC/IEEE Floating-point Arithmetic
+ Package (@xref{SoftfloatHauser}) and doesn't need any system libraries for
+ FP emulation. May be slower than the ROM libraries, though.
+ Otherwise everything mentioned for @file{mieee.lib} applies here
+ as well.
+ Note that you have to call the @command{vc} frontend with the
+ @option{-rmcfg-amiga-softfloat} option, when your config file contains
+ @option{-amiga-softfloat} (which is the case for @file{aos68k}
+ since vbcc V0.9h).
+
+@item m881.lib
+ This one uses direct FPU instructions and function
+ return values are passed in fp0. You must have a
+ 68020 or higher and an FPU to use this library. You
+ also have to specify @option{-fpu=68881} or
+ @option{-fpu=68882}.
+ Several FPU instructions that have to be emulated on
+ 040/060 may be used.
+
+@item m040.lib
+ This one uses only direct FPU instructions that do not
+ have to be emulated on a 68040. Other functions use
+ the Motorola emulation routines modified by
+ Aki M Laukkanen and Matthew Hey.
+ It should be used for programs compiled for 68040
+ with FPU.
+ Return values are passed in fp0.
+
+@item m060.lib
+ This one uses only direct FPU instructions that do not
+ have to be emulated on a 68060. Other functions use
+ the Motorola emulation routines modified by
+ Aki M Laukkanen and Matthew Hey.
+ It should be used for programs compiled for 68060
+ with FPU.
+ Return values are passed in fp0.
+@end table
+
+Depending on the CPU/FPU selected, including @file{math.h} will
+cause inline-code generated for certain math functions.
+
+@node amiga-stack
+@subsection Stack
+
+An application can specify the stack-size needed by defining a variable
+@code{__stack} (of type @code{size_t}) with external linkage, e.g.
+
+@example
+size_t __stack=65536; /* 64KB stack-size */
+@end example
+
+The startup code will check whether the stack-size specified is larger
+than the default stack-size (as set in the shell) and switch to a new
+stack of appropriate size, if necessary.
+
+If the @option{-stack-check} option is specified when compiling, the
+library will check for a stack overflow and abort the program, if the
+stack overflows. Note, however, that only code compiled with this
+option will be checked. Calls to libraries which have not been compiled
+with @option{-stack-check} or calls to OS function may cause a stack
+overflow which is not noticed.
+
+Additionally, if @option{-stack-check} is used, the maximum stack-size
+used can be read by querying the external variable @code{__stack_usage}.
+
+@example
+#include <stdio.h>
+
+extern size_t __stack_usage;
+
+main()
+@{
+ do_program();
+ printf("stack used: %lu\n",(unsigned long)__stack_usage);
+@}
+@end example
+
+Like above, the stack used by functions not compiled using
+@option{-stack-check} or OS functions is ignored.
+
+@node amigasmalldata
+@subsection Small data model
+
+When using the small data model of the 68k series CPUs, you also have
+to link with appropriate libraries. Most libraries documented here are
+also available as small data versions (with an 's' attached to the
+file name). Exceptions are the math libraries.
+
+To compile and link a program using the small data model a command like
+
+@example
+vc test.c -o test -sd -lvcs -lamigas
+@end example
+
+might be used.
+
+@subsection Restrictions
+
+The following list contains some restrictions of this version of the
+library:
+
+@table @code
+
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on AmigaOS it is not possible to
+obtain the time used by the calling process.
+
+@end table
+
+@node Minimal Startup
+@subsection Minimal Startup
+
+If you want to write programs that use only Amiga functions and none from
+vc.lib you can use @file{minstart.o} instead of @file{startup.o} and
+produce smaller executables. You can also achieve that by simply using
+the @file{aos68km} config file instead.
+
+This startup code does not set up everything needed by vc.lib, so you
+must not use most of these functions (string and ctype functions are ok,
+but most other functions - especially I/O and memory handling - must not
+be used).
+@code{exit()} is supplied by minstart and can be used.
+
+The command line is not parsed, but passed to @code{main()} as a single
+string,
+so you can declare main as
+@code{int main(char *command)} or @code{int main(void)}.
+
+Also no Amiga libraries are opened (but @code{SysBase} is set up), so you
+have to define and open @code{DOSBase} yourself if you need it.
+If you want to use floating point with the IEEE libraries
+or @option{-amiga-softfloat} you have to
+define and open MathIeeeSingBas.library, MathIeeeDoubBas.library and
+MathIeeeDoubTrans.library (in this order!) and link with mieee.lib (if
+compiled for FPU this is not needed).
+
+A hello world using minstart could look like this:
+
+@example
+#include <proto/exec.h>
+#include <proto/dos.h>
+
+struct DosLibrary *DOSBase;
+
+int main()
+@{
+ if(DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",0))@{
+ Write(Output(),"Hello, world!\n",14);
+ CloseLibrary((struct Library *)DOSBase);
+ @}
+ return 0;
+@}
+
+@end example
+
+This can yield an executable of under 256 bytes when compiled with
+@option{-sc -sd} and linked with @file{minstart.o} and @code{amigas.lib}
+(using @command{vlink} - may not work with other linkers).
+
+@node Minimal Resident
+@subsection Minimal Startup for resident programs
+
+AmigaOS can keep special "pure" programs resident in RAM, and restart them
+from there without having to load them again from disk. To make it easy to
+create such reentrant programs, even with static data, you can link with the
+special startup code @file{minres.o}, which is a minimal startup code for
+resident programs. Or simply use the config file @file{aos68kr} instead.
+Everything mentioned for @file{minstart.o} in the previous section is also
+valid for @file{minres.o}.
+
+To create real resident programs you have to follow the following rules:
+@itemize @minus
+
+@item Compile all your code for the small data model (@option{-sd} option).
+
+@item Avoid absolute references to small data symbols.
+ Usually these are constant pointers to static data.
+ The following example creates such an illegal relocation:
+@example
+int x;
+int const *p = &x;
+@end example
+@command{vlink} warns about all potential problems.
+
+@item Link with the @file{minres.o} startup code,
+ and use the small data
+ versions of linker libraries (@file{vcs.lib}, @file{amigas.lib}, etc.).
+
+@item Set the Pure flag in the file attributes.
+ Load the program into RAM
+ with the AmigaDOS @command{resident} command.
+
+@end itemize
+
+
+@node amigalib
+@subsection amiga.lib
+
+To write programs using AmigaOS (rather than standard C functions
+only), a replacement for the original (copyrighted) @file{amiga.lib}
+is provided with @command{vbcc}. This replacement is adapted to vbcc,
+does not cause collisions with some functions (e.g. @code{sprintf})
+provided by the original @file{amiga.lib} and is available for the
+small data mode as well. It is recommended to always use this library
+rather than the original version.
+
+Additionally, there are header files (in the @file{proto}- and
+@file{inline}-subdirectories) which cause inlined calls to Amiga
+library functions.
+
+Besides some support functions @file{amiga.lib} contains stub routines
+to call functions from all common AmigaOS libraries with stack arguments.
+By including the library's proto header file you make sure that AmigaOS
+functions are called directly by inline code, unless @code{_NO_INLINE}
+is defined.
+
+Preprocessor defines to control the behaviour of vbcc's proto headers:
+@table @code
+@item __NOLIBBASE__
+ Do not declare the library base symbol.
+@item _NO_INLINE
+ Do not use optimized inline code for library function calls.
+@end table
+
+Note that the OS-call inlines have been generated using the NDK3.2 clib
+header files, while trying to keep compatibility to NDK3.9, so it is
+advised to use one of the two NDKs for development.
+Otherwise you will get warnings about missing @code{CONST} typedefs and
+similar.
+
+Specify @option{-lamiga} to link with @file{amiga.lib}.
+
+@node autolib
+@subsection auto.lib
+
+ To link with @file{auto.lib} (or the small data version
+ @file{autos.lib}) specify
+ the @option{-lauto} or @option{-lautos} option to @command{vc}.
+
+ When you are calling a standard Amiga library function without
+ having defined the corresponding library base, then the library base
+ as well as code to open/close it will be taken from @file{auto.lib}.
+
+ By default, @file{auto.lib} will try to open any library version. If you
+ need at least a certain version you can define and set a variable
+ _<library-base>Ver with external linkage, e.g. (on file-scope):
+
+@example
+ int _IntuitionBaseVer = 39;
+@end example
+
+ Note that your program will abort before reaching @code{main()} if one
+ of the libraries cannot be opened. Also note that @file{auto.lib}
+ depends on constructor/destructor handling in vclib, which means it
+ cannot work when linking without vclib, without standard startup code,
+ or only with a minimal startup code, like @file{minstart.o}.
+
+@subsection reaction.lib
+
+The @file{reaction.lib} in @command{vbcc} is a port of Stephan Rupprecht's
+rewrite of the copyrighted linker library, extended and fixed by
+Olaf Barthel for the NDK 3.2 release. This version should work in
+combination with NDK 3.9 as well.
+
+To link with @file{reaction.lib} (or the small data version
+@file{reactions.lib}) specify the @option{-lreaction} or
+@option{-lreactions} option to @command{vc}.
+
+The library contains ReAction GUI class support functions and their
+autoinitialization code. Refer to @file{reaction_lib.doc} from your
+NDK Autodocs for more information. As documented there, the version
+used to automatically open the classes can be defined by the variable
+@code{__reactionversion} with external linkage. Otherwise a default
+of version 0 is used.
+
+
+@section Kickstart1.x/68k
+
+This section describes specifics of the C library for Amiga Kickstart 1.2
+and 1.3 provided by the target @file{m68k-kick13}.
+The relevant files are @file{startup.o}, @file{minstart.o}, @file{minres.o},
+@file{startup16.o}, @file{minstart16.o}, @file{minres16.o},
+@file{vc.lib}, @file{vcs.lib}, @file{m13.lib}, @file{m13s.lib},
+@file{msoft.lib}, @file{msofts.lib}, @file{m881.lib}, @file{m881s.lib},
+@file{amiga.lib}, @file{amigas.lib}, @file{auto.lib} and @file{autos.lib},
+@file{vc16.lib}, @file{vc16s.lib}, @file{m1316.lib}, @file{m1316s.lib},
+@file{msoft16.lib}, @file{msoft16s.lib}, @file{m88116.lib}, @file{m88116s.lib},
+@file{amiga16.lib}, @file{amiga16s.lib}, @file{auto16.lib} and
+@file{auto16s.lib}.
+
+This target makes it possible to develop programs targeted for these older
+versions of the Amiga operating system, using the original Commodore
+Kickstart 1.3 header files. Note that there are also libraries and
+config files for using a 16-bit int ABI, which was common at that time,
+and may have some advantages on 16-bit CPUs, like the 68000 or 68010.
+
+The following config files are available:
+@table @code
+@item kick13
+ Standard startup code (@file{startup.o}) with command line parsing
+ and optional Workbench startup (@xref{Startup13}) using 32-bit int.
+@item kick13m
+ Minimal startup code (@file{minstart.o}) without command line
+ parsing. You have to open all libraries yourself (@xref{Minimal Startup})
+ using 32-bit int.
+@item kick13r
+ Minimal startup code (@file{minres.o}) for resident programs.
+ Always compiles in small data mode and links with @file{vcs.lib}
+ (@xref{Minimal Resident}) using 32-bit int.
+@item kick13s
+ Standard startup code (@file{startup.o}) with command line parsing
+ and optional Workbench startup (@xref{Startup13}) using 16-bit int.
+@item kick13sm
+ Minimal startup code (@file{minstart.o}) without command line
+ parsing. You have to open all libraries yourself (@xref{Minimal Startup})
+ using 16-bit int.
+@item kick13sr
+ Minimal startup code (@file{minres.o}) for resident programs.
+ Always compiles in small data mode and links with @file{vcs.lib}
+ (@xref{Minimal Resident}) using 16-bit int.
+@end table
+
+@node Startup13
+@subsection Startup
+
+ The startup code currently consists of a slightly modified standard
+ AmigaOS 1.3 startup (@file{startup.o}). The startup code sets up some
+ global variables and initializes stdin, stdout and stderr.
+ The exit code closes all open files and frees all memory.
+ If you link with a math library the startup/exit code will be taken
+ from there if necessary.
+
+
+@subsection Floating point
+
+ Note that you have to link with a math library if you want to use
+ floating point. All math functions, special startup code and
+ printf/scanf functions which support floating point are contained in
+ the math libraries only.
+ At the moment there are two math libraries:
+
+@table @file
+@item m13.lib
+ This one uses the C= math libraries present under Kickstart 1.2 and 1.3.
+ The startup code will always open mathffp.library,
+ MathIeeeDoubBas.library and MathIeeeDoubTrans.library.
+ Note that all single precision floating point calculations take place
+ in FFP format and have to be converted between FFP and IEEE by the
+ library.
+ Float return values are passed in d0, double return
+ values are passed in d0/d1.
+ A 68000 is sufficient to use this library.
+ You must not specify @option{-fpu=...}
+ when you use this library.
+
+@item msoft.lib
+ This one is based on John Hauser's IEC/IEEE Floating-point Arithmetic
+ Package (@xref{SoftfloatHauser}) and doesn't need any system libraries for
+ FP emulation. May be slower than the ROM libraries, though.
+ Otherwise everything mentioned for @file{m13.lib} applies here
+ as well.
+
+@item m881.lib
+ This one uses direct FPU instructions and function
+ return values are passed in fp0. You must have a
+ 68020 or higher and an FPU to use this library. You
+ also have to specify @option{-fpu=68881}.
+ Several FPU instructions that have to be emulated on
+ 040/060 may be used.
+@end table
+
+@subsection Stack
+
+Stack-checking is available similar to AmigaOS/68k (@xref{amiga-stack}).
+But there is no automatic stack-extension under Kickstart 1.3 and a
+@code{__stack} variable will be ignored.
+
+@subsection Small data model
+
+Small data is supported as described for AmigaOS/68k (@xref{amigasmalldata}).
+The startup code takes care of clearing the unititalized part of a
+small data section (which Kickstart 1.x fails to do).
+
+@subsection Restrictions
+
+The following list contains some restrictions of this version of the
+library:
+
+@table @code
+
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on AmigaOS it is not possible to
+obtain the time used by the calling process.
+
+@end table
+
+@subsection amiga.lib
+
+@xref{amigalib}.
+
+This version of @file{amiga.lib} only supports the functionality present
+in Kickstart 1.2/1.3.
+
+@subsection auto.lib
+
+This library corresponds to the AmigaOS/68k version (@xref{autolib}), but
+only supports libraries of Kickstart 1.3.
+
+@subsection Minimal Startup
+
+You can use @file{minstart.o} similar to AmigaOS/68k (@xref{Minimal Startup}).
+
+@subsection Minimal Startup for Resident Programs
+
+You can use @file{minres.o} similar to AmigaOS/68k (@xref{Minimal Resident}).
+
+
+@section PowerUp/PPC
+
+This section describes specifics of the C library for PowerUp/PPC
+provided by the target @file{ppc-powerup}.
+The relevant files are @file{startup.o}, @file{minstart.o},
+@file{libvc.a}, @file{libvcs.a}, @file{libm.a}, @file{libms.a}
+@file{libamiga.a}, @file{libamigas.a},
+@file{libauto.a} and @file{libautos.a}.
+
+Note that @file{libextra.a} is no longer part of the vbcc distribution.
+It was replaced by 'PosixLib', available on Aminet
+@file{dev/c/vbcc_PosixLib.lha}, which has a much more comprehensive
+support for POSIX and Unix functions.
+
+@subsection Startup
+
+ The startup code @file{startup.o} sets up some
+ global variables and initializes stdin, stdout and stderr.
+ The exit code closes all open files and frees all memory.
+ If you link with a math library the startup/exit code will be taken
+ from there if necessary.
+
+@subsection Floating point
+
+ Note that you have to link with a math library if you want to use
+ floating point. All math functions, special startup code and
+ printf/scanf functions which support floating point are contained in
+ the math libraries only.
+
+ The math library (@file{libm.a}) is linked against the floating point
+ library libmoto by Motorola.
+
+Depending on the CPU/FPU selected, including @file{math.h} will
+cause inline-code generated for certain math functions.
+
+@subsection Stack
+
+Stack-handling is similar to AmigaOS/68k (@xref{amiga-stack}).
+The only difference is that stack-swapping cannot be done. If the
+default stack-size is less than the stack-size specified with
+@code{__stack} the program will abort.
+
+@subsection Small data model
+
+When using the small data model of the PPC series CPUs, you also have
+to link with appropriate libraries. Most libraries documented here are
+also available as small data versions (with an 's' attached to the
+file name). Exceptions are the math libraries.
+
+To compile and link a program using the small data model a command like
+
+@example
+vc test.c -o test -sd -lvcs -lamigas
+@end example
+
+might be used.
+
+@subsection Restrictions
+
+The following list contains some restrictions of this version of the
+library:
+
+@table @code
+
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on AmigaOS it is not possible to
+obtain the time used by the calling process.
+
+@end table
+
+@subsection Minimal Startup
+
+The provided minimal startup code (@file{minstart.o}) is used
+similarly like the one for 68k (@xref{Minimal Startup}). Only use
+it if you know what you are doing.
+
+@subsection libamiga.a
+
+To write programs accessing AmigaOS (rather than standard C functions
+only), a replacement for the original (copyrighted) @file{amiga.lib}
+is provided with @command{vbcc}. This replacement (@file{libamiga.a})
+automatically performs a necessary context switch to the 68k to execute
+the system call. Furthermore, it is adapted to vbcc,
+does not cause collisions with some functions (e.g. @code{sprintf})
+provided by the original @file{amiga.lib} and is available in
+small data.
+
+Specify @option{-lamiga} to link with @file{libamiga.a}.
+
+@subsection libauto.a
+
+This library corresponds to the AmigaOS/68k version (@xref{autolib}).
+
+@section WarpOS/PPC
+
+This section describes specifics of the C library for WarpOS/PPC
+provided by the target @file{ppc-warpos}.
+The relevant files are @file{startup.o},
+@file{vc.lib}, @file{m.lib}, @file{amiga.lib} and @file{auto.lib}.
+
+Note that @file{extra.lib} is no longer part of the vbcc distribution.
+It was replaced by 'PosixLib', available on Aminet
+@file{dev/c/vbcc_PosixLib.lha}, which has a much more comprehensive
+support for POSIX and Unix functions.
+
+@subsection Startup
+
+ The startup code @file{startup.o} sets up some
+ global variables and initializes stdin, stdout and stderr.
+ The exit code closes all open files and frees all memory.
+ If you link with a math library the startup/exit code will be taken
+ from there if necessary.
+
+@subsection Floating point
+
+ Note that you have to link with a math library if you want to use
+ floating point. All math functions, special startup code and
+ printf/scanf functions which support floating point are contained in
+ the math libraries only.
+
+ The math library (@file{m.lib}) contains functions from Sun's
+ portable floating point library. Additionally, there is a
+ @command{vbcc} version of Andreas Heumann's @file{ppcmath.lib}.
+ These routines are linked against Motorola's floating point
+ routines optimized for PowerPC and therefore are much faster.
+
+ To make use of this library, link with @file{ppcmath.lib} before
+ @file{m.lib}, e.g.
+
+@example
+ vc test.c -lppcmath -lm
+@end example
+
+
+
+Depending on the CPU/FPU selected, including @file{math.h} will
+cause inline-code generated for certain math functions.
+
+@subsection Stack
+
+Stack-handling is similar to AmigaOS/68k (@xref{amiga-stack}).
+
+@subsection Restrictions
+
+The following list contains some restrictions of this version of the
+library:
+
+@table @code
+
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on AmigaOS it is not possible to
+obtain the time used by the calling process.
+
+@end table
+
+@subsection amiga.lib
+
+To write programs accessing AmigaOS (rather than standard C functions
+only), a replacement for the original (copyrighted) @file{amiga.lib}
+is provided with @command{vbcc}. This replacement
+automatically performs a necessary context switch to the 68k to execute
+the system call. Furthermore, it is adapted to vbcc,
+does not cause collisions with some functions (e.g. @code{sprintf})
+provided by the original @file{amiga.lib} and is available in
+small data.
+
+Specify @option{-lamiga} to link with @file{amiga.lib}.
+
+
+@subsection auto.lib
+
+This library corresponds to the AmigaOS/68k version (@xref{autolib}).
+
+
+@section MorphOS/PPC
+
+This section describes specifics of the C library for MorphOS/PPC
+provided by the target @file{ppc-morphos}.
+The relevant files are @file{startup.o}, @file{minstart.o},
+@file{libvc.a}, @file{libvcs.a}, @file{libm.a}, @file{libms.a}
+@file{libamiga.a}, @file{libamigas.a},
+@file{libauto.a} and @file{libautos.a}.
+
+Note that @file{libextra.a} is no longer part of the vbcc distribution.
+It was replaced by 'PosixLib', available on Aminet
+@file{dev/c/vbcc_PosixLib.lha}, which has a much more comprehensive
+support for POSIX and Unix functions.
+
+@subsection Startup
+
+ The startup code @file{startup.o} sets up some
+ global variables and initializes stdin, stdout and stderr.
+ The exit code closes all open files and frees all memory.
+ If you link with a math library the startup/exit code will be taken
+ from there if necessary.
+
+@subsection Floating point
+
+ Note that you have to link with a math library if you want to use
+ floating point. All math functions, special startup code and
+ printf/scanf functions which support floating point are contained in
+ the math libraries only.
+
+ The math library (@file{libm.a}) is linked against the floating point
+ library libmoto by Motorola.
+
+Depending on the CPU/FPU selected, including @file{math.h} will
+cause inline-code generated for certain math functions.
+
+@subsection Stack
+
+Stack-handling is similar to AmigaOS/68k (@xref{amiga-stack}).
+
+@subsection Small data model
+
+When using the small data model of the PPC series CPUs, you also have
+to link with appropriate libraries. Most libraries documented here are
+also available as small data versions (with an 's' attached to the
+file name). Exceptions are the math libraries.
+
+To compile and link a program using the small data model a command like
+
+@example
+vc test.c -o test -sd -lvcs -lamigas
+@end example
+
+might be used.
+
+@subsection Restrictions
+
+The following list contains some restrictions of this version of the
+library:
+
+@table @code
+
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on MorphOS it is not possible to
+obtain the time used by the calling process.
+
+@end table
+
+@subsection libamiga.a
+
+To write programs using AmigaOS compatible functions, a replacement for
+the original (copyrighted) @file{amiga.lib}
+is provided with @command{vbcc}. This replacement (@file{libamiga.a})
+will invoke the MorphOS 68k emulator to execute the system function.
+Furthermore, it is adapted to vbcc and
+does not cause collisions with some functions (e.g. @code{sprintf})
+and is available in small data.
+
+Specify @option{-lamiga} to link with @file{libamiga.a}.
+
+
+@subsection libauto.a
+
+This library corresponds to the AmigaOS/68k version (@xref{autolib}).
+
+
+@section AmigaOS4/PPC
+
+This section describes specifics of the C library for AmigaOS4/PPC
+provided by the target @file{ppc-amigaos}.
+The relevant files are @file{startup.o}, @file{minstart.o},
+@file{libvc.a}, @file{libvcs.a}, @file{libm.a}, @file{libms.a}
+@file{libamiga.a}, @file{libamigas.a},
+@file{libauto.a} and @file{libautos.a}.
+
+Note that @file{libextra.a} is no longer part of the vbcc distribution.
+It was replaced by 'PosixLib', available on Aminet
+@file{dev/c/vbcc_PosixLib.lha}, which has a much more comprehensive
+support for POSIX and Unix functions.
+
+@subsection Startup
+
+The startup code @file{startup.o} sets up some
+global variables and initializes stdin, stdout and stderr.
+Then it runs all constructors of dynamically linked libraries, before
+entering the main program.
+The exit code runs all destructors of dynamically linked libraries,
+closes all open files and frees all memory.
+If you link with a math library the startup/exit code will be taken
+from there if necessary.
+
+@subsection Floating point
+
+Note that you have to link with a math library if you want to use
+floating point. All math functions, special startup code and
+printf/scanf functions which support floating point are contained in
+the math libraries only.
+
+The math library (@file{libm.a}) is linked against the floating point
+library libmoto by Motorola.
+
+Depending on the CPU/FPU selected, including @file{math.h} will
+cause inline-code generated for certain math functions.
+
+@subsection Stack
+
+There is no automatic stack extension for AmigaOS 4! This should be
+done automatically by the operating system.
+
+@subsection Small data model
+
+When using the small data model of the PPC series CPUs, you also have
+to link with appropriate libraries. Most libraries documented here are
+also available as small data versions (with an 's' attached to the
+file name). Exceptions are the math libraries.
+
+To compile and link a program using the small data model a command like
+
+@example
+vc test.c -o test -sd -lvcs -lamigas
+@end example
+
+might be used.
+
+@subsection Dynamic linking
+Since @file{elf.library} @code{V52.2} AmigaOS4 supports dynamic linking with
+shared object files (@file{.so} extension), similar to Unix. The default
+behaviour is to prefer linking against a shared object over a static
+library. To force static linking you might want to give the
+@option{-static} option to the @file{vc} frontend.
+
+@subsection Restrictions
+
+The following list contains some restrictions of this version of the
+library:
+
+@table @code
+
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because on AmigaOS it is not possible to
+obtain the time used by the calling process.
+
+@item Small data in dynamically linked executables
+There is a bug in @file{elf.library} @code{V52.4} (and earlier), which
+doesn't load @code{.sdata} and @code{.sbss} as a contiguous block into
+memory, when the executable requires dynamic linking. I decided against
+writing a workaround, as the bug should be fixed in OS4.
+
+@end table
+
+@subsection libamiga.a
+
+In contrast to other amigalibs the OS4 @file{libamiga.a} doesn't contain
+any stubs for calling system functions. AmigaOS 4 system calls are done
+through special macros in the SDK's interface header files.
+
+The library only includes some remaining amigalib functions, not already
+integrated into the OS, like @code{CreateIO()}, but its use is discouraged.
+
+Specify @option{-lamiga} to link with @file{libamiga.a}.
+
+
+@subsection libauto.a
+
+Include auto-open and -close functions for the most common OS libraries and
+interfaces. May also be used together with newlib (see below).
+
+
+@subsection newlib
+
+@subsubsection Introduction
+
+ newlib.library is a shared AmigaOS4 library, which is covered by
+ several BSD like licenses,
+ and includes standard ANSI and POSIX functions as well as some
+ functions common in Unix, BSD and similar operating systems. It is
+ part of the OS4 SDK.
+
+ The config file @file{newlib} will be created on installation to
+ use the paths for header files and libraries pointing to the
+ newlib from the SDK.
+
+ What are the main differences between vclib and newlib?
+
+@itemize @minus
+@item vclib contains (almost) only standard ANSI-C and some ISO-C99
+ functions. If you want to port Unix programs you will probably
+ miss a lot of functions.
+ Also newlib supports things like mapping Unix directory paths to
+ Amiga paths or expanding wildcards in command lines automatically.
+
+@item Programs compiled for newlib will be shorter because the code for all
+ functions is not contained in the executable itself.
+
+@item Programs compiled for newlib will need the shared object
+ @file{libc.so} present when started.
+
+@item Programs compiled for newlib will probably need more memory because
+ the entire (rather large) @file{libc.so} will be loaded into memory.
+ With vclib only the functions your program uses will be in RAM.
+ However if you have several programs using newlib at the same
+ time only one copy of @file{libc.so} should be loaded.
+@end itemize
+
+ Things you should note:
+
+@itemize @minus
+@item With newlib you do not need extra math-libraries.
+
+@item You must link with a vbcc-specific @file{startup.o} from the newlib
+ @file{lib/} directory as startup code.
+ The config-file @file{newlib} will usually take care of this.
+
+@item You _must_ use the newlib-includes from the SDK
+ rather than the ones which are for vc.lib.
+ The config-file @file{newlib} will usually take care of this.
+
+@item There may be vbcc-related bugs in the SDK-newlib. Patches are
+ automatically installed when using the Amiga Installer. When
+ installing the target manually, you also have to fix the SDK
+ manually. For a list of known SDK bugs at this point of time,
+ @xref{Known Newlib Bugs}.
+@end itemize
+
+@node Known Newlib Bugs
+@subsubsection Known Newlib Bugs
+
+@itemize @minus
+
+@item The @code{__asm_toupper()} and @code{__asm_tolower()} assembler inlines
+ in @file{newlib/include/ctype.h} are wrong, which makes
+ @code{toupper()} and @code{tolower()} fail when including
+ @file{ctype.h}. Fix:
+@example
+--- ctype.h.orig 2006-04-03 18:00:00.000000000 +0200
++++ ctype.h 2017-05-07 19:32:00.000000000 +0200
+@@@@ -64,8 +64,8 @@@@
+ #elif defined(__VBCC__)
+ int __asm_toupper(__reg("r3") int) =
+ "\t.extern\t__ctype_ptr\n"
+- "\tlis\t11,(__ctype_ptr)@@ha\n"
+- "\taddi\t11,11,(__ctype_ptr)@@l\n"
++ "\tlis\t11,__ctype_ptr@@ha\n"
++ "\tlwz\t11,11,__ctype_ptr@@l(11)\n"
+ "\tlbzx\t12,11,3\n"
+ "\tandi.\t12,12,2\n"
+ "\tbeq\t$+8\n"
+@@@@ -73,8 +73,8 @@@@
+ "#barrier";
+ int __asm_tolower(__reg("r3") int) =
+ "\t.extern\t__ctype_ptr\n"
+- "\tlis\t11,(__ctype_ptr)@@ha\n"
+- "\taddi\t11,11,(__ctype_ptr)@@l\n"
++ "\tlis\t11,__ctype_ptr@@ha\n"
++ "\tlwz\t11,11,__ctype_ptr@@l(11)\n"
+ "\tlbzx\t12,11,3\n"
+ "\tandi.\t12,12,1\n"
+ "\tbeq\t$+8\n"
+@end example
+Note: This should be fixed with the latest OS4 SDK, and the V0.9h
+installer will no longer install a patch!
+
+@item Newlib's @file{libauto.a} contains no working vbcc-style
+constructors or destructors for auto-opening or -closing of libraries.
+You can work-around it, by copying vclib's @file{libauto.a} to
+newlib's lib-directory. Rename it, if you don't want to overwrite
+the gcc-version of it.
+
+@item Some header files, like @file{sys/stat.h}, use the reserved vbcc
+attribute @code{__mask} as an argument name. The config file should
+take care of that, by redefining it as @code{___mask}.
+
+@end itemize
+
+@subsubsection Usage
+
+To compile a program to use newlib for OS4 you must make sure the proper
+config-file (@file{newlib}) is used, e.g.
+
+@example
+ vc +newlib hello.c
+@end example
+
+With a new SDK this will usually generate a dynamically linked executable,
+which requires @file{libc.so}. To force a statically linked executable:
+
+@example
+ vc +newlib -static hello.c
+@end example
+
+
+@section Atari TOS/MiNT
+
+This section describes specifics of the C library for Atari TOS and MiNT.
+M680x0 processors are supported by the target @file{m68k-atari}, while
+ColdFire processors are supported by the target @file{cf-atari}. Both
+share the same startup-code and are based on common library sources and
+header files. Executables linked with this C library run on plain TOS as
+well as on MiNT, without modifications.
+
+The relevant files are @file{startup.o}, @file{minstart.o},
+@file{libvc.a}, @file{libm.a}, @file{libgem.a}. For the M68k target
+there are also math libs with FPU support (@file{libm881.a},
+@file{libm040.a} and @file{libm060.a}) and 16-bit integer versions
+of all libraries (@file{lib*16.a}).
+
+The following config files are available:
+@table @code
+@item tos
+ M68k 32-bit @code{int} for classic TOS machines.
+@item tos16
+ M68k 16-bit @code{int} for classic TOS machines.
+@item mint
+ M68k 32-bit @code{int} for MiNT. Also works on classic machines,
+ but uses an embedded a.out header for MiNT, includes a changeable
+ @code{__stksize} and sets the FastLoad, FastRAM and FastAlloc flags
+ in the header.
+@item mintcf
+ ColdFire 32-bit @code{int}. Otherwise same as @file{mint}.
+@end table
+
+@subsection Startup
+
+The startup code @file{startup.o} sets up some
+global variables and initializes stdin, stdout and stderr and returns
+the unneeded memory to the system.
+The exit code closes all open files and frees all memory.
+
+@subsection Floating point
+
+Note that you have to link with a math library if you want to use
+floating point. All math functions, special startup code and
+printf/scanf functions which support floating point are contained in
+the math libraries only.
+
+On the M68k target you have the option to enable FPU support with
+the @option{-fpu} option and choose the appropriate math library
+(@xref{Floating point}). Otherwise, there is a soft-float library,
+which is compatible with all the Atari models without an FPU.
+
+@subsection Stack
+
+The default stack size is 64k. There is a MiNT tool called @file{stack}
+which can adjust the stack size of an executable to any value, by looking
+for a symbol named @code{__stksize} (defined by vclib's startup code).
+
+Additionally the required stack size can be specified by defining a
+variable @code{__stack} (of type @code{size_t}) with external linkage, as
+in other vbcc targets.
+
+@subsection 16-bit integer model
+
+The default libraries use 32-bit @code{int} types, but you may want to
+use 16-bit @code{int} types for compatibility reasons. In this case you
+have to specify the config file @code{tos16} and link with the appropriate
+16-bit libraries (which have a '@file{16}' attached to their name).
+
+To compile and link a program using 16-bit integers a command like
+
+@example
+vc +tos16 test.c -o test -lm16 -lvc16
+@end example
+
+may be used. There are no 16-bit versions for ColdFire targets,
+because this is strictly a 32-bit CPU.
+
+@subsection Restrictions
+
+The following list contains some restrictions of this version of the
+library:
+
+@table @code
+
+@item tmpfile()
+The @code{tmpfile()} function always returns an error.
+
+@item clock()
+The @code{clock()} function always returns -1. This is correct,
+according to the C standard, because neither under TOS nor under MiNT it
+is possible to obtain the time used by the calling process.
+
+@end table
+
+@section VideoCore/Linux
+
+This section describes specifics of the C library for VideoCore under Linux
+provided by the target @file{vidcore-linux}.
+
+The relevant files are @code{vcload}, @file{startup.o},
+@file{libvc.a}, @file{libm.a}, @file{libms.a}.
+
+The config file @code{vc4-linux} is part of the library.
+
+@subsection Startup
+
+The startup code @file{startup.o} sets up stack and heap and provides
+a function @code{__armcall()} to transfer control to the loader on
+the ARM side.
+The startup process calls constructors to set up some
+global variables and initialize stdin, stdout and stderr if needed.
+
+@subsection Floating point
+
+Note that you have to link with a math library if you want to use
+floating point operations that are not natively implemented.
+All math functions, special startup code and
+printf/scanf functions which support floating point are contained in
+the math libraries only.
+
+@subsection Stack
+
+The library contains a default stack of 32KB. If another size is needed,
+you can add the following to your project:
+
+@example
+ .align 4
+ .space <desired-size, suitably aligned>
+___stackend:
+ .global ___stackend
+@end example
+
+@subsection Heap
+
+Currently, a global variable of 16KB is used to get memory for
+malloc() etc. If another size is needed,
+you can add the following to your project:
+
+@example
+#define HEAPSIZE <desired size>
+
+char __heap[HEAPSIZE],*__heapptr=__heap;
+size_t __heapsize=HEAPSIZE;
+@end example
+
+Note that this mechanism will likely be changed in the future!
+
+@subsection System Calls
+
+To access system functions from the VideoCore-side, the function
+@code{__armcall()} can be used. It will save the current context and return
+to the loader. Registers @code{r0-r5} (the function arguments) will be saved
+and are available to the loader. The loader can then execute the system
+call and resume execution, passing the return value of the system
+function.
+
+Resuming is done by calling the image with offset 2.
+
+This functionality can also be used for debugging purposes.
+
+@subsection Loader
+
+A loader is required to execute VideoCore code from the ARM side. For
+standalone VideoCore code, the provided loader can be used. Usually, it
+will be necessary to adapt the loader to communicate between ARM and
+VideoCore side during runtime.
+
+@subsubsection Object Format
+
+Currently, the loader loads an simple binary image that must be pc-relative
+and located to address 0x00000000. Additionally, if present, a file
+with extension @file{.reltext} will be loaded for some limited
+relocation. This file contains a 32bit word containing the number of
+relocations followed by n 32bit words containing an offset. For each
+offset, the address will be relocated to the image load address.
+
+@subsubsection Command line arguments
+
+@code{vcload [-debug] [-cache] [-offset] <image-name>}
+
+The loader currently has the following options:
+
+@table @code
+
+@item -debug
+
+ The loader will enter debug mode (see below).
+
+@item -cache
+
+ The loader will set the LSB in the start address when executing
+ code. This is supposed to inhibit a cache flush.
+
+ Just for testing!
+
+@item -offset
+
+ The loader will allocate 1 KB more memory than required and leaves
+ this space unused at the beginning of the allocated memory.
+
+ Just for testing!
+
+@end table
+
+@subsubsection Debug Mode
+
+In debug mode, the loader will wait for user input before starting the
+VideoCore code as well as after every @code{__armcall}.
+
+The following commands are available:
+
+@table @code
+@item w <addr> [<num>]
+ Display <num> 32bit words starting at <addr>.
+ <addr> must be the offset into the image. If <num> is omitted,
+ one unit is displayed.
+
+ If one word is displayed, it is additionally displayed translated
+ as an offset into the image.
+
+@item h <addr> [<num>]
+ Display <num> 16bit halfwords starting at <addr>.
+ <addr> must be the offset into the image. If <num> is omitted,
+ one unit is displayed.
+
+@item b <addr> [<num>]
+ Display <num> 8bit bytes starting at <addr>.
+ <addr> must be the offset into the image. If <num> is omitted,
+ one unit is displayed.
+
+@item c
+ Start/continue execution.
+
+@item q
+ Quit.
+
+@item bp <addr>
+ Set a breakpoint at <addr>.
+
+ This is currently a very crude implementation. It will just write
+ a branch to @code{__armcall()} to <addr>. If everything works well,
+ you will end in the debugger if <addr> is reached. However, the
+ arguments passed are random (and might be dangerous syscalls by
+ accident). Also, the old code at this address is currently not
+ restored.
+
+ As a result, you must not continue execution after hitting a
+ breakpoint!
+@end table
+
+
+@subsection Restrictions
+
+The following list contains some restrictions of this version of the
+library:
+
+@itemize @minus
+
+@item no real floating point support yet
+
+@item lots, lots, lots...
+
+
+@end itemize
+
+@section ATARI Jaguar/68k
+
+This section describes specifics of the C library for ATARI Jaguar
+provided by the target @file{m68k-jaguar}.
+
+The relevant files are @file{startup.o},
+@file{libvc.a}, @file{libm.a}, @file{libjag.a}.
+
+The config files @code{jaguar_unix} and @code{jaguar_windows} are part of the library.
+
+@subsection Startup
+
+The startup code @file{startup.o} sets up stack and heap.
+The startup process calls constructors to set up some
+global variables and initialize stdin, stdout and stderr.
+
+The ATARI Jaguar has no OS, so it is impossible to define how input, output and files
+can be handled. There are a few set of function you have to define if you want to use stdio.
+
+Alternatively you can use the @file{libjag.a}. This library initializes a console window with stdout
+support and uses optionally a SkunkBoard to redirect stderr and file I/O.
+
+@subsection Floating point
+
+Note that you have to link with a math library if you want to use
+floating point operations that are not natively implemented.
+All math functions, special startup code and
+printf/scanf functions which support floating point are contained in
+the math library only. Consider the ATARI Jaguar does not own a FPU so this library is pretty slow.
+
+@subsection Stack
+
+The library contains a default stack of 32KB. If another size is needed,
+you can add a global variable named __stack to your code:
+
+@example
+
+/* Set 64kB stack */
+unsigned long __stack = 65536;
+
+@end example
+
+@subsection Heap
+
+Currently the free RAM is used as global heapsize for malloc() etc.
+
+It is necessary to place a symbol named _BSS_END at the end of the BSS segment.
+The heap allocates the free RAM between _BSS_END and the bottom of the stack.
+
+If less size is needed feel free to manipulate the value of _BSS_END.
+
+All allocated heap objects can be used as internal JAGUAR objects, because they are qhrase aligned.
+
+@subsection stdio support
+
+The ATARI Jaguar lacks stdio support. So the @file{libvc.a} has just empty stub functions for
+open, close, read and write, which you may overwrite if you need stdio.
+Alternatively you can use @file{libjag.a} which has simple stdio
+and file I/O functionality.
+
+@example
+/**
+ * param name: name mentioned in fopen
+ * param mode: mode mentioned in fopen
+ * returns: > 0 a valid file handle
+ * < 0 to indicate an error
+ * the values 0,1,2 are used by stdin, stdout and stderr
+ *
+ * No need to handle stdin, stdout and stderr here
+ */
+int jagopen(const char *name,const char *mode)
+
+/**
+ * param handle: handle from jagopen
+ *
+ * No need to handle stdin, stdout and stderr here
+ */
+void jagclose(int handle)
+
+/**
+ * param handle: handle from jagopen
+ * param p: points to the char buffer to fill.
+ * param l: buffer size of p
+ * returns: >=0 number of read bytes
+ <0 indicate an error
+ *
+ * Handle stdin, stdout and stderr here
+ */
+size_t jagread(int handle,char *p,size_t l)
+
+/**
+ * param handle: handle from jagopen
+ * param p: points to the char buffer to write.
+ * param l: number of bytes of p
+ * returns: >=0 number of bytes written
+ <0 indicate an error
+ *
+ * Handle stdin, stdout and stderr here
+ */
+size_t jagwrite(int handle,const char *p, size_t l)
+
+/**
+ * param handle: handle from jagopen
+ * param offset: number of bytes to seek.
+ * param direction: see fseek direction
+ * returns: =0 successful seek
+ <>0 indicate an error
+ -1: seek not supported
+ *
+ * Handle stdin, stdout and stderr here
+ */
+long jagseek(int handle,long offset,int direction)
+@end example
+
+@subsection The jaglib
+
+The jaglib @file{libjag.a} provides simple functions to support your first
+steps in ATARI Jaguar programming. It initializes a simple console output window and comes with
+an old ATARI character set.
+If a SkunkBoard is available I/O functionality can be redirected.
+
+Your first Jaguar program can look like this:
+
+@example
+
+#include <stdio.h>
+
+int main()
+@{
+ printf("Hello, world\n");
+@}
+
+@end example
+
+Keep in mind: Your JAGUAR will get a red background color to indicate @code{main()} has exited.
+
+The jaglib API documentation is available in a separate document. There is more demo code
+available in the @uref{https://github.com/toarnold/jaglib-demo, jaglib-demo} gibhub repository.
+
+@section 6502/C64
+
+This is a port of vclib to the C64.
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x801. A BASIC line is included so that the program can be started using @code{RUN}
+from BASIC. The startup code
+will turn off the BASIC ROM to allow usage of RAM until 0xD000 and most of the
+zero page without need for any special handling. The BSS segment will be cleared
+during startup.
+
+With the default configuration, after exiting the C program, an infinite loop will
+be entered. When using the @code{+c64r} config, the program will return to BASIC
+an can be started again.
+However, this needs additional memory as the init values for the data section have
+to be stored in RAM. Also, some register values and zero page contents have to be
+saved. The overhead depends on the amount of initialized variables.
+
+@subsubsection Command line
+
+Command line parameters are supported by using the convention/code submitted by
+Stefan Haubenthal.
+
+Command-lines look like these lines:
+
+@example
+ run
+ run : rem
+ run:rem arg1 " arg 2 is quoted " arg3 "" arg5
+@end example
+
+
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x02..0x8d}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the user stack is mapped from @code{0xC800..0xD000}. The size can be
+changed at the top of @code{vlink.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting after the BASIC init line.
+The heap is placed in the remaining space to stack start.
+
+@subsubsection Banking
+
+The following banking models are supported:
+
+@table @code
+@item -reuflat
+ This library supports a REU using a flat 16MB address space. The memory has to
+ be addressed through far-pointers. It is not possible to declare variables in
+ the REU nor to place code in the REU. The memory is addressed as 0x000000 to
+ 0xFFFFFF. All accesses through far-pointers are addressing the REU. It is not
+ possible to address the C64 memory through a far-pointer.
+
+ Far-pointer arithmetic only works on the lower 16bits. It is not possible to
+ cross a bank boundary using far-pointers. Huge-pointers will support this, but
+ are not yet fully implemented. In the meantime it is possible to use long integers
+ and cast them to far-pointers.
+
+ Use @code{-lreuflat} to link with this library. Note that the library does
+ not check for the presence of a REU.
+
+@item -reubank
+ This configuration reserves a 16KB memory space within the C64 memory as window
+ for banking. As the bank number is stored as a single byte (with bank
+ 255 denoting the unbanked memory), it is only possible to address up to
+ about 4MB of memory in the REU.
+
+ Variables and code can be mapped into the REU using the @code{__bank()} attribute
+ or @code{#pragma bank}. When calling a banked function, the corresponding bank
+ will be copied from the REU into the C64 memory window.
+
+ Use the @code{+c64reu} configuration to use this mechanism. Currently the
+ linker file provides 8 banks resulting in a 128K REU image. More banks can
+ be added for larger expansions.
+
+ The configuration will create a usually C64 prg file containing the unbanked
+ code and data as well as a REU image with extension @code{.b0}. It must
+ be loaded (e.g. with an emulator or the TurboChameleon) before the prg file
+ can is executed.
+@end table
+
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+stdio supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (keyboard). Both are unbuffered by default.
+
+Furthermore, file IO with standard C functions is supported
+for 1541 and compatible disk drives. Other devices have not been tested.
+Only sequential reading and writing of files is supported. No seeking etc.
+There are hardcoded limits for the maximum number of open files and the
+maximum length of filenames.
+
+The @code{remove()} and @code{rename()} functions are supported using 1541
+
+By default, device ID 8 is used. Another device ID can be specified as prefix
+to the filename:
+
+@example
+ /* try to open file "test" on the second drive */
+ FILE *f;
+ f=fopen("9:test","r");
+ ...
+@end example
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
+
+@section 6502/NES
+
+This is a port of vclib to the NES console.
+
+
+@subsection Startup and Memory
+
+Startup and memory layout is dependent on the ROM used. Currently two example configurations
+are provided. They can be selected with @code{+nrom256v} and @code{+unrom512v}. Have a
+look at the corresponding linker scripts in @code{vbcc/targets/6502-nes} for further
+details.
+
+The necessary library routines to support configurations with several ROM banks are
+included.
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. The entire zero page can be used, but this can be changed
+in the linker file.
+
+@subsubsection Stack
+
+By default, the user stack starts from @code{0x0800} growing downwards.
+
+@subsubsection Heap
+
+By default, code and data/BSS are mapped starting after the system stack at @code{0x0200}.
+The heap is placed in the remaining space to stack start.
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+At the moment, stdio only supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (simple input via joypad).
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+For input, up/down changes the current character, left/right moves the cursor,
+the B button deletes from the cursor position, and the A button confirms the input.
+You do not want to use this in real code.
+
+The library contains a default character set. To replace it, link an object that
+contains a character set mapped to section @code{chars} and defines the global symbol
+@code{___stdchr}.
+
+To replace stdio, the function @code{__read()} and @code{__write()} have to be
+implemented.
+
+@subsection Interrupts
+
+The library contains a default NMI implementation that is used for stdio handling
+and the @code{clock()}-function. It can be replaced by linking with an own
+implementation that starts at the global symbol @code{___nmi}. In this case the stdio and
+timing functions from vclib can not be used.
+
+@code{___irq} can be used to overwrite the other IRQ vector. The default implementation
+in the library immediately returns.
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+IEEE floating point is currently not available for this target.
+
+
+@section 6502/Atari
+
+This is a port of vclib to Atari 8bit computers.
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x600. The memory area can be adapted by changing @code{MEMSTART} and
+@code{MEMEND} in @code{vlink.cmd}.
+
+With the default configuration, after exiting the C program, it will wait
+for pressing the return key before returning to DOS.
+
+@subsubsection Command line
+
+Command line parameters are not yet supported.
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x82..0xFF}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the startup code maps the user stack from
+@code{MEMTOP-STACKLEN..MEMTOP}.
+The size can be changed at the top of @code{vlink.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting at @code{MEMSTART}.
+The heap is placed in the remaining space to stack start.
+
+@subsubsection Banking
+
+Banking support for this target has not yet been implemented.
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+At the moment, stdio only supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (keyboard). Both are line-buffered by default.
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
+
+@section 6502/BBC Micro/Master
+
+This is a port of vclib to BBC 8bit computers.
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x1900 up to 0x7B00 with 256 bytes of software stack. The memory area can be adapted by
+changing @code{OSHWM}, @code{HIMEM} and @code{STACKSTART} in @code{vlink.cmd}.
+
+With the default configuration (@code{+bbc}), after exiting the C program, the code will
+enter an endless loop. If the reentrant configs are used (@code{+bbcr} or
+@code{+bbcbr}), the program will return to the command prompt. As this
+requires saving the zero page, a bit more memory is used.
+
+
+@subsubsection Command line
+
+If @code{main()} uses arguments, the command line parameters will be passed
+accordingly. There are hardcoded limits to the number of arguments (currently 8)
+and the maximum total command length (currently 80).
+
+Space is used to separate arguments. The quote character (@code{"}) can be used
+to group arguments containing spaces.
+
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x00..0x90}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the startup code maps the user stack from
+@code{STACKSTART..HIMEM}.
+The size can be changed at the top of @code{vlink.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting at @code{OSHWM}.
+The heap is placed in the remaining space to stack start.
+
+@subsubsection Banking
+
+When using the @code{+bbcb} or @code{bbcbr} configurations, vbcc supports
+banked memory, including automated bank-switching. Up to 16 sections of 16K
+size are supported. Each section starts at 0x8000.
+
+The corresponding linker
+files @code{vlinkb.cmd} and @code{vlinkbr.cmd} can be edited to choose the
+banks that are required. Unused banks can be removed by commenting out
+(using old-style C-comments) the corresponding entries in the @code{SECTIONS}
+part of the linker file. When using bank 1-3 the section in the linker file
+could look like this:
+
+@example
+ ...
+
+SECTIONS
+@{
+ text : @{*(text)@} >ram
+ .dtors : @{ *(.dtors) @} > ram
+ .ctors : @{ *(.ctors) @} > ram
+ rodata : @{*(rodata)@} >ram
+ data: @{*(data)@} >ram
+ init : @{*(init)@} >ram
+ zpage (NOLOAD) : @{*(zpage) *(zp1) *(zp2)@} >zero
+ bss (NOLOAD): @{*(bss)@} >ram
+
+/*
+ b0 : @{.=PAGEADDR; *(text0) *(rodata0) *(data0) *(bss0)
+ RESERVE(PAGEADDR+PAGESIZE-.);
+ @} >b0 AT>dummy0
+*/
+
+ b1 : @{.=PAGEADDR; *(text1) *(rodata1) *(data1) *(bss1)
+ RESERVE(PAGEADDR+PAGESIZE-.);
+ @} >b1 AT>dummy1
+
+ b2 : @{.=PAGEADDR; *(text2) *(rodata2) *(data2) *(bss2)
+ RESERVE(PAGEADDR+PAGESIZE-.);
+ @} >b2 AT>dummy2
+
+ b3 : @{.=PAGEADDR; *(text3) *(rodata3) *(data3) *(bss3)
+ RESERVE(PAGEADDR+PAGESIZE-.);
+ @} >b3 AT>dummy3
+/*
+ b4 : @{.=PAGEADDR; *(text4) *(rodata4) *(data4) *(bss4)
+ RESERVE(PAGEADDR+PAGESIZE-.);
+ @} >b4 AT>dummy4
+*/
+
+ ...
+
+@end example
+
+During the linking process, apart from the normal output file, a 16K large
+image for each bank and a loader script will be generated. E.g. when using banks
+1-3 and using the output file name test, the following files will be generated:
+
+@table @code
+@item @code{test}
+ The unbanked code/data.
+
+@item @code{test.inf}
+ Info file with start address.
+
+@item @code{testb1}
+ Image for bank1.
+
+@item @code{testb2}
+ Image for bank2.
+
+@item @code{testb2}
+ Image for bank2.
+
+@item @code{loadtest}
+ Loader
+
+@end table
+
+The contents of the loader @code{loadtest} will look like this:
+
+@example
+*srload testb1 8000 1
+*srload testb2 8000 2
+*srload testb3 8000 3
+*run test
+@end example
+
+The program can be started with @code{*exec loadtest}.
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+@code{stdout}, @code{stderr} (both using the screen) and @code{stdin} (keyboard)
+are supported. Furthermore normal file operations are possible using the
+usual C functions. There are hardcoded limits on the maximum number of
+simultaneously open files as well as the length of filenames.
+
+Sequential reading and writing is supported, but no seeking. Furthermore, the
+@code{remove()} call is supported.
+
+When using stdio to emit VDU control sequences, the function
+@code{__vdu_sequence()} is available to ensure verbatim 1:1 transmission
+of all characters:
+
+@example
+ /* print diagonal line */
+ __vdu_sequence(1);
+ for(int i=0;i<20;i++)
+ printf("\x1f%c%cO",i,i);
+ __vdu_sequence(0);
+@end example
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
+
+
+
+@section 6502/MEGA65
+
+This is a port of vclib to the MEGA65. This port is intended for the C65 mode
+with a C65 or compatible ROM (although the ROM is not used after the
+program is started). The C64 configuration can be used to create programs for
+the C64 mode.
+
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+The following basic configurations are available. See below for more details:
+
+@table @code
+@item +m65s
+ Standard unbanked configuration.
+
+@item +m65sr
+ Standard unbanked reentrant configuration.
+
+@item +m65sb
+ Standard banked configuration.
+
+@item +m65l
+ Large unbanked configuration.
+
+@item +m65lr
+ Large unbanked reentrant configuration.
+
+@item +m65lb
+ Large banked configuration.
+
+@end table
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x2001. A BASIC line is included so that the program can be started using @code{RUN}
+from BASIC. The startup code
+will switch to VIC-IV mode, remove write protection of ROM banks, turn on full
+speed and change to a suitable mapping.
+The BSS segment will be cleared during startup.
+
+There are two sets of configurations that affect the configuration of
+upper memory. The standard versions (@code{+m65s, +m65sr, +m65sb})
+will keep the IO area mapped in at $D000.
+This will limit the contiguous memory block for unbanked configurations to 0xCFFF.
+For banked configurations (see below) it will make a 16K window from
+0x8000..0xBFFF available for banking. The large configurations
+(@code{+m65l, +m65lr, +m65lb}) will move the upper bound for unbanked programs
+to 0xFFFF. With banking, 32K window will be available from 0x8000..0xFFFF.
+In both cases the total amount of memory available for banking is the same in
+both configurations.
+
+While the large configurations provide larger contiguous memory areas, accesses
+to the IO area have to be made through extended 28bit instructions which are
+much larger and slower. For programs doing many IO accesses, the standard
+configurations are recommended.
+
+With the default configurations, after exiting the C program, an infinite loop will
+be entered. When using the reentrant (@code{+m65sr, +m65lr}) configs, the
+program will return to BASIC an can be started again.
+However, this needs additional memory as the init values for the data section have
+to be stored in RAM. Also, some register values and zero page contents have to be
+saved. The overhead depends on the amount of initialized variables.
+
+Caution: The current configuration assumes that the Z register always contains 0.
+To work correctly, the Z register has to be 0 when C code is
+executed. The startup code will set it correctly and the compiler generated code will
+not touch it. However, when calling other code you may have to take care
+to save/restore the Z register or to set the Z register to 0 again.
+
+@subsubsection Command line
+
+Command line parameters are supported by using the convention/code submitted by
+Stefan Haubenthal.
+
+Command-lines look like these lines:
+
+@example
+ run
+ run : rem
+ run:rem arg1 " arg 2 is quoted " arg3 "" arg5
+@end example
+
+
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x02..0xFF}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the user stack is mapped from @code{0xB800..0xC000}. For the banked version,
+it is mapped from @code{0x7800..0x8000}. The size can be
+changed at the top of @code{vlink.cmd} and @code{vlinkbank.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting after the BASIC init line.
+The heap is placed in the remaining space depending on the configuration.
+
+@subsubsection Banking
+
+The following banking models are supported:
+
+@table @code
+@item +m65sb
+ 16K window at 0x8000 with IO area mapped in at all times.
+
+@item +m65lb
+ 32K window at 0x8000.
+@end table
+
+
+Automated bank switching is supported in both modes. The mapping of banks to
+real memory in the standard configuration is like this:
+@example
+Unbanked: 0x000000..0x007FFF
+Bank0: 0x008000..0x00BFFF
+Bank1: 0x00C000..0x00FFFF
+Bank2: 0x010000..0x013FFF
+Bank3: 0x014000..0x017FFF
+ ...
+@end example
+
+On the large configuration, it looks like this:
+@example
+Unbanked: 0x000000..0x007FFF
+Bank0: 0x008000..0x00FFFF
+Bank1: 0x010000..0x017FFF
+Bank2: 0x018000..0x01FFFF
+Bank3: 0x020000..0x027FFF
+ ...
+@end example
+
+In both cases, the program start is moved to 0x1000.
+When using the banked configurations, the code can not be simply loaded from
+BASIC. The linker will create on large image without any BASIC lines. The
+file can be executed from SD-card by using a special loader that can be loaded
+from BASIC off a disk or disk image. When specifying a name as command line
+argument (see above), the loader will try to load this image from SD-card. If
+no argument is given, the loader will look for a file of the same name.
+Therefore by renaming the loader it can be made to automatically run a
+specific file.
+
+If the loader is on the current disk/image and @code{myimage} on the SD:
+@example
+LOAD "LOADER"
+RUN:REM MYIMAGE
+@end example
+
+After renaming @code{LOADER} to @code{MYIMAGE}, it can be done like this:
+@example
+RUN "MYIMAGE"
+@end example
+
+The colour RAM will be relocated to 0xFF80800 before loading to avoid being
+overwritten through the window at 0x1F800.
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+At the moment, stdio only supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (keyboard). Both are unbuffered by default.
+Using those streams will directly access the screen buffer and keyboard
+hardware. No ROM functions are needed once the program runs.
+
+Furthermore it is possible to read files on the SD-card using standard
+C functions after opening them using @code{fopen()}. Hyppo services are
+used to read those files. There are several limitations due to the
+restrictions of Hyppo:
+
+@itemize
+@item Files can only be read sequentially, no seeking etc.
+@item Files can not be written to.
+@item Only one file can be open at the same time.
+@end itemize
+
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+@subsection Multiplication/Division
+
+When generating code for the MEGA65, @code{vbcc} will make use of hardware
+multiplier/divider. This can greatly improve performance of such operations.
+Please note the following issues:
+
+@itemize
+@item Some versions of the MEGA65 core contain a bug in the hardware divider
+ which will calculate wrong results in certain cases. As workaround you can
+ specify option @code{-div-bug} to use (much slower) 6502 software
+ routines instead. Multiplication is not affected by the bug and will still
+ be using the hardware multiplier.
+
+@item The hardware multiplier registers are mapped in the IO area. When using
+ the large configurations (@code{+m65l, +m65lr, +m65lb}), they can only
+ be accessed using extended 28bit instructions. The code generator and
+ library functions will handle this, but there is some overhead (still
+ nowhere near using software multiplication). If your code is speed
+ critical and uses many multiplications we strongly recomment to use
+ the standard configurations (@code{+m65s, +m65sr, +m65sb}). Those will
+ set the option @code{-m65io} that tells @code{vbcc} to use faster
+ direct IO accesses.
+@end itemize
+
+@subsection Interrupts
+
+The provided configurations will disable interrupts on the MEGA65. All the
+library functions are written to work with disabled interrupts and do not use
+any ROM routines. The interrupt handlers in existing C65 ROMs do not work well
+with assembly language code and deficiencies in the mapping hardware make it
+very hard to use the ROM in a non-BASIC environment.
+
+If an application wants to use interrupts, interrupt vectors have to be
+installed at 0xFFFA..0xFFFF. Take care that there are always valid vectors
+visible at this address (especially in a banked configuration). Also take
+care that those always point to a valid handler that is visible (i.e. do
+not use an ISR in banked memory).
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
+
+@section 6502/X16
+
+This is a port of vclib to the Commander X16.
+
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x801. A BASIC line is included so that the program can be started using @code{RUN}
+from BASIC. The startup code
+will turn off the BASIC ROM to allow usage of RAM until 0x9F00 and most of the
+zero page without need for any special handling. The BSS segment will be cleared
+during startup.
+
+With the default configuration, after exiting the C program, an infinite loop will
+be entered. When using the @code{+x16r} config, the program will return to BASIC
+an can be started again.
+However, this needs additional memory as the init values for the data section have
+to be stored in RAM. Also, some register values and zero page contents have to be
+saved. The overhead depends on the amount of initialized variables.
+
+@subsubsection Command line
+
+Command line parameters are supported by using the convention/code submitted by
+Stefan Haubenthal.
+
+Command-lines look like these lines:
+
+@example
+ run
+ run : rem
+ run:rem arg1 " arg 2 is quoted " arg3 "" arg5
+@end example
+
+
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x02..0x7e}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the user stack is mapped from @code{0x9700..0x9F00}. The size can be
+changed at the top of @code{vlink.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting after the BASIC init line.
+The heap is placed in the remaining space to stack start.
+
+@subsubsection Banking
+
+Banking support for this target is not yet implemented.
+
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+At the moment, stdio only supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (keyboard). Both are unbuffered by default.
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
+
+@section 6502/PET
+
+This is a port of vclib to the CBM PET series of computers.
+
+@subsection Startup and Memory
+
+Startup and memory layout is described in the following paragraphs.
+
+@subsubsection Startup
+
+The default linker file creates program files that are loaded to address
+0x401. A BASIC line is included so that the program can be started using @code{RUN}
+from BASIC. RAM is available until 0x7FFF and most of the
+zero page without need for any special handling. The BSS segment will be cleared
+during startup.
+
+With the default configuration, after exiting the C program, an infinite loop will
+be entered. When using the @code{+petr} config, the program will return to BASIC
+an can be started again.
+However, this needs additional memory as the init values for the data section have
+to be stored in RAM. Also, some register values and zero page contents have to be
+saved. The overhead depends on the amount of initialized variables.
+
+@subsubsection Command line
+
+Command line parameters are supported by using the convention/code submitted by
+Stefan Haubenthal.
+
+Command-lines look like these lines:
+
+@example
+ run
+ run : rem
+ run:rem arg1 " arg 2 is quoted " arg3 "" arg5
+@end example
+
+
+
+@subsubsection Zero Page
+
+@code{vbcc} uses a number of zero page locations for register variables, stack
+pointer etc. in section @code{zpage}. Also, variables can be mapped to zero page using
+the @code{__zpage} attribute. By default the area @code{0x02..0x8d}
+is used, but this can be changed in the linker file.
+
+@subsubsection Stack
+
+By default, the user stack is mapped from @code{0x7F00..0x7FFF}. The size can be
+changed at the top of @code{vlink.cmd}.
+
+@subsubsection Heap
+
+Code and data/BSS are mapped starting after the BASIC init line.
+The heap is placed in the remaining space to stack start.
+
+@subsubsection Banking
+
+Automated banking is currently not supported.
+
+
+@subsection Runtime
+
+Apart from standard C library functions, @code{libvc.a} also provides a few
+runtime support functions needed by the compiler. Apart from the math and
+floating point functions mentioned in the documentation of the 6502 backend,
+it includes functions for saving/restoring registers.
+
+@subsection @code{stdio}
+
+At the moment, stdio only supports @code{stdout}, @code{stderr} (both using the
+screen) and @code{stdin} (keyboard). Both are unbuffered by default.
+
+@code{printf/scanf} functions which support floating point are contained in
+the math library only.
+
+
+@subsection Floating Point / wozfp
+
+When using floating point, the math library @code{libm.a} must be linked using
+the @code{-lm} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on Steve Wozniaks routines from the 70s,
+somewhat adapted to the ABI of @code{vbcc}. These functions are small and
+reasonably usable, but they do not fully satisfy the requirements of C99.
+
+Only a part of the C library functions for floating point is implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp()}
+@item @code{pow()}
+@item @code{log()}
+@item @code{log10()}
+@end itemize
+
+@subsection Floating Point / IEEE
+
+When using IEEE floating point, @code{-ieee} must be specified and the math library
+@code{libmieee.a} must be linked using
+the @code{-lmieee} option. It contains the floating routines as well as versions of
+the @code{printf/scanf} family that support floating point.
+
+The floating point routines are based on SANE,
+somewhat adapted to the ABI of @code{vbcc} using wrapper functions.
+These functions should be fully C and IEEE compliant and provide precise results for
+32 and 64bit floating point numbers (the library actually internally calculates
+all operation using 80bits, but vbcc currently only uses up to 64 bits).
+
+Currently, this library probably must be run from RAM.
+
+Most parts of the C library functions for floating point are implemented. The
+list currently includes:
+
+@itemize
+@item @code{exp(), expf(), expl()}
+@item @code{exp2(), exp2f(), exp2l()}
+@item @code{exp1m(), exp1mf(), exp1ml()}
+@item @code{pow(), powf(), powl()}
+@item @code{log(), logf(), logl()}
+@item @code{log1p(), log1pf(), log1pl()}
+@item @code{log2(), log2f(), log2l()}
+@item @code{log10(), log10f(), log10l()}
+@item @code{sqrt(), sqrtf(), sqrtl()}
+@item @code{sin(), sinf(), sinl()}
+@item @code{cos(), cosf(), cosl()}
+@item @code{tan(), tanf(), tanl()}
+@item @code{atan(), atanf(), atanl()}
+
+
+@end itemize
diff --git a/doc/vcpr.texi b/doc/vcpr.texi
new file mode 100755
index 0000000..2ae1942
--- /dev/null
+++ b/doc/vcpr.texi
@@ -0,0 +1,192 @@
+vcpr - code compressor for vbcc (c) in 2020 by Volker Barthelmann
+
+
+@section Introduction
+
+ vcpr is a code compressor which scans the assembly output of
+ vbcc and tries to reduce code size of the generated code by
+ moving common code sequences into separate subroutines. As a
+ trade-off, the code will usually run slower.
+
+ Like the compiler vbcc it is split into a target independent and a
+ target dependent part. However there may be code-generators for vbcc
+ which do not have a corresponding compressor.
+
+ This document only deals with the target independent parts of vcpr.
+ Be sure to read all the documents for your machine.
+
+
+@section Usage
+
+ Usually @command{vcpr} will be called by a frontend. However if you call it
+ directly, it has to be done like this:
+
+@example
+ vcpr [options] input-file output-file
+@end example
+
+ The following options are supported:
+
+@table @option
+ @item -quiet
+ Do not print the copyright notice.
+
+ @item -debug=<n>
+ Set debug-level to <n>.
+@end table
+
+
+ Note that depending on the target @command{vbcc} may insert hints into the
+ generated code. Assembly code that was not generated by @command{vbcc}
+ may not work correctly after running it through @command{vcpr}.
+
+
+@section Known problems
+
+@itemize @minus
+ @item still in early development
+@end itemize
+
+@section Backend Interface
+
+@subsection Building @code{vcpr}
+
+To write a backend for @code{vcpr}, the file @code{compress.c} has to be created
+in the machine subdirectory. The executable @code{vcpr<target>} can be built
+using:
+
+@example
+ make TARGET=<target> bin/vcpr<target>
+@end example
+
+@subsection Basic Function
+
+@code{vcpr} first reads the assembly source into a linked list of lines. It will
+call a backend function for each line to parse the line and fill in necessary
+information.
+
+The frontend looks for identical code sequences and calculates the
+savings that can be obtained by outlining the code. If code sequences are found
+that provide enough savings, they will be moved to subroutines using functions
+provided by the backend.
+
+Lines have to be textually identical to be considered for outlining. One exception
+are labels. The following sequences are considered equal as long as the labels
+are not used anywhere else:
+
+@example
+
+ a
+ bne l1
+ b
+l1:
+ c
+
+ a
+ bne l2
+ b
+l2:
+ c
+@end example
+
+Currently, @code{vcpr} only supports code sequences with one label.
+
+@subsection Data Types
+
+The main data type relevant for the backend represents the attributed source lines:
+
+@example
+typedef struct line @{
+ ...
+ char *code;
+ int flags;
+ int size;
+ ...
+ int l1,l2;
+@} line;
+@end example
+
+The following members are relevant to the backend:
+
+@code{code} points to the assembly text of the line.
+
+@code{size} contains the (estimated) size of the instruction.
+
+@code{l1, l2} specify up to two labels referenced by this instruction.
+
+@code{flags} specifies the type of instruction and can be a combination of:
+
+@itemize
+@item @code{LABDEF}: This line defines a label.
+@item @code{LABUSE}: This line references a label.
+@item @code{BARRIER}: This line must not be moved into a subroutine.
+@item @code{LBARRIER}: Used by the frontend.
+@end itemize
+
+@subsection Backend Variables
+
+The following variables have to be defined and initialized by the backend:
+
+@itemize
+
+@item @code{const char tg_copyright[]}
+A copyright string.
+
+@item @code{int minsave;}
+The minimum size units saved by outlining a function. Should at least be larger
+than the size of the code for a subroutine call.
+
+@end itemize
+
+@subsection Backend Functions
+
+The following functions have to be provided by the backend:
+
+@itemize
+
+@item @code{void parse_line(char *s,line *p);}
+
+This function parses assembly line @code{s} and has to fill the
+members @code{flags}, @code{l1}, @code{l2} and @code{size} of the line structure
+@code{p}.
+
+@item @code{add_header(line *after);}
+
+This function creates a line for the header of outlined code and inserts it into the
+line list.
+
+@item @code{add_ret(line *after);}
+
+This function adds a return line and inserts it into the line list.
+
+@item @code{add_jsr(line *after);}
+
+This function adds a subroutine call to the subroutine corresponding to the last
+call of @code{add_header()}.
+
+@end itemize
+
+@subsection Frontend Functions
+
+The following functions are provided by the frontend and can be used by the
+backend:
+
+@itemize
+
+@item @code{void *mymalloc(size_t sz);}
+
+Allocate memory.
+
+@item @code{int new_label(void);}
+
+Create a new unused label number.
+
+@item @code{line *new_line(void);}
+
+Create a new line.
+
+@item @code{void insert_line(line *after, line *new);}
+
+Insert a line into the line list at a specified position.
+
+@end itemize
diff --git a/doc/vprof.texi b/doc/vprof.texi
new file mode 100644
index 0000000..7d449b6
--- /dev/null
+++ b/doc/vprof.texi
@@ -0,0 +1,33 @@
+
+INTRODUCTION
+
+ vprof is a portable utility to visualize the profiling information,
+ which are usually stored in the file "mon.out".
+ It shows the percentage of total time spent in a function, the
+ total time in seconds, the number of function calls and the time
+ by call in ms.
+
+
+LEGAL
+
+ vprof is freeware.
+
+
+USAGE
+
+ vprof [mon.out]
+
+ If the profiling file has another name than "mon.out", you may
+ specify it as an argument to vprof.
+
+ Some vbcc code generators are able to create profiling information
+ by compiling with the -prof option (vbccm68k, for example).
+
+
+BUGS
+
+ The percentage column is still not working and will always
+ display "n.a.".
+
+
+Frank Wille frank@phoenix.owl.de
diff --git a/doc/vsc.texi b/doc/vsc.texi
new file mode 100755
index 0000000..93aecd4
--- /dev/null
+++ b/doc/vsc.texi
@@ -0,0 +1,52 @@
+vsc - scheduler for vbcc (c) in 1997-99 by Volker Barthelmann
+
+
+@section Introduction
+
+ vsc is an instruction-scheduler which reorders the assembly output of
+ vbcc and tries to improve performance of the generated code by avoiding
+ pipeline stalls etc.
+
+ Like the compiler vbcc it is split into a target independent and a
+ target dependent part. However there may be code-generators for vbcc
+ which do not have a corresponding scheduler.
+
+ This document only deals with the target independent parts of vsc.
+ Be sure to read all the documents for your machine.
+
+
+@section Usage
+
+ Usually @command{vsc} will be called by a frontend. However if you call it
+ directly, it has to be done like this:
+
+@example
+ vsc [options] input-file output-file
+@end example
+
+ The following options are supported:
+
+@table @option
+ @item -quiet
+ Do not print the copyright notice.
+
+ @item -debug=<n>
+ Set debug-level to <n>.
+@end table
+
+
+ Note that depending on the target @command{vbcc} may insert hints into the
+ generated code to tell vsc what CPU to schedule for. Code
+ scheduled for a certain CPU may run much slower on slightly different
+ CPUs. Therefore it is especially important to specify the correct
+ target-CPU when compiling.
+
+
+@section Known problems
+
+@itemize @minus
+ @item works only on basic-blocks
+@end itemize
+
+
+
diff --git a/dwarf2.c b/dwarf2.c
new file mode 100644
index 0000000..281deb3
--- /dev/null
+++ b/dwarf2.c
@@ -0,0 +1,1294 @@
+/* $VER: vbcc (dwarf2.c) $Revision: 1.5 $ */
+
+enum dwarf_tag
+{
+ DW_TAG_padding = 0x00,
+ DW_TAG_array_type = 0x01,
+ DW_TAG_class_type = 0x02,
+ DW_TAG_entry_point = 0x03,
+ DW_TAG_enumeration_type = 0x04,
+ DW_TAG_formal_parameter = 0x05,
+ DW_TAG_imported_declaration = 0x08,
+ DW_TAG_label = 0x0a,
+ DW_TAG_lexical_block = 0x0b,
+ DW_TAG_member = 0x0d,
+ DW_TAG_pointer_type = 0x0f,
+ DW_TAG_reference_type = 0x10,
+ DW_TAG_compile_unit = 0x11,
+ DW_TAG_string_type = 0x12,
+ DW_TAG_structure_type = 0x13,
+ DW_TAG_subroutine_type = 0x15,
+ DW_TAG_typedef = 0x16,
+ DW_TAG_union_type = 0x17,
+ DW_TAG_unspecified_parameters = 0x18,
+ DW_TAG_variant = 0x19,
+ DW_TAG_common_block = 0x1a,
+ DW_TAG_common_inclusion = 0x1b,
+ DW_TAG_inheritance = 0x1c,
+ DW_TAG_inlined_subroutine = 0x1d,
+ DW_TAG_module = 0x1e,
+ DW_TAG_ptr_to_member_type = 0x1f,
+ DW_TAG_set_type = 0x20,
+ DW_TAG_subrange_type = 0x21,
+ DW_TAG_with_stmt = 0x22,
+ DW_TAG_access_declaration = 0x23,
+ DW_TAG_base_type = 0x24,
+ DW_TAG_catch_block = 0x25,
+ DW_TAG_const_type = 0x26,
+ DW_TAG_constant = 0x27,
+ DW_TAG_enumerator = 0x28,
+ DW_TAG_file_type = 0x29,
+ DW_TAG_friend = 0x2a,
+ DW_TAG_namelist = 0x2b,
+ DW_TAG_namelist_item = 0x2c,
+ DW_TAG_packed_type = 0x2d,
+ DW_TAG_subprogram = 0x2e,
+ DW_TAG_template_type_param = 0x2f,
+ DW_TAG_template_value_param = 0x30,
+ DW_TAG_thrown_type = 0x31,
+ DW_TAG_try_block = 0x32,
+ DW_TAG_variant_part = 0x33,
+ DW_TAG_variable = 0x34,
+ DW_TAG_volatile_type = 0x35,
+ /* SGI/MIPS Extensions */
+ DW_TAG_MIPS_loop = 0x4081,
+ /* GNU extensions */
+ DW_TAG_format_label = 0x4101,
+ DW_TAG_function_template = 0x4102,
+ DW_TAG_class_template = 0x4103
+};
+
+enum dwarf_children
+{
+ DW_children_no = 0,
+ DW_children_yes = 1
+};
+
+enum dwarf_form
+{
+ DW_FORM_addr = 0x01,
+ DW_FORM_block2 = 0x03,
+ DW_FORM_block4 = 0x04,
+ DW_FORM_data2 = 0x05,
+ DW_FORM_data4 = 0x06,
+ DW_FORM_data8 = 0x07,
+ DW_FORM_string = 0x08,
+ DW_FORM_block = 0x09,
+ DW_FORM_block1 = 0x0a,
+ DW_FORM_data1 = 0x0b,
+ DW_FORM_flag = 0x0c,
+ DW_FORM_sdata = 0x0d,
+ DW_FORM_strp = 0x0e,
+ DW_FORM_udata = 0x0f,
+ DW_FORM_ref_addr = 0x10,
+ DW_FORM_ref1 = 0x11,
+ DW_FORM_ref2 = 0x12,
+ DW_FORM_ref4 = 0x13,
+ DW_FORM_ref8 = 0x14,
+ DW_FORM_ref_udata = 0x15,
+ DW_FORM_indirect = 0x16
+};
+
+enum dwarf_attribute
+{
+ DW_AT_sibling = 0x01,
+ DW_AT_location = 0x02,
+ DW_AT_name = 0x03,
+ DW_AT_ordering = 0x09,
+ DW_AT_subscr_data = 0x0a,
+ DW_AT_byte_size = 0x0b,
+ DW_AT_bit_offset = 0x0c,
+ DW_AT_bit_size = 0x0d,
+ DW_AT_element_list = 0x0f,
+ DW_AT_stmt_list = 0x10,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12,
+ DW_AT_language = 0x13,
+ DW_AT_member = 0x14,
+ DW_AT_discr = 0x15,
+ DW_AT_discr_value = 0x16,
+ DW_AT_visibility = 0x17,
+ DW_AT_import = 0x18,
+ DW_AT_string_length = 0x19,
+ DW_AT_common_reference = 0x1a,
+ DW_AT_comp_dir = 0x1b,
+ DW_AT_const_value = 0x1c,
+ DW_AT_containing_type = 0x1d,
+ DW_AT_default_value = 0x1e,
+ DW_AT_inline = 0x20,
+ DW_AT_is_optional = 0x21,
+ DW_AT_lower_bound = 0x22,
+ DW_AT_producer = 0x25,
+ DW_AT_prototyped = 0x27,
+ DW_AT_return_addr = 0x2a,
+ DW_AT_start_scope = 0x2c,
+ DW_AT_stride_size = 0x2e,
+ DW_AT_upper_bound = 0x2f,
+ DW_AT_abstract_origin = 0x31,
+ DW_AT_accessibility = 0x32,
+ DW_AT_address_class = 0x33,
+ DW_AT_artificial = 0x34,
+ DW_AT_base_types = 0x35,
+ DW_AT_calling_convention = 0x36,
+ DW_AT_count = 0x37,
+ DW_AT_data_member_location = 0x38,
+ DW_AT_decl_column = 0x39,
+ DW_AT_decl_file = 0x3a,
+ DW_AT_decl_line = 0x3b,
+ DW_AT_declaration = 0x3c,
+ DW_AT_discr_list = 0x3d,
+ DW_AT_encoding = 0x3e,
+ DW_AT_external = 0x3f,
+ DW_AT_frame_base = 0x40,
+ DW_AT_friend = 0x41,
+ DW_AT_identifier_case = 0x42,
+ DW_AT_macro_info = 0x43,
+ DW_AT_namelist_items = 0x44,
+ DW_AT_priority = 0x45,
+ DW_AT_segment = 0x46,
+ DW_AT_specification = 0x47,
+ DW_AT_static_link = 0x48,
+ DW_AT_type = 0x49,
+ DW_AT_use_location = 0x4a,
+ DW_AT_variable_parameter = 0x4b,
+ DW_AT_virtuality = 0x4c,
+ DW_AT_vtable_elem_location = 0x4d,
+ DW_AT_MIPS_fde = 0x2001,
+ DW_AT_MIPS_loop_begin = 0x2002,
+ DW_AT_MIPS_tail_loop_begin = 0x2003,
+ DW_AT_MIPS_epilog_begin = 0x2004,
+ DW_AT_MIPS_loop_unroll_factor = 0x2005,
+ DW_AT_MIPS_software_pipeline_depth = 0x2006,
+ DW_AT_MIPS_linkage_name = 0x2007,
+ DW_AT_MIPS_stride = 0x2008,
+ DW_AT_MIPS_abstract_name = 0x2009,
+ DW_AT_MIPS_clone_origin = 0x200a,
+ DW_AT_MIPS_has_inlines = 0x200b,
+ /* GNU */
+ DW_AT_sf_names = 0x2101,
+ DW_AT_src_info = 0x2102,
+ DW_AT_mac_info = 0x2103,
+ DW_AT_src_coords = 0x2104,
+ DW_AT_body_begin = 0x2105,
+ DW_AT_body_end = 0x2106
+};
+
+enum dwarf_location_atom
+{
+ DW_OP_addr = 0x03,
+ DW_OP_deref = 0x06,
+ DW_OP_const1u = 0x08,
+ DW_OP_const1s = 0x09,
+ DW_OP_const2u = 0x0a,
+ DW_OP_const2s = 0x0b,
+ DW_OP_const4u = 0x0c,
+ DW_OP_const4s = 0x0d,
+ DW_OP_const8u = 0x0e,
+ DW_OP_const8s = 0x0f,
+ DW_OP_constu = 0x10,
+ DW_OP_consts = 0x11,
+ DW_OP_dup = 0x12,
+ DW_OP_drop = 0x13,
+ DW_OP_over = 0x14,
+ DW_OP_pick = 0x15,
+ DW_OP_swap = 0x16,
+ DW_OP_rot = 0x17,
+ DW_OP_xderef = 0x18,
+ DW_OP_abs = 0x19,
+ DW_OP_and = 0x1a,
+ DW_OP_div = 0x1b,
+ DW_OP_minus = 0x1c,
+ DW_OP_mod = 0x1d,
+ DW_OP_mul = 0x1e,
+ DW_OP_neg = 0x1f,
+ DW_OP_not = 0x20,
+ DW_OP_or = 0x21,
+ DW_OP_plus = 0x22,
+ DW_OP_plus_uconst = 0x23,
+ DW_OP_shl = 0x24,
+ DW_OP_shr = 0x25,
+ DW_OP_shra = 0x26,
+ DW_OP_xor = 0x27,
+ DW_OP_bra = 0x28,
+ DW_OP_eq = 0x29,
+ DW_OP_ge = 0x2a,
+ DW_OP_gt = 0x2b,
+ DW_OP_le = 0x2c,
+ DW_OP_lt = 0x2d,
+ DW_OP_ne = 0x2e,
+ DW_OP_skip = 0x2f,
+ DW_OP_lit0 = 0x30,
+ DW_OP_lit1 = 0x31,
+ DW_OP_lit2 = 0x32,
+ DW_OP_lit3 = 0x33,
+ DW_OP_lit4 = 0x34,
+ DW_OP_lit5 = 0x35,
+ DW_OP_lit6 = 0x36,
+ DW_OP_lit7 = 0x37,
+ DW_OP_lit8 = 0x38,
+ DW_OP_lit9 = 0x39,
+ DW_OP_lit10 = 0x3a,
+ DW_OP_lit11 = 0x3b,
+ DW_OP_lit12 = 0x3c,
+ DW_OP_lit13 = 0x3d,
+ DW_OP_lit14 = 0x3e,
+ DW_OP_lit15 = 0x3f,
+ DW_OP_lit16 = 0x40,
+ DW_OP_lit17 = 0x41,
+ DW_OP_lit18 = 0x42,
+ DW_OP_lit19 = 0x43,
+ DW_OP_lit20 = 0x44,
+ DW_OP_lit21 = 0x45,
+ DW_OP_lit22 = 0x46,
+ DW_OP_lit23 = 0x47,
+ DW_OP_lit24 = 0x48,
+ DW_OP_lit25 = 0x49,
+ DW_OP_lit26 = 0x4a,
+ DW_OP_lit27 = 0x4b,
+ DW_OP_lit28 = 0x4c,
+ DW_OP_lit29 = 0x4d,
+ DW_OP_lit30 = 0x4e,
+ DW_OP_lit31 = 0x4f,
+ DW_OP_reg0 = 0x50,
+ DW_OP_reg1 = 0x51,
+ DW_OP_reg2 = 0x52,
+ DW_OP_reg3 = 0x53,
+ DW_OP_reg4 = 0x54,
+ DW_OP_reg5 = 0x55,
+ DW_OP_reg6 = 0x56,
+ DW_OP_reg7 = 0x57,
+ DW_OP_reg8 = 0x58,
+ DW_OP_reg9 = 0x59,
+ DW_OP_reg10 = 0x5a,
+ DW_OP_reg11 = 0x5b,
+ DW_OP_reg12 = 0x5c,
+ DW_OP_reg13 = 0x5d,
+ DW_OP_reg14 = 0x5e,
+ DW_OP_reg15 = 0x5f,
+ DW_OP_reg16 = 0x60,
+ DW_OP_reg17 = 0x61,
+ DW_OP_reg18 = 0x62,
+ DW_OP_reg19 = 0x63,
+ DW_OP_reg20 = 0x64,
+ DW_OP_reg21 = 0x65,
+ DW_OP_reg22 = 0x66,
+ DW_OP_reg23 = 0x67,
+ DW_OP_reg24 = 0x68,
+ DW_OP_reg25 = 0x69,
+ DW_OP_reg26 = 0x6a,
+ DW_OP_reg27 = 0x6b,
+ DW_OP_reg28 = 0x6c,
+ DW_OP_reg29 = 0x6d,
+ DW_OP_reg30 = 0x6e,
+ DW_OP_reg31 = 0x6f,
+ DW_OP_breg0 = 0x70,
+ DW_OP_breg1 = 0x71,
+ DW_OP_breg2 = 0x72,
+ DW_OP_breg3 = 0x73,
+ DW_OP_breg4 = 0x74,
+ DW_OP_breg5 = 0x75,
+ DW_OP_breg6 = 0x76,
+ DW_OP_breg7 = 0x77,
+ DW_OP_breg8 = 0x78,
+ DW_OP_breg9 = 0x79,
+ DW_OP_breg10 = 0x7a,
+ DW_OP_breg11 = 0x7b,
+ DW_OP_breg12 = 0x7c,
+ DW_OP_breg13 = 0x7d,
+ DW_OP_breg14 = 0x7e,
+ DW_OP_breg15 = 0x7f,
+ DW_OP_breg16 = 0x80,
+ DW_OP_breg17 = 0x81,
+ DW_OP_breg18 = 0x82,
+ DW_OP_breg19 = 0x83,
+ DW_OP_breg20 = 0x84,
+ DW_OP_breg21 = 0x85,
+ DW_OP_breg22 = 0x86,
+ DW_OP_breg23 = 0x87,
+ DW_OP_breg24 = 0x88,
+ DW_OP_breg25 = 0x89,
+ DW_OP_breg26 = 0x8a,
+ DW_OP_breg27 = 0x8b,
+ DW_OP_breg28 = 0x8c,
+ DW_OP_breg29 = 0x8d,
+ DW_OP_breg30 = 0x8e,
+ DW_OP_breg31 = 0x8f,
+ DW_OP_regx = 0x90,
+ DW_OP_fbreg = 0x91,
+ DW_OP_bregx = 0x92,
+ DW_OP_piece = 0x93,
+ DW_OP_deref_size = 0x94,
+ DW_OP_xderef_size = 0x95,
+ DW_OP_nop = 0x96
+};
+
+enum dwarf_type
+{
+ DW_ATE_void = 0x0,
+ DW_ATE_address = 0x1,
+ DW_ATE_boolean = 0x2,
+ DW_ATE_complex_float = 0x3,
+ DW_ATE_float = 0x4,
+ DW_ATE_signed = 0x5,
+ DW_ATE_signed_char = 0x6,
+ DW_ATE_unsigned = 0x7,
+ DW_ATE_unsigned_char = 0x8
+};
+
+enum dwarf_array_dim_ordering
+{
+ DW_ORD_row_major = 0,
+ DW_ORD_col_major = 1
+};
+
+enum dwarf_access_attribute
+{
+ DW_ACCESS_public = 1,
+ DW_ACCESS_protected = 2,
+ DW_ACCESS_private = 3
+};
+
+enum dwarf_visibility_attribute
+{
+ DW_VIS_local = 1,
+ DW_VIS_exported = 2,
+ DW_VIS_qualified = 3
+};
+
+enum dwarf_virtuality_attribute
+{
+ DW_VIRTUALITY_none = 0,
+ DW_VIRTUALITY_virtual = 1,
+ DW_VIRTUALITY_pure_virtual = 2
+};
+
+enum dwarf_id_case
+{
+ DW_ID_case_sensitive = 0,
+ DW_ID_up_case = 1,
+ DW_ID_down_case = 2,
+ DW_ID_case_insensitive = 3
+};
+
+enum dwarf_calling_convention
+{
+ DW_CC_normal = 0x1,
+ DW_CC_program = 0x2,
+ DW_CC_nocall = 0x3
+};
+
+enum dwarf_inline_attribute
+{
+ DW_INL_not_inlined = 0,
+ DW_INL_inlined = 1,
+ DW_INL_declared_not_inlined = 2,
+ DW_INL_declared_inlined = 3
+};
+
+enum dwarf_descrim_list
+{
+ DW_DSC_label = 0,
+ DW_DSC_range = 1
+};
+
+enum dwarf_line_number_ops
+{
+ DW_LNS_extended_op = 0,
+ DW_LNS_copy = 1,
+ DW_LNS_advance_pc = 2,
+ DW_LNS_advance_line = 3,
+ DW_LNS_set_file = 4,
+ DW_LNS_set_column = 5,
+ DW_LNS_negate_stmt = 6,
+ DW_LNS_set_basic_block = 7,
+ DW_LNS_const_add_pc = 8,
+ DW_LNS_fixed_advance_pc = 9
+};
+
+enum dwarf_line_number_x_ops
+{
+ DW_LNE_end_sequence = 1,
+ DW_LNE_set_address = 2,
+ DW_LNE_define_file = 3
+};
+
+enum dwarf_call_frame_info
+{
+ DW_CFA_advance_loc = 0x40,
+ DW_CFA_offset = 0x80,
+ DW_CFA_restore = 0xc0,
+ DW_CFA_nop = 0x00,
+ DW_CFA_set_loc = 0x01,
+ DW_CFA_advance_loc1 = 0x02,
+ DW_CFA_advance_loc2 = 0x03,
+ DW_CFA_advance_loc4 = 0x04,
+ DW_CFA_offset_extended = 0x05,
+ DW_CFA_restore_extended = 0x06,
+ DW_CFA_undefined = 0x07,
+ DW_CFA_same_value = 0x08,
+ DW_CFA_register = 0x09,
+ DW_CFA_remember_state = 0x0a,
+ DW_CFA_restore_state = 0x0b,
+ DW_CFA_def_cfa = 0x0c,
+ DW_CFA_def_cfa_register = 0x0d,
+ DW_CFA_def_cfa_offset = 0x0e,
+ DW_CFA_MIPS_advance_loc8 = 0x1d
+};
+
+#define DW_CIE_ID 0xffffffff
+#define DW_CIE_VERSION 1
+
+#define DW_CFA_extended 0
+#define DW_CFA_low_user 0x1c
+#define DW_CFA_high_user 0x3f
+
+#define DW_CHILDREN_no 0x00
+#define DW_CHILDREN_yes 0x01
+
+#define DW_ADDR_none 0
+
+enum dwarf_source_language
+{
+ DW_LANG_C89 = 0x0001,
+ DW_LANG_C = 0x0002,
+ DW_LANG_Ada83 = 0x0003,
+ DW_LANG_C_plus_plus = 0x0004,
+ DW_LANG_Cobol74 = 0x0005,
+ DW_LANG_Cobol85 = 0x0006,
+ DW_LANG_Fortran77 = 0x0007,
+ DW_LANG_Fortran90 = 0x0008,
+ DW_LANG_Pascal83 = 0x0009,
+ DW_LANG_Modula2 = 0x000a,
+ DW_LANG_Mips_Assembler = 0x8001
+};
+
+
+enum dwarf_macinfo_record_type
+{
+ DW_MACINFO_define = 1,
+ DW_MACINFO_undef = 2,
+ DW_MACINFO_start_file = 3,
+ DW_MACINFO_end_file = 4,
+ DW_MACINFO_vendor_ext = 255
+};
+
+
+
+#define HAVE_LOCATION_LISTS 0
+
+/* provided by the code generator */
+static void dwarf2_print_frame_location(FILE *,Var *);
+static zmax dwarf2_fboffset(Var *);
+static int dwarf2_regnumber(int);
+
+static int abbrev_label,info_start,info_end,line_start,line_end;
+
+static int sizeof_addr;
+static char *dwarfd1,*dwarfd2,*dwarfd4,*da,*lp,*ip,*dsec;
+static int addr_form;
+static char **names;
+static int namecount;
+
+extern Var *merk_varf,*first_var[],*first_ext; /*FIXME: not nice */
+extern struct_declaration *first_sd[];
+
+#define COMP_UNIT 1UL
+#define SUBPROGRAM 2UL
+#define SUBPROGRAMVOID 3UL
+#define BASETYPE 4UL
+#define POINTERTYPE 5UL
+#define CONSTTYPE 6UL
+#define VOLATILETYPE 7UL
+#define FORMALPARAMETER 8UL
+#define VARIABLE 9UL
+#define ARRAYTYPE 10UL
+#define ARRAYDIM 11UL
+#define STRUCTTYPE 12UL
+#define UNIONTYPE 13UL
+#define STRUCTTAG 14UL
+#define UNIONTAG 15UL
+#define TYPEDEFTYPE 16UL
+#define MEMBERTYPE 17UL
+#define FUNCTYPE 18UL
+#define VOIDFUNCTYPE 19UL
+#define PARMTYPE 20UL
+
+typedef struct dwarf2_line_info {
+ struct dwarf2_line_info *next;
+ char *id;
+ int file,line,label;
+} tdwarf2_line_info;
+
+static tdwarf2_line_info *dwarf2_first_li,*dwarf2_last_li;
+
+static void dwarf2_add_line(int file,int line,int label,char *id)
+{
+ tdwarf2_line_info *new,*p,*lp;
+ new=mymalloc(sizeof(*new));
+ new->file=file;
+ new->line=line;
+ new->label=label;
+ if(id){
+ new->id=mymalloc(strlen(id)+1);
+ strcpy(new->id,id);
+ }else{
+ new->id=0;
+ }
+ new->next=0;
+#if 0
+ for(lp=p=dwarf2_first_li;p;p=p->next){
+ if(p!=lp&&p->file==file&&p->line>=line){
+ new->next=lp->next;
+ lp->next=new;
+ return;
+ }
+ lp=p;
+ }
+#endif
+ if(dwarf2_last_li){
+ dwarf2_last_li->next=new;
+ dwarf2_last_li=new;
+ }else{
+ dwarf2_first_li=dwarf2_last_li=new;
+ }
+#if 0
+ printf("linfo:\n");
+ for(p=dwarf2_first_li;p;p=p->next)
+ printf("li: line=%d\n",p->line);
+#endif
+}
+
+static void dwarf2_setup(int sa,char *dwarfd1s,char *dwarfd2s,char *dwarfd4s,char *das,char *lps,char *ips,char *ds)
+{
+ sizeof_addr=sa;
+ dwarfd1=dwarfd1s;
+ dwarfd2=dwarfd2s;
+ dwarfd4=dwarfd4s;
+ da=das;
+ lp=lps;
+ ip=ips;
+ dsec=ds;
+ if(sizeof_addr==2)
+ addr_form=DW_FORM_data2;
+ else if(sizeof_addr==4)
+ addr_form=DW_FORM_data4;
+ else if(sizeof_addr==8)
+ addr_form=DW_FORM_data8;
+ else
+ ierror(0);
+}
+static int dwarf2_uleb128_size(zumax value)
+{
+ int size=0;
+ do{
+ value=zumrshift(value,ul2zum(7UL));
+ size++;
+ }while(!zmeqto(value,ul2zum(0UL)));
+ return size;
+}
+static void dwarf2_print_uleb128(FILE *f,zumax value)
+{
+ unsigned long byte;
+ emit(f,"\t%s\t",dwarfd1);
+ do{
+ byte=zum2ul(zumand(value,ul2zum(127UL)));
+ value=zumrshift(value,ul2zum(7UL));
+ if(!zumeqto(value,ul2zum(0UL)))
+ emit(f,"%lu,",byte|0x80);
+ else
+ emit(f,"%lu\n",byte);
+ }while(!zumeqto(value,ul2zum(0UL)));
+}
+static int dwarf2_sleb128_size(zmax value)
+{
+ int more=1,size=0;
+ long byte;
+ do{
+ byte=zm2l(zmand(value,l2zm(127L)));
+ value=zmrshift(value,l2zm(7L)); /*FIXME*/
+ if((zmeqto(value,l2zm(0L))&&!(byte&0x40))||
+ (zmeqto(value,l2zm(-1L))&&(byte&0x40)))
+ more=0;
+ size++;
+ }while(more);
+ return size;
+}
+static void dwarf2_print_sleb128(FILE *f,zmax value)
+{
+ int more=1;
+ long byte;
+ emit(f,"\t%s\t",dwarfd1);
+ do{
+ byte=zm2l(zmand(value,l2zm(127L)));
+ value=zmrshift(value,l2zm(7L)); /*FIXME*/
+ if((zmeqto(value,l2zm(0L))&&!(byte&0x40))||
+ (zmeqto(value,l2zm(-1L))&&(byte&0x40))){
+ more=0;
+ emit(f,"%ld\n",byte);
+ }else{
+ emit(f,"%ld,",byte|0x80);
+ }
+ }while(more);
+}
+static void dwarf2_print_location(FILE *f,obj *o)
+{
+ if(o->flags&(KONST|DREFOBJ)) ierror(0);
+ if(!(o->flags&(VAR|REG))) ierror(0);
+ if(o->flags®){
+ int r=dwarf2_regnumber(o->reg);
+ if(r<=31){
+ emit(f,"\t%s\t%d\n",dwarfd2,1);
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_OP_reg0+r);
+ }else{
+ emit(f,"\t%s\t%d\n",dwarfd2,1+dwarf2_uleb128_size(ul2zum((unsigned long)r)));
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_OP_regx);
+ dwarf2_print_uleb128(f,ul2zum(r));
+ }
+ }else{
+ if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN){
+ if(cross_module&&!(o->v->flags&REFERENCED)){
+ emit(f,"\t%s\t0\n",dwarfd1);
+ }else{
+ emit(f,"\t%s\t%d\n",dwarfd2,(int)(1+sizeof_addr));
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_OP_addr);
+ if(o->v->storage_class==STATIC)
+ emit(f,"\t%s\t%s%ld\n",da,lp,zm2l(o->v->offset));
+ else
+ emit(f,"\t%s\t%s%s\n",da,ip,o->v->identifier);
+ }
+ }else{
+ zmax of=dwarf2_fboffset(o->v);
+ emit(f,"\t%s\t%d\n",dwarfd2,1+dwarf2_sleb128_size(of));
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_OP_fbreg);
+ dwarf2_print_sleb128(f,of);
+ }
+ }
+}
+static int dwarf2_file(const char *p)
+{
+ int i;
+ if(!p) ierror(0);
+ for(i=0;i<namecount;i++)
+ if(!strcmp(p,names[i]))
+ return i+1;
+ namecount++;
+ names=myrealloc(names,namecount*sizeof(*names));
+ names[namecount-1]=mymalloc(strlen(p)+1);
+ strcpy(names[namecount-1],p);
+ return namecount;
+}
+static int dwarf2_type(FILE *f,type *t)
+{
+ int l,lo;char *p;
+ if(ISPOINTER(t->flags)){
+ lo=dwarf2_type(f,t->next);
+ l=++label;
+ emit(f,"%s%d:\n",lp,l);
+ dwarf2_print_uleb128(f,ul2zum(POINTERTYPE));
+ emit(f,"\t%s\t%s%d\n",da,lp,lo);
+ }else if(ISINT(t->flags)||ISFLOAT(t->flags)||(t->flags&NQ)==VOID){
+ l=++label;
+ emit(f,"%s%d:\n",lp,l);
+ dwarf2_print_uleb128(f,ul2zum(BASETYPE));
+ for(p=typname[t->flags&NQ];*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ if(ISFLOAT(t->flags)){
+ lo=DW_ATE_float;
+ }else if((t->flags&NQ)==CHAR){
+ if(t->flags&UNSIGNED)
+ lo=DW_ATE_unsigned_char;
+ else
+ lo=DW_ATE_signed_char;
+ }else if((t->flags&NQ)==VOID){
+ lo=DW_ATE_unsigned_char;
+ }else{
+ if(!ISINT(t->flags)) ierror(0);
+ if(t->flags&UNSIGNED)
+ lo=DW_ATE_unsigned;
+ else
+ lo=DW_ATE_signed;
+ }
+ dwarf2_print_uleb128(f,ul2zum((unsigned long)lo));
+ dwarf2_print_uleb128(f,sizetab[t->flags&NQ]);
+ }else if(ISARRAY(t->flags)){
+ lo=dwarf2_type(f,t->next);
+ l=++label;
+ emit(f,"%s%d:\n",lp,l);
+ dwarf2_print_uleb128(f,ul2zum(ARRAYTYPE));
+ emit(f,"\t%s\t%s%d\n",da,lp,lo);
+ dwarf2_print_uleb128(f,ul2zum(ARRAYDIM));
+ dwarf2_print_uleb128(f,zumsub(t->size,ul2zum(1UL)));
+ emit(f,"\t%s\t0\n",dwarfd1);
+ }else if(ISSTRUCT(t->flags)||ISUNION(t->flags)){
+ if(t->exact->label>0){
+ l=t->exact->label;
+ }else{
+ int i,*tl;zmax offset=l2zm(0L),al;
+ type *tp;
+ l=++label;
+ t->exact->label=l;
+ tl=mymalloc(t->exact->count*sizeof(*tl));
+ for(i=0;i<t->exact->count;i++)
+ tl[i]=dwarf2_type(f,(*t->exact->sl)[i].styp);
+ emit(f,"%s%d:\n",lp,l);
+ if(t->exact->identifier){
+ if(ISSTRUCT(t->flags))
+ dwarf2_print_uleb128(f,STRUCTTAG);
+ else
+ dwarf2_print_uleb128(f,UNIONTAG);
+ dwarf2_print_uleb128(f,szof(t));
+ for(p=t->exact->identifier;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ }else{
+ if(ISSTRUCT(t->flags))
+ dwarf2_print_uleb128(f,STRUCTTYPE);
+ else
+ dwarf2_print_uleb128(f,UNIONTYPE);
+ dwarf2_print_uleb128(f,szof(t));
+ }
+ for(i=0;i<t->exact->count;i++){
+ dwarf2_print_uleb128(f,MEMBERTYPE);
+ for(p=(*t->exact->sl)[i].identifier;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ emit(f,"\t%s\t%s%d\n",da,lp,tl[i]);
+ dwarf2_print_uleb128(f,zumadd(dwarf2_uleb128_size(zm2zum(offset)),ul2zum(1L)));
+ tp=(*t->exact->sl)[i].styp;
+ al=falign(tp);
+ offset=zmmult(zmdiv(zmadd(offset,zmsub(al,l2zm(1L))),al),al);
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_OP_plus_uconst);
+ dwarf2_print_uleb128(f,zm2zum(offset));
+ if(ISSTRUCT(t->flags))
+ offset=zmadd(offset,szof(tp));
+ }
+ emit(f,"\t%s\t0\n",dwarfd1);
+ free(tl);
+ }
+ }else if(ISFUNC(t->flags)){
+ int *tl,i;
+ l=++label;
+ tl=mymalloc(t->exact->count*sizeof(*tl));
+ for(i=0;i<t->exact->count;i++){
+ if(((*t->exact->sl)[i].styp->flags&NQ)!=VOID)
+ tl[i]=dwarf2_type(f,(*t->exact->sl)[i].styp);
+ }
+ if((t->next->flags&NQ)==VOID){
+ emit(f,"%s%d:\n",lp,l);
+ dwarf2_print_uleb128(f,VOIDFUNCTYPE);
+ }else{
+ lo=dwarf2_type(f,t->next);
+ emit(f,"%s%d:\n",lp,l);
+ dwarf2_print_uleb128(f,FUNCTYPE);
+ emit(f,"\t%s\t%s%d\n",da,lp,lo);
+ }
+ for(i=0;i<t->exact->count;i++){
+ if(((*t->exact->sl)[i].styp->flags&NQ)!=VOID){
+ dwarf2_print_uleb128(f,PARMTYPE);
+ emit(f,"\t%s\t%s%d\n",da,lp,tl[i]);
+ }
+ }
+ emit(f,"\t%s\t0\n",dwarfd1);
+ free(tl);
+ }else{
+ printf("%d\n",t->flags);
+ ierror(0);
+ }
+ if(t->flags&VOLATILE){
+ lo=l;l=++label;
+ emit(f,"%s%d:\n",lp,l);
+ dwarf2_print_uleb128(f,ul2zum(VOLATILETYPE));
+ emit(f,"\t%s\t%s%d\n",da,lp,lo);
+ }
+ if(t->flags&CONST){
+ lo=l;l=++label;
+ emit(f,"%s%d:\n",lp,l);
+ dwarf2_print_uleb128(f,ul2zum(CONSTTYPE));
+ emit(f,"\t%s\t%s%d\n",da,lp,lo);
+ }
+ return l;
+}
+static void dwarf2_var(FILE *f,Var *v)
+{
+ char *p;int l;
+ if(!(v->flags&(DEFINED|TENTATIVE))) return;
+ if(v->storage_class==STATIC&&v->nesting>0&&!(v->flags&(USEDASSOURCE|USEDASDEST))) return;
+
+ if(ISFUNC(v->vtyp->flags)) return;
+ if(*v->identifier&&v->storage_class!=TYPEDEF){
+ l=dwarf2_type(f,v->vtyp);
+ if((v->storage_class==AUTO||v->storage_class==REGISTER)&&(!zmleq(l2zm(0L),v->offset)||v->reg)){
+ dwarf2_print_uleb128(f,ul2zum(FORMALPARAMETER));
+ }else{
+ dwarf2_print_uleb128(f,ul2zum(VARIABLE));
+ }
+ for(p=v->identifier;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ emit(f,"\t%s\t%s%d\n",da,lp,l);
+ if((v->storage_class==AUTO||v->storage_class==REGISTER)&&(!zmleq(l2zm(0L),v->offset)||v->reg)){
+ /* no external flag for formal-parameter */
+ }else{
+ emit(f,"\t%s\t%d\n",dwarfd1,(v->storage_class==EXTERN));
+ }
+ if((!v->dfilename||!v->dline)&&(!v->filename||!v->line)) ierror(0);
+ if(v->dfilename){
+ dwarf2_print_uleb128(f,ul2zum((unsigned long)dwarf2_file(v->dfilename)));
+ dwarf2_print_uleb128(f,ul2zum((unsigned long)v->dline));
+ }else{
+ dwarf2_print_uleb128(f,ul2zum((unsigned long)dwarf2_file(v->filename)));
+ dwarf2_print_uleb128(f,ul2zum((unsigned long)v->line));
+ }
+ { /*FIXME!*/
+ obj o;
+ o.flags=VAR;
+ o.val.vmax=l2zm(0L);
+ o.v=v;
+#if HAVE_LOCATION_LISTS
+ emit(f,"\t%s\t\".debug_loc\"\n",dsec);
+ ++label;
+ emit(f,"%s%d:\n",lp,label);
+ emit(f,"\t%s\t0\n",da);
+ emit(f,"\t%s\t-1\n",da);
+ dwarf2_print_location(f,&o);
+ emit(f,"\t%s\t0\n",da);
+ emit(f,"\t%s\t0\n",da);
+ emit(f,"\t%s\t\".debug_info\"\n",dsec);
+ emit(f,"\t%s\t%s%d\n",da,lp,label);
+#else
+ dwarf2_print_location(f,&o);
+#endif
+ }
+ }
+}
+static void dwarf2_print_comp_unit_header(FILE *f)
+{
+ char *p;
+ extern char *copyright; /* not nice */
+ extern char *inname; /* not nice */
+
+ abbrev_label=++label;
+ emit(f,"\t%s\t\".debug_abbrev\"\n",dsec);
+ emit(f,"%s%d:\n",lp,abbrev_label);
+
+ dwarf2_print_uleb128(f,ul2zum(COMP_UNIT));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_compile_unit));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_language));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_stmt_list));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_producer));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_identifier_case));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+ dwarf2_print_uleb128(f,ul2zum(0UL));
+ dwarf2_print_uleb128(f,ul2zum(0UL));
+
+ dwarf2_print_uleb128(f,ul2zum(SUBPROGRAM));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_subprogram));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_low_pc));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_addr));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_high_pc));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_addr));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_external));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_flag));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_file));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_line));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_frame_base));
+#if HAVE_LOCATION_LISTS
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+#else
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_block2));
+#endif
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(SUBPROGRAMVOID));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_subprogram));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_low_pc));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_addr));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_high_pc));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_addr));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_external));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_flag));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_file));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_line));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_frame_base));
+#if HAVE_LOCATION_LISTS
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+#else
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_block2));
+#endif
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(FORMALPARAMETER));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_formal_parameter));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_file));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_line));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_location));
+#if HAVE_LOCATION_LISTS
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+#else
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_block2));
+#endif
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(VARIABLE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_variable));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_external));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_flag));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_file));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_decl_line));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_location));
+#if HAVE_LOCATION_LISTS
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+#else
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_block2));
+#endif
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(BASETYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_base_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_encoding));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_byte_size));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(POINTERTYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_pointer_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(CONSTTYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_const_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(VOLATILETYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_volatile_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(ARRAYTYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_array_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(ARRAYDIM));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_subrange_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_upper_bound));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(STRUCTTYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_structure_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_byte_size));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(UNIONTYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_union_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_byte_size));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(STRUCTTAG));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_structure_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_byte_size));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(UNIONTAG));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_union_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_byte_size));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_udata));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(MEMBERTYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_member));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_name));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_string));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_data_member_location));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_block));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(FUNCTYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_subroutine_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(VOIDFUNCTYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_subroutine_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_yes));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+ dwarf2_print_uleb128(f,ul2zum(PARMTYPE));
+ dwarf2_print_uleb128(f,ul2zum(DW_TAG_formal_parameter));
+ dwarf2_print_uleb128(f,ul2zum(DW_CHILDREN_no));
+ dwarf2_print_uleb128(f,ul2zum(DW_AT_type));
+ dwarf2_print_uleb128(f,ul2zum(DW_FORM_ref_addr));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+ dwarf2_print_uleb128(f,ul2zum(0L));
+
+
+ info_start=++label;info_end=++label;
+ emit(f,"\t%s\t\".debug_info\"\n",dsec);
+
+ /* header */
+ emit(f,"%s%d:\n",lp,info_start);
+ emit(f,"\t%s\t%s%d-%s%d-4\n",dwarfd4,lp,info_end,lp,info_start);
+ emit(f,"\t%s\t2\n",dwarfd2); /* version */
+ emit(f,"\t%s\t%s%d\n",dwarfd4,lp,abbrev_label);
+ emit(f,"\t%s\t%d\n",dwarfd1,sizeof_addr);
+
+ /* compile_unit */
+ dwarf2_print_uleb128(f,ul2zum(COMP_UNIT));
+ dwarf2_print_uleb128(f,ul2zum(DW_LANG_C89));
+ line_start=++label;line_end=++label;
+ emit(f,"\t%s\t%s%d\n",da,lp,line_start);
+ for(p=copyright;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_ID_case_sensitive);
+ for(p=inname?inname:"<multiple>";*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+ emit(f,"\t%s\t0\n",dwarfd1);
+}
+static void dwarf2_cleanup(FILE *f)
+{
+ int i,line,file,label,length;char *p;
+ tdwarf2_line_info *li,*m;
+ Var *vl;
+ struct_declaration *sd;
+ emit(f,"\t%s\t\".debug_line\"\n",dsec);
+ /* line info */
+ emit(f,"%s%d:\n",lp,line_start);
+ emit(f,"\t%s\t%s%d-%s%d-4\n",dwarfd4,lp,line_end,lp,line_start); /* length */
+ emit(f,"\t%s\t2\n",dwarfd2); /* version */
+ length=16;
+ for(i=0;i<namecount;i++) length+=strlen(names[i])+4;
+ emit(f,"\t%s\t%d\n",dwarfd4,length); /* prologue length */
+ emit(f,"\t%s\t1\n",dwarfd1); /* instruction_length */
+ emit(f,"\t%s\t1\n",dwarfd1); /* is_stmt */
+ emit(f,"\t%s\t-10\n",dwarfd1); /* line_base */
+ emit(f,"\t%s\t245\n",dwarfd1); /* line_range */
+ emit(f,"\t%s\t10\n",dwarfd1); /* opcode_base */
+ emit(f,"\t%s\t0\n",dwarfd1); /* standard opcode arguments */
+ emit(f,"\t%s\t1\n",dwarfd1);
+ emit(f,"\t%s\t1\n",dwarfd1);
+ emit(f,"\t%s\t1\n",dwarfd1);
+ emit(f,"\t%s\t1\n",dwarfd1);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ emit(f,"\t%s\t1\n",dwarfd1);
+ emit(f,"\t%s\t0\n",dwarfd1); /* include directories */
+ for(i=0;i<namecount;i++){
+ for(p=names[i];*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ }
+ emit(f,"\t%s\t0\n",dwarfd1); /* file names */
+
+ file=-1;line=1;label=-1;
+ li=dwarf2_first_li;
+ while(li){
+ m=li->next;
+ if(li->file!=file){
+ file=li->file;
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_LNS_set_file);
+ dwarf2_print_uleb128(f,ul2zum((long)file));
+ }
+ if(!li->id&&li->label!=label){
+ label=li->label;
+ emit(f,"\t%s\t0\n",dwarfd1); /* extended opcode */
+ emit(f,"\t%s\t%d\n",dwarfd1,1+sizeof_addr); /* length */
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_LNE_set_address);
+ emit(f,"\t%s\t%s%d\n",da,lp,label);
+ }
+ if(li->id){
+ emit(f,"\t%s\t0\n",dwarfd1); /* extended opcode */
+ emit(f,"\t%s\t%d\n",dwarfd1,1+sizeof_addr); /* length */
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_LNE_set_address);
+ emit(f,"\t%s\t%s%s\n",da,ip,li->id);
+ free(li->id);
+ }
+ if(li->line!=line){
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_LNS_advance_line);
+ dwarf2_print_sleb128(f,l2zm((long)(li->line-line)));
+ line=li->line;
+ }
+ emit(f,"\t%s\t%d\n",dwarfd1,DW_LNS_copy);
+ free(li);
+ li=m;
+ }
+ emit(f,"\t%s\t0,1,1\n",dwarfd1); /* end_sequence */
+ emit(f,"%s%d:\n",lp,line_end);
+ emit(f,"\t%s\t\".debug_info\"\n",dsec);
+ for(sd=first_sd[0];sd;sd=sd->next){
+ if(sd->identifier){
+ static type styp;
+ styp.flags=sd->typ;
+ styp.exact=sd;
+ sd->label=0;
+ dwarf2_type(f,&styp);
+ }
+ }
+ for(vl=first_var[0];vl;vl=vl->next)
+ dwarf2_var(f,vl);
+ for(vl=first_ext;vl;vl=vl->next)
+ dwarf2_var(f,vl);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ emit(f,"%s%d:\n",lp,info_end);
+ for(i=0;i<namecount;i++) free(names[i]);
+ free(names);
+}
+/* generate line info for IC p, return 0 if nothing had to be generated */
+static void dwarf2_line_info(FILE *f,IC *p)
+{
+ static int line,file,n;
+ tdwarf2_line_info *new;
+ if(!f) return;
+ if(p->line==0) return;
+ if(!p->file) ierror(0);
+ n=dwarf2_file(p->file);
+ if(n!=file||p->line!=line){
+ file=n;
+ line=p->line;
+ emit(f,"%s%d:\n",lp,++label);
+ dwarf2_add_line(file,line,label,0);
+ }
+}
+
+static void dwarf2_function(FILE *f,Var *v,int endlabel)
+{
+ char *p;int l;Var *vl;
+ struct struct_identifier *si;
+ /* subprogram */
+ if(!f) return;
+ emit(f,"\t%s\t\".debug_info\"\n",dsec);
+ if(!v->vtyp||!v->vtyp->next) ierror(0);
+ if((v->vtyp->next->flags&NQ)==VOID){
+ dwarf2_print_uleb128(f,ul2zum(SUBPROGRAMVOID));
+ }else{
+ l=dwarf2_type(f,v->vtyp->next);
+ dwarf2_print_uleb128(f,ul2zum(SUBPROGRAM));
+ }
+ for(p=ip;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+ for(p=v->identifier;*p;p++) emit(f,"\t%s\t%d\n",dwarfd1,*p);
+ emit(f,"\t%s\t0\n",dwarfd1);
+ if(v->storage_class==EXTERN){
+ emit(f,"\t%s\t%s%s\n",da,ip,v->identifier);
+ }else{
+ emit(f,"\t%s\t%s%ld\n",da,lp,zm2l(v->offset));
+ }
+ emit(f,"\t%s\t%s%d\n",da,lp,endlabel);
+ if((v->vtyp->next->flags&NQ)!=VOID)
+ emit(f,"\t%s\t%s%d\n",da,lp,l);
+ if(!v->dfilename||v->dline<=0) ierror(0);
+ emit(f,"\t%s\t%d\n",dwarfd1,(v->storage_class==EXTERN));
+ if(v->storage_class==EXTERN)
+ dwarf2_add_line(dwarf2_file(v->dfilename),v->dline,0,v->identifier);
+ else
+ dwarf2_add_line(dwarf2_file(v->dfilename),v->dline,(int)zm2l(v->offset),0);
+ dwarf2_print_uleb128(f,ul2zum((long)dwarf2_file(v->dfilename)));
+ dwarf2_print_uleb128(f,ul2zum((long)v->dline));
+#if HAVE_LOCATION_LISTS
+ emit(f,"\t%s\t\".debug_loc\"\n",dsec);
+ emit(f,"%s%d:\n",lp,++label);
+ emit(f,"\t%s\t0\n",da);
+ emit(f,"\t%s\t-1\n",da);
+ dwarf2_print_frame_location(f,v);
+ emit(f,"\t%s\t0\n",da);
+ emit(f,"\t%s\t0\n",da);
+ emit(f,"\t%s\t\".debug_info\"\n",dsec);
+ emit(f,"\t%s\t%s%d\n",da,lp,label);
+#else
+ dwarf2_print_frame_location(f,v);
+#endif
+
+ /* children */
+
+ /*FIXME: not nice */
+ if(cross_module){
+ if(!v->fi) ierror(0);
+ for(vl=v->fi->vars;vl;vl=vl->next)
+ dwarf2_var(f,vl);
+ }else{
+ for(vl=first_var[1];vl;vl=vl->next)
+ dwarf2_var(f,vl);
+ for(vl=merk_varf;vl;vl=vl->next)
+ dwarf2_var(f,vl);
+ }
+
+
+ emit(f,"\t%s\t0\n",dwarfd1);
+}
diff --git a/errors.h b/errors.h
new file mode 100644
index 0000000..5d1b4e0
--- /dev/null
+++ b/errors.h
@@ -0,0 +1,374 @@
+/* $VER: vbcc (errors.h) V0.8 */
+
+"declaration expected",ERROR|ANSIV|FATAL, /* 0 */
+"only one input file allowed",ERROR|NOLINE|FATAL, /* 1 */
+"Flag <%s> specified more than once",NOLINE|WARNING, /* 2 */
+"Flag <%s> needs string",NOLINE|FATAL|ERROR, /* 3 */
+"Flag <%s> needs value",NOLINE|FATAL|ERROR, /* 4 */
+"Unknown Flag <%s>",NOLINE|FATAL|ERROR, /* 5 */
+"No input file",ERROR|NOLINE|FATAL, /* 6 */
+"Could not open <%s> for input",NOLINE|FATAL|ERROR, /* 7 */
+"need a struct or union to get a member",ERROR|ANSIV,
+"too many (%d) nested blocks",ERROR|FATAL,
+"left block 0",ERROR|ANSIV, /* 10 */
+"incomplete struct",ERROR|ANSIV,
+"out of memory",ERROR|FATAL,
+"redeclaration of struct <%s>",ERROR|ANSIV,
+"incomplete type (%s) in struct",ERROR|ANSIV,
+"function (%s) in struct/union",ERROR|ANSIV, /* 15 */
+"redeclaration of struct/union member <%s>",ERROR|ANSIV,
+"redeclaration of <%s>",ERROR|ANSIV,
+"invalid constant expression",ERROR|ANSIV,
+"array dimension must be constant integer",ERROR|ANSIV,
+"no declarator and no identifier in prototype",ERROR|ANSIV|FATAL, /* 20 */
+"invalid storage-class in prototype",ERROR|ANSIV,
+"void not the only function argument",ERROR|ANSIV,
+"<%s> no member of struct/union",ERROR|ANSIV,
+"increment/decrement is only allowed for aithmetic and pointer types",ERROR|ANSIV,
+"functions may not return arrays or functions",ERROR|ANSIV, /* 25 */
+"only pointers to functions can be called",ERROR|ANSIV,
+"redefinition of var <%s>",ERROR|ANSIV,
+"redeclaration of var <%s> with new storage-class",ERROR|ANSIV,
+"first operand of conditional-expression must be arithmetic or pointer type",ERROR|ANSIV,
+"multiple definitions of var <%s>",ERROR|ANSIV, /* 30 */
+"operands of : do not match",ERROR|ANSIV,
+"function definition in inner block",ERROR|ANSIV,
+"redefinition of function <%s>",ERROR|ANSIV,
+"invalid storage-class for function",ERROR|ANSIV,
+"declaration-specifiers expected",ERROR|ANSIV, /* 35 */
+"declarator expected",ERROR|ANSIV,
+"<%s> is no parameter",ERROR|ANSIV,
+"assignment of different structs/unions",ERROR|ANSIV,
+"invalid types for assignment",ERROR|ANSIV,
+"only 0 can be compared against pointer",WARNING|ANSIV, /* 40 */
+"pointers do not point to the same type",WARNING|ANSIV,
+"function initialized",ERROR|ANSIV|FATAL,
+"initialization of incomplete struct",ERROR|FATAL|ANSIV,
+"initialization of incomplete union",ERROR|FATAL|ANSIV,
+"empty initialization",ERROR|ANSIV, /* 45 */
+"initializer not a constant",ERROR|ANSIV,
+"double type-specifier",WARNING|ANSIV,
+"illegal type-specifier",WARNING|ANSIV,
+"multiple storage-classes",WARNING|ANSIV,
+"storage-class specifier should be first",WARNING|ANSIV, /* 50 */
+"bitfield type non-portable",WARNING,
+"bitfield width must be constant integer",WARNING|ANSIV,
+"struct/union member needs identifier",WARNING|ANSIV,
+"; expected",WARNING|ANSIV,
+"struct/union has no members",WARNING|ANSIV, /* 55 */
+"} expected",WARNING|ANSIV,
+", expected",WARNING|ANSIV,
+"invalid type-qualifier",WARNING|ANSIV,
+") expected",WARNING|ANSIV,
+"array dimension has sidefx (will be ignored)",WARNING|ANSIV, /* 60 */
+"array of size <=0 (set to 1)",WARNING|ANSIV,
+"] expected",WARNING|ANSIV,
+"mixed identifier- and parameter-type-list",WARNING|ANSIV,
+"var <%s> was never assigned a value",WARNING|DONTWARN|INFUNC,
+"var <%s> was never used",WARNING|DONTWARN|INFUNC, /* 65 */
+"invalid storage-class",WARNING|ANSIV,
+"type defaults to int",WARNING|DONTWARN,
+"redeclaration of var <%s> with new type",WARNING|ANSIV,
+"redeclaration of parameter <%s>",WARNING|ANSIV,
+": expected",WARNING|ANSIV, /* 70 */
+"illegal escape-sequence in string",WARNING|ANSIV,
+"character constant contains multiple chars",WARNING,
+"could not evaluate sizeof-expression",ERROR|ANSIV,
+"\" expected",ERROR|ANSIV,
+"something wrong with numeric constant",ERROR|ANSIV, /* 75 */
+"identifier expected",ERROR|ANSIV|FATAL,
+"definition does not match previous declaration",WARNING|ANSIV,
+"integer added to illegal pointer",WARNING|ANSIV,
+"offset equals size of object",WARNING|DONTWARN,
+"offset out of object",WARNING|ANSIV, /* 80 */
+"only 0 should be cast to pointer",WARNING|DONTWARN,
+"unknown identifier <%s>",ERROR|ANSIV,
+"too few function arguments",WARNING|ANSIV,
+"division by zero (result set to 0)",WARNING|ANSIV,
+"assignment of different pointers",WARNING|ANSIV, /* 85 */
+"lvalue required for assignment",ERROR|ANSIV,
+"assignment to constant type",ERROR|ANSIV,
+"assignment to incomplete type",ERROR|ANSIV,
+"operands for || and && have to be arithmetic or pointer",ERROR|ANSIV,
+"bitwise operations need integer operands",ERROR|ANSIV, /* 90 */
+"assignment discards const",WARNING|ANSIV,
+"relational expression needs arithmetic or pointer type",ERROR|ANSIV,
+"both operands of comparison must be pointers",ERROR|ANSIV,
+"operand needs arithmetic type",ERROR|ANSIV,
+"pointer arithmetic with void * is not possible",ERROR|ANSIV, /* 95 */
+"pointers can only be subtracted",ERROR|ANSIV,
+"invalid types for operation <%s>",ERROR|ANSIV,
+"invalid operand type",ERROR|ANSIV,
+"integer-pointer is not allowed",ERROR|ANSIV,
+"assignment discards volatile",WARNING|ANSIV, /* 100 */
+"<<, >> and %% need integer operands",ERROR|ANSIV,
+"casting from void is not allowed",ERROR|ANSIV,
+"integer too large to fit into pointer",WARNING,
+"only integers can be cast to pointers",ERROR|ANSIV,
+"invalid cast",ERROR|ANSIV, /* 105 */
+"pointer too large to fit into integer",WARNING|ANSIV,
+"unary operator needs arithmetic type",ERROR|ANSIV,
+"negation type must be arithmetic or pointer",ERROR|ANSIV,
+"complement operator needs integer type",ERROR|ANSIV,
+"pointer assignment with different qualifiers",WARNING|ANSIV, /* 110 */
+"dereferenced object is no pointer",ERROR|ANSIV,
+"dereferenced object is incomplete",ERROR|ANSIV,
+"only 0 should be assigned to pointer",WARNING|ANSIV,
+"typedef <%s> is initialized",WARNING|ANSIV,
+"lvalue required to take address",ERROR|ANSIV, /* 115 */
+"unknown var <%s>",ERROR|ANSIV,
+"address of register variables not available",ERROR|ANSIV,
+"var <%s> initialized after \'extern\'",WARNING,
+"const var <%s> not initialized",WARNING,
+"function definition after \'extern\'",WARNING|ANSIV, /* 120 */
+"return type of main is not int",WARNING|ANSIV,
+"invalid storage-class for function parameter",WARNING|ANSIV,
+"formal parameters conflict with parameter-type-list",WARNING|ANSIV,
+"parameter type defaults to int",WARNING|DONTWARN,
+"no declaration-specifier, used int",WARNING|ANSIV, /* 125 */
+"no declarator in prototype",WARNING|ANSIV,
+"static var <%s> never defined",WARNING,
+"} expected",WARNING,
+"left operand of comma operator has no side-effects",WARNING,
+"label empty",ERROR|ANSIV, /* 130 */
+"redefinition of label <%s>",ERROR|ANSIV,
+"case without switch",ERROR|ANSIV,
+"case-expression must be constant",ERROR|ANSIV,
+"case-expression must be integer",ERROR|ANSIV,
+"empty if-expression",ERROR|ANSIV, /* 135 */
+"if-expression must be arithmetic or pointer",ERROR|ANSIV,
+"empty switch-expression",ERROR|ANSIV,
+"switch-expression must be integer",ERROR|ANSIV,
+"multiple default labels",ERROR|ANSIV,
+"while-expression must be arithmetic or pointer",ERROR|ANSIV, /* 140 */
+"empty while-expression",ERROR|ANSIV,
+"for-expression must be arithmetic or pointer",ERROR|ANSIV,
+"do-while--expression must be arithmetic or pointer",ERROR|ANSIV,
+"goto without label",ERROR|ANSIV,
+"continue not within loop",ERROR|ANSIV, /* 145 */
+"break not in matching construct",ERROR|ANSIV,
+"label <%s> was never defined",ERROR|ANSIV|INFUNC|NORAUS,
+"label <%s> was never used",WARNING|INFUNC,
+"register %s not ok",WARNING,
+"default not in switch",WARNING|ANSIV, /* 150 */
+"( expected",WARNING|ANSIV,
+"loop eliminated",WARNING,
+"statement has no effect",WARNING,
+"\'while\' expected",WARNING|ANSIV,
+"function should not return a value",WARNING|ANSIV, /* 155 */
+"function should return a value",WARNING,
+"{ expected",WARNING|ANSIV,
+"internal error %d in line %d of file %s !!",ERROR|INTERNAL|FATAL,
+"there is no message number %d",NOLINE|FATAL|ERROR,
+"message number %d cannot be suppressed",ERROR|NOLINE|FATAL, /* 160 */
+"implicit declaration of function <%s>",WARNING|DONTWARN,
+"function call without prototype in scope",WARNING|DONTWARN,
+"#pragma used",WARNING|DONTWARN,
+"assignment in comparison context",WARNING|DONTWARN,
+"comparison redundant because operand is unsigned",WARNING, /* 165 */
+"cast to narrow type may cause loss of precision",WARNING|DONTWARN,
+"pointer cast may cause alignment problems",WARNING|DONTWARN,
+"no declaration of global variable <%s> before definition",WARNING|DONTWARN,
+"'extern' inside function",WARNING|DONTWARN,
+"dead assignment to <%s%s> eliminated",WARNING|INFUNC|INIC|DONTWARN,/* 170 */
+"var <%s> is used before defined",WARNING|INFUNC,
+"would need more than %ld optimizer passes for best results",WARNING|INFUNC,
+"function <%s> has no return statement",WARNING|INFUNC,
+"function <%s> has no return statement",WARNING|DONTWARN|INFUNC,
+"this code is weird",WARNING|INFUNC, /* 175 */
+"size of incomplete type not available",WARNING|ANSIV,
+"line too long",FATAL|ERROR|ANSIV|PREPROC,
+"identifier must begin with a letter or underscore",FATAL|ERROR|ANSIV|PREPROC,
+"cannot redefine macro",ERROR|ANSIV|PREPROC,
+"missing ) after argumentlist",ERROR|ANSIV|PREPROC, /* 180 */
+"identifier expected",ERROR|ANSIV|PREPROC,
+"illegal character in identifier",ERROR|ANSIV|PREPROC,
+"missing operand before/after ##",ERROR|ANSIV|PREPROC,
+"no macro-argument after #-operator",ERROR|ANSIV|PREPROC,
+"macro redefinition not allowed",ERROR|ANSIV|PREPROC, /* 185 */
+"unexpected end of file (unterminated comment)",FATAL|ERROR|PREPROC,
+"too many nested includes",FATAL|ERROR|PREPROC,
+"#else without #if/#ifdef/#ifndef",FATAL|ERROR|ANSIV|PREPROC,
+"#else after #else",ERROR|ANSIV|PREPROC,
+"#endif without #if",ERROR|ANSIV|PREPROC, /* 190 */
+"cannot include file",FATAL|ERROR|PREPROC,
+"expected \" or < in #include-directive",ERROR|ANSIV|PREPROC,
+"unknown #-directive",WARNING|PREPROC,
+"wrong number of macro arguments",ERROR|ANSIV|PREPROC,
+"macro argument expected",ERROR|ANSIV|PREPROC, /* 195 */
+"out of memory",FATAL|ERROR|PREPROC,
+"macro redefinition",WARNING|PREPROC,
+"/* in comment",WARNING|PREPROC,
+"cannot undefine macro",ERROR|ANSIV|PREPROC,
+"characters after #-directive ignored",WARNING|PREPROC, /* 200 */
+"duplicate case labels",WARNING|ANSIV,
+"var <%s> is incomplete",WARNING|ANSIV,
+"long float is no longer valid",WARNING|ANSIV,
+"long double is not really supported by vbcc",WARNING,
+"empty struct-declarations are not yet handled correct",WARNING, /* 205 */
+"identifier too long (only %d characters are significant)",WARNING,
+"illegal initialization of var <%s>",WARNING|ANSIV,
+"suspicious loop",WARNING|INFUNC,
+"ansi/iso-mode turned on",NOLINE|WARNING,
+"division by zero (result set to 0)",WARNING|ANSIV|INFUNC|INIC, /* 210 */
+"constant out of range",WARNING|ANSIV,
+"constant is unsigned due to size",WARNING|DONTWARN,
+"varargs function called without prototype in scope",WARNING,
+"suspicious format string",WARNING,
+"format string contains \'\\0\'",WARNING, /* 215 */
+"illegal use of keyword <%s>",WARNING|ANSIV,
+"register <%s> used with wrong type",ERROR,
+"register <%s> is not free",ERROR,
+"'__reg' used in old-style function definition",WARNING,
+"unknown register \"%s\"",WARNING, /* 220 */
+"'...' only allowed with prototypes",WARNING|ANSIV,
+"Hey, do you really know the priority of '&&' vs. '||'?",WARNING|DONTWARN,
+"be careful with priorities of <</>> vs. +/-",WARNING,
+"address of auto variable returned",WARNING,
+"void function returns a void expression",WARNING, /* 225 */
+"redeclaration of typedef <%s>",WARNING|ANSIV,
+"multiple specification of attribute \"%s\"",WARNING,
+"redeclaration of var \"%s\" with differing setting of attribute \"%s\"",WARNING,
+"string-constant expected",ERROR,
+"tag \"%s\" used for wrong type",WARNING|ANSIV, /* 230 */
+"member after flexible array member",ERROR|ANSIV,
+"illegal number",ERROR|ANSIV,
+"void character constant",PREPROC|ERROR|ANSIV,
+"spurious tail in octal character constant",PREPROC|ERROR|ANSIV,
+"spurious tail in hexadecimal character constant",PREPROC|ERROR|ANSIV, /* 235 */
+"illegal escape sequence in character constant",PREPROC|ERROR|ANSIV,
+"invalid constant integer value",PREPROC|ERROR|ANSIV,
+"a right parenthesis was expected",PREPROC|ERROR|ANSIV,
+"a colon was expected",PREPROC|ERROR|ANSIV,
+"truncated constant integral expression",PREPROC|ERROR|ANSIV, /* 240 */
+"rogue operator '%s' in constant integral expression",PREPROC|ERROR|ANSIV,
+"invalid token in constant integral expression",PREPROC|ERROR|ANSIV,
+"trailing garbage in constant integral expression",PREPROC|ERROR|ANSIV,
+"void condition for a #if/#elif",PREPROC|ERROR|ANSIV,
+"void condition (after expansion) for a #if/#elif",PREPROC|ERROR|ANSIV, /* 245 */
+"invalid '#include'",PREPROC|ERROR|ANSIV,
+"macro expansion did not produce a valid filename for #include",PREPROC|ERROR|ANSIV,
+"file '%s' not found",PREPROC|ERROR|ANSIV,
+"not a valid number for #line",PREPROC|ERROR|ANSIV,
+"not a valid filename for #line",PREPROC|ERROR|ANSIV, /* 250 */
+"rogue '#'",PREPROC|ERROR|ANSIV,
+"rogue #else",PREPROC|ERROR|ANSIV,
+"rogue #elif",PREPROC|ERROR|ANSIV,
+"unmatched #endif",PREPROC|ERROR|ANSIV,
+"unknown cpp directive '#%s'",PREPROC|WARNING|ANSIV, /* 255 */
+"unterminated #if construction",PREPROC|ERROR|ANSIV,
+"could not flush output (disk full ?)",PREPROC|ERROR|ANSIV,
+"truncated token",PREPROC|ERROR|ANSIV,
+"illegal character '%c'",PREPROC|ERROR|ANSIV,
+"unfinished string at end of line",PREPROC|ERROR|ANSIV, /* 260 */
+"missing macro name",PREPROC|ERROR|ANSIV,
+"trying to redefine the special macro %s",PREPROC|ERROR|ANSIV,
+"truncated macro definition",PREPROC|ERROR|ANSIV,
+"'...' must end the macro argument list",PREPROC|ERROR|ANSIV,
+"void macro argument",PREPROC|ERROR|ANSIV, /* 265 */
+"missing comma in macro argument list",PREPROC|ERROR|ANSIV,
+"invalid macro argument",PREPROC|ERROR|ANSIV,
+"duplicate macro argument",PREPROC|ERROR|ANSIV,
+"'__VA_ARGS__' is forbidden in macros with a fixed number of arguments",PREPROC|ERROR|ANSIV,
+"operator '##' may neither begin nor end a macro",PREPROC|ERROR|ANSIV, /* 270 */
+"operator '#' not followed by a macro argument",PREPROC|ERROR|ANSIV,
+"macro '%s' redefined unidentically",PREPROC|ERROR|ANSIV,
+"not enough arguments to macro",PREPROC|ERROR|ANSIV,
+"unfinished macro call",PREPROC|ERROR|ANSIV,
+"too many arguments to macro",PREPROC|ERROR|ANSIV, /* 275 */
+"operator '##' produced the invalid token '%s%s'",PREPROC|ERROR|ANSIV,
+"quad sharp",PREPROC|ERROR|ANSIV,
+"void macro name",PREPROC|ERROR|ANSIV,
+"macro %s already defined",PREPROC|ERROR|ANSIV,
+"trying to undef special macro %s",PREPROC|ERROR|ANSIV, /* 280 */
+"illegal macro name for #ifdef",PREPROC|ERROR|ANSIV,
+"unfinished #ifdef",PREPROC|ERROR|ANSIV,
+"illegal macro name for #undef",PREPROC|ERROR|ANSIV,
+"unfinished #undef",PREPROC|ERROR|ANSIV,
+"illegal macro name for #ifndef",PREPROC|ERROR|ANSIV, /* 285 */
+"unfinished #ifndef",PREPROC|ERROR|ANSIV,
+"reconstruction of <foo> in #include",PREPROC|WARNING|DONTWARN,
+"comment in the middle of a cpp directive",PREPROC|WARNING|DONTWARN,
+"null cpp directive",PREPROC|WARNING|DONTWARN,
+"rogue '#' in code compiled out",PREPROC|WARNING, /* 290 */
+"rogue '#' dumped",PREPROC|WARNING|DONTWARN,
+"#error%s",PREPROC|ANSIV|ERROR,
+"trigraph ?""?%c encountered",PREPROC|WARNING,
+"unterminated #if construction (depth %ld)",PREPROC|ERROR|ANSIV,
+"malformed identifier with UCN: '%s'",PREPROC|WARNING|ANSIV, /* 295 */
+"truncated UTF-8 character",PREPROC|WARNING|ANSIV,
+"identifier not followed by whitespace in #define",PREPROC|WARNING|ANSIV,
+"assignment discards restrict",WARNING|ANSIV,
+"storage-class in declaration within for() converted to auto",WARNING|ANSIV,
+"corrupted special object",ANSIV|FATAL, /* 300 */
+"<inline> only allowed in function declarations",ERROR|ANSIV,
+"reference to static variable <%s> in inline function with external linkage",ERROR|ANSIV,
+"underflow of pragma popwarn",ERROR|FATAL|ANSIV,
+"invalid argument to _Pragma",ERROR|ANSIV|PREPROC,
+"missing comma before '...'",ERROR|ANSIV|PREPROC, /* 305 */
+"padding bytes behind member <%s>",WARNING|DONTWARN,
+"member <%s> does not have natural alignment",WARNING|DONTWARN,
+"function <%s> exceeds %s limit",WARNING,
+"%s could not be calculated for function <%s>",WARNING,
+"offsetof applied to non-struct",ERROR|ANSIV, /* 310 */
+"trailing garbage in #ifdef",WARNING|ANSIV|PREPROC,
+"too many arguments to macro",WARNING|ANSIV|PREPROC,
+"truncated comment",WARNING|ANSIV|PREPROC,
+"trailing garbage in preprocessing directive",WARNING|ANSIV|PREPROC,
+"variable-length array must have auto storage-class",ERROR|ANSIV, /* 315 */
+"member <%s> has type with zero alignment/size (probably void)",ERROR|ANSIV|FATAL,
+"stack information for target <%s> unavailable",WARNING|INIC|DONTWARN,
+"used registers information unavailable for target <%s>",WARNING|INIC|DONTWARN,
+"computed %sstack usage %d but set to %d",WARNING|INFUNC,
+"unable to compute call targets",WARNING|INIC|DONTWARN, /* 320 */
+"computed register usage differs from specified one",WARNING|INFUNC,
+"trailing garbage in #include",WARNING|ANSIV|PREPROC,
+"target-warning: %s",WARNING,
+"target-error: %s",ERROR|FATAL,
+"#warning%s",WARNING|PREPROC|ANSIV, /* 325 */
+"trailing garbage in #undef",WARNING|PREPROC|ANSIV,
+"Flag <%s>: syntax error",FATAL|ERROR|NOLINE,
+"Wrong MISRA version (%d) specified for flag %s%s",FATAL|ERROR|NOLINE,
+"No such MISRA 1998 Rule (%d) in flag %s%s",FATAL|ERROR|NOLINE,
+"No such MISRA 2004 Rule(%d.%d) in flag %s%s",FATAL|ERROR|NOLINE, /* 330 */
+"unknown register <%s>",FATAL|ERROR|NOLINE,
+"illegal bitfield size",ERROR|ANSIV,
+"Flag <%s> conflicts with flag <%s>",FATAL|ERROR|NOLINE,
+"vbcc was not compiled with <%s> support",FATAL|ERROR|NOLINE,
+"{ expected",ERROR|ANSIV, /* 335 */
+"base class <%s> has incomplete type",ERROR|ANSIV,
+"unknown class/struct <%s>",ERROR|ANSIV,
+"<%s> declared as a virtual field",ERROR|ANSIV,
+"<virtual> only allowed at method declarations",ERROR|ANSIV,
+"no such member function declared",ERROR|ANSIV, /* 340 */
+":: unexpected",ERROR|ANSIV,
+"polymorphic type <%s> must be initialized by constructor",ERROR|ANSIV,
+"unknown language in linkage specification <%s>",ERROR|ANSIV,
+"multiple initializations for <%s>",ERROR|ANSIV,
+"too many arguments for <%s>",ERROR|ANSIV, /* 345 */
+"no fitting overloaded function found",ERROR|ANSIV,
+"call of overloaded function <%s> is ambiguous",ERROR|ANSIV,
+"member differs from previous declaration",ERROR|ANSIV,
+"member not previously declared",ERROR|ANSIV,
+"access is %s",ERROR|ANSIV, /* 350 */
+"jump into scope of variable-length-array",ERROR|ANSIV|INIC|FATAL,
+"variable-length-array (%s) in struct/union",ERROR|ANSIV,
+"encountered non-existent label during optimizing",ERROR|ANSIV|INFUNC|FATAL,
+"array designator not in valid range",ERROR|ANSIV,
+"'=' expected",ERROR|ANSIV, /* 355 */
+"type has non-empty identifier",WARNING|ANSIV,
+"unterminated // comment",PREPROC|WARNING|ANSIV,
+"initialization of variable-length array",ERROR|ANSIV,
+"initialization of flexible array member",ERROR|ANSIV,
+"empty initializer",ERROR|FATAL|ANSIV, /* 360 */
+"redeclaration of var <%s> as new function",ERROR|FATAL|ANSIV,
+"constant implicitly sign-changed",WARNING|DONTWARN,
+"constant implicitly truncated",WARNING,
+"hexadecimal escape sequence overflow",WARNING,
+"missing identifier",ERROR|FATAL|ANSIV, /* 365 */
+"negative shift count is undefined",WARNING,
+"shift count too large for data type",WARNING,
+"redeclaration of function argument with different register",WARNING,
+"declaration expected",WARNING|ANSIV,
+"possible redeclaration of var <%s> with different attributes <%s> and <%s>",WARNING, /* 370 */
+"redeclaration of var <%s> with new attribute <%s>",WARNING,
diff --git a/flow.c b/flow.c
new file mode 100644
index 0000000..5be1c0c
--- /dev/null
+++ b/flow.c
@@ -0,0 +1,609 @@
+/* $VER: vbcc (flow.c) $Revision: 1.13 $ */
+/* Generierung des FLussgraphs und Optimierungen des Kontrollflusses */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+int bvcmp(bvtype *dest,bvtype *src,size_t len)
+/* vergleicht zwei Bitvektoren */
+{
+ len/=sizeof(bvtype);
+ for(;len>0;len--)
+ if(*dest++!=*src++) return(0);
+ return(1);
+}
+/* Schnittmenge nicht leer? */
+int bvdointersect(bvtype *p1,bvtype *p2,size_t len)
+{
+ len/=sizeof(bvtype);
+ for(;len>0;len--)
+ if(*p1++&*p2++)
+ return 1;
+ return 0;
+}
+void bvunite(bvtype *dest,bvtype *src,size_t len)
+/* berechnet Vereinigung zweier Bitvektoren */
+{
+ len/=sizeof(bvtype);
+ for(;len>0;len--)
+ *dest++|=*src++;
+}
+void bvintersect(bvtype *dest,bvtype *src,size_t len)
+/* berechnet Durchschnitt zweier Bitvektoren */
+{
+ len/=sizeof(bvtype);
+ for(;len>0;len--)
+ *dest++&=*src++;
+}
+void bvdiff(bvtype *dest,bvtype *src,size_t len)
+/* berechnet 'Differenz' zweier Bitvektoren */
+{
+ len/=sizeof(bvtype);
+ for(;len>0;len--)
+ *dest++&=~(*src++);
+}
+
+unsigned int basic_blocks;
+
+flowgraph *new_flowgraph(void)
+{
+ flowgraph *new;
+ new=mymalloc(sizeof(*new));
+ new->av_in=new->av_out=new->av_gen=new->av_kill=0;
+ new->rd_in=new->rd_out=new->rd_gen=new->rd_kill=0;
+ new->ae_in=new->ae_out=new->ae_gen=new->ae_kill=0;
+ new->cp_in=new->cp_out=new->cp_gen=new->cp_kill=0;
+ new->pt=0;
+ new->start=new->end=0;
+ new->normalout=new->branchout=0;
+ new->in=0;
+ new->loopend=0;
+#if ALEX_REG
+ new->loop_depth=0;
+#endif
+ return new;
+}
+
+flowgraph *construct_flowgraph(void)
+/* entfernt ueberfluessige Labels und erzeugt Flussgraph */
+{
+ IC *p,*cl;
+ int firstl,lcnt,currentl,i,code,l;
+ int *iseq,*used;
+ flowgraph **lg,*g,*fg;
+ if(cross_module){
+ int lastl;
+ firstl=0;lastl=0;lcnt=0;
+ for(p=first_ic;p;p=p->next){
+ if(p->code==LABEL){
+ if(p->typf<firstl) firstl=p->typf;
+ if(p->typf>lastl) lastl=p->typf;
+ }
+ }
+ lcnt=lastl-firstl+1;
+ }else{
+ firstl=lastlabel;
+ lcnt=label-firstl;
+ }
+ return_label=0;
+ if(last_ic&&last_ic->code==LABEL) return_label=last_ic->typf;
+ if(last_ic&&last_ic->code==SETRETURN&&last_ic->prev&&last_ic->prev->code==LABEL) return_label=last_ic->prev->typf;
+
+ iseq=mymalloc(lcnt*sizeof(int));
+ used=mymalloc(lcnt*sizeof(int));
+ lg=mymalloc(lcnt*sizeof(flowgraph *));
+ g=new_flowgraph();
+ fg=g;
+ g->start=first_ic;g->in=0;g->branchout=0;g->loopend=0;
+
+ for(i=0;i<lcnt;i++) {iseq[i]=used[i]=0;lg[i]=0;}
+ currentl=0;firstl++;
+ /* Diese Schleife entfernt alle Labels, die mit anderen */
+ /* uebereinstimmen, merkt sich das und kennzeichnet alle */
+ /* Labels, die benutzt werden. */
+ /* Ausserdem wird der Flussgraph teilweise aufgebaut. */
+ if(DEBUG&1024) {puts("construct_flowgraph(): loop1");/*scanf("%d",&i);*/}
+ i=1;g->index=i;
+ for(p=first_ic;p;){
+ code=p->code;
+ if(code>=BEQ&&code<=BRA){
+ l=p->typf;
+ /* als used markieren; falls aequivalent, das erste markieren */
+ if(iseq[l-firstl]) used[iseq[l-firstl]-firstl]=1;
+ else used[l-firstl]=1;
+ /* Flussgraph beenden und evtl. naechsten Knoten erzeugen */
+ g->end=p;
+ if(p->next){
+ g->normalout=new_flowgraph();
+ g->normalout->in=mymalloc(sizeof(flowlist));
+ g->normalout->in->next=0;
+ g->normalout->in->graph=g;
+ g=g->normalout;
+ g->start=p->next;
+ g->branchout=0;
+ g->loopend=0;
+ g->index=++i;
+ }else g->normalout=0;
+
+ currentl=0;p=p->next;continue;
+ }
+ if(code==ALLOCREG||code==FREEREG){p=p->next; continue;}
+ if(code!=LABEL){currentl=0;p=p->next;continue;}
+ /* ist ein Label */
+ l=p->typf;
+ if(currentl){
+ IC *m;
+ iseq[l-firstl]=currentl;
+ if(l==return_label) return_label=currentl;
+ if(used[l-firstl]) used[currentl-firstl]=1;
+ cl->flags|=p->flags;
+ m=p;p=p->next;
+ remove_IC(m);
+ continue;
+/* if(DEBUG&1024) printf("label %d==%d\n",l,iseq[l-firstl]);*/
+ }else{
+ currentl=l;cl=p;
+ if(g->start!=p){
+ g->end=p->prev;
+ g->normalout=new_flowgraph();
+ g->normalout->in=mymalloc(sizeof(flowlist));
+ g->normalout->in->next=0;
+ g->normalout->in->graph=g;
+ g=g->normalout;
+ g->start=p;
+ g->branchout=0;
+ g->loopend=0;
+ g->index=++i;
+ }else g->branchout=0;
+ lg[l-firstl]=g;
+ }
+ p=p->next;
+ }
+ g->end=last_ic;g->normalout=g->branchout=0;
+ if(DEBUG&(16384|1024)) printf("%d basic blocks\n",i);
+ basic_blocks=i;
+
+/* if(DEBUG&1024) for(i=firstl;i<=lcnt;i++) printf("L%d used: %d\n",i,used[i-firstl]);*/
+ /* Diese Schleife entfernt alle nicht benutzten Labels und biegt alle */
+ /* Branches auf aequivalente Labels um. */
+ if(DEBUG&1024) {puts("construct_flowgraph(): loop2");/*scanf("%d",&i);*/}
+ g=fg;
+ while(g){
+ int flag=0;flowlist *lp;
+/* printf("g=%p\n",(void *)g);*/
+ g->av_in=g->av_out=g->av_gen=g->av_kill=0;
+ g->rd_in=g->rd_out=g->rd_gen=g->rd_kill=0;
+ g->ae_in=g->ae_out=g->ae_gen=g->ae_kill=0;
+ g->cp_in=g->cp_out=g->cp_gen=g->cp_kill=0;
+ g->pt=0;
+ p=g->start;
+ while(p&&!flag){
+/* pric2(stdout,p);*/
+ code=p->code;
+ if(code>=BEQ&&code<=BRA){
+ l=p->typf;
+ if(iseq[l-firstl]) p->typf=l=iseq[l-firstl];
+ /* in Flussgraph eintragen */
+ g->branchout=lg[l-firstl];
+ if(!lg[l-firstl]) error(353);
+ lp=lg[l-firstl]->in;
+ /* das hier sollte man noch schoener machen */
+ if(!lp){
+ lg[l-firstl]->in=mymalloc(sizeof(flowlist));
+ lg[l-firstl]->in->next=0;
+ lg[l-firstl]->in->graph=g;
+ }else{
+ while(lp&&lp->next) lp=lp->next;
+ lp->next=mymalloc(sizeof(flowlist));
+ lp->next->next=0;
+ lp->next->graph=g;
+ }
+ }
+/* if(code==LABEL&&!used[p->typf-firstl]) remove_IC(p);*/
+ if(p==g->end) flag=1;
+ p=p->next;
+ }
+ g=g->normalout;
+ }
+ /* Unbenutzte Labels entfernen und Bloecke verbinden */
+ if(DEBUG&1024) {puts("construct_flowgraph(): loop3");/*scanf("%d",&i);*/}
+ for(g=fg;g;g=g->normalout){
+ if(g->end&&(g->end->code<BEQ||g->end->code>BRA)){
+ flowgraph *next=g->normalout;flowlist *lp;
+ if(next&&next->start&&next->start->code==LABEL&&!used[next->start->typf-firstl]){
+ if(next->end!=next->start) g->end=next->end;
+ g->normalout=next->normalout;
+ g->branchout=next->branchout;
+ free(next->in); /* darf eigentlich nur einen Vorgaenger haben */
+ /* in im Nachfolgeknoten auf den ersten der beiden setzen */
+ if(next->normalout&&next->normalout->in) next->normalout->in->graph=g;
+ /* in im Ziel von next->branchout auf den ersten setzen */
+ if(next->branchout){
+ lp=next->branchout->in;
+ while(1){
+ if(lp->graph==next){ lp->graph=g;break;}
+ lp=lp->next;if(!lp) ierror(0);
+ }
+ }
+ if(DEBUG&1024){ printf("unused label deleted:\n");pric2(stdout,next->start);}
+ remove_IC(next->start);
+ free(next);
+ }
+ }
+ /* unbenutzte Labels entfernen */
+ if(g->start&&g->start->code==LABEL&&!used[g->start->typf-firstl])
+ remove_IC_fg(g,g->start);
+ }
+ free(iseq);
+ free(used);
+ return(fg);
+}
+
+void print_flowgraph(flowgraph *g)
+/* Gibt Flussgraph auf Bildschirm aus */
+{
+ static int dontprint=0;
+ int flag,i;flowlist *lp;IC *ip;
+ if(dontprint>0) {dontprint--;return;}
+ if(dontprint!=-1){
+ puts("print_flowgraph()");scanf("%d",&i);
+ if(i<-1){dontprint=-i;return;}
+ if(!i) return;
+ if(i==-1){dontprint=-1; i=1;}
+ }else{
+ i=1;
+ }
+ while(g){
+ printf("\nBasic Block nr. %d\n",g->index);
+ printf("\tin from ");
+ lp=g->in;
+ while(lp){if(lp->graph) printf("%d ",lp->graph->index);lp=lp->next;}
+ printf("\n\tout to %d %d\n",g->normalout?g->normalout->index:0,g->branchout?g->branchout->index:0);
+ if(g->loopend) printf("head of a loop ending at block %d\n",g->loopend->index);
+ if(!(optflags&32)&&g->pt)
+ ierror(0);
+ if(i&2){
+ printf("av_gen:\n"); print_av(g->av_gen);
+ printf("av_kill:\n"); print_av(g->av_kill);
+ printf("av_in:\n"); print_av(g->av_in);
+ printf("av_out:\n"); print_av(g->av_out);
+ }
+ if(i&4){
+ printf("rd_gen:\n"); print_rd(g->rd_gen);
+ printf("rd_kill:\n"); print_rd(g->rd_kill);
+ printf("rd_in:\n"); print_rd(g->rd_in);
+ printf("rd_out:\n"); print_rd(g->rd_out);
+ }
+ if(i&8){
+ printf("ae_gen:\n"); print_ae(g->ae_gen);
+ printf("ae_kill:\n"); print_ae(g->ae_kill);
+ printf("ae_in:\n"); print_ae(g->ae_in);
+ printf("ae_out:\n"); print_ae(g->ae_out);
+ }
+ if(i&16){
+ printf("cp_gen:\n"); print_cp(g->cp_gen);
+ printf("cp_kill:\n"); print_cp(g->cp_kill);
+ printf("cp_in:\n"); print_cp(g->cp_in);
+ printf("cp_out:\n"); print_cp(g->cp_out);
+ }
+ if(i&32){
+ int r;
+ for(r=1;r<=MAXR;r++)
+ if(g->regv[r]) printf("(%s),%ld assigned to %s\n",g->regv[r]->identifier,(long)zm2l(g->regv[r]->offset),regnames[r]);
+ }
+ if(i&64){
+ print_pt(g->pt);
+ }
+ flag=0;ip=g->start;
+ while(ip&&!flag){
+ pric2(stdout,ip);
+ if(i&64){
+ int r;
+ printf("changes: ");
+ for(r=0;r<ip->change_cnt;r++)
+ printf("(%s,%ld,%d,%d)",ip->change_list[r].v->identifier,(long)zm2l(ip->change_list[r].v->offset),ip->change_list[r].flags,ip->change_list[r].v->index);
+ printf("\nuses: ");
+ for(r=0;r<ip->use_cnt;r++)
+ printf("(%s,%ld,%d,%d)",ip->use_list[r].v->identifier,(long)zm2l(ip->use_list[r].v->offset),ip->use_list[r].flags,ip->use_list[r].v->index);
+ printf("\n");
+ }
+ if(ip==g->end) flag=1;
+ ip=ip->next;
+ }
+ g=g->normalout;
+ }
+ printf("return_label=%d\n",return_label);
+}
+void free_flowgraph(flowgraph *g)
+/* Gibt Flussgraph frei */
+{
+ flowgraph *pm;flowlist *lp,*lpm;
+ if(DEBUG&(16384|1024)) puts("free_flowgraph()");
+ while(g){
+ lp=g->in;
+ while(lp){
+ lpm=lp->next;
+ free(lp);
+ lp=lpm;
+ }
+ free(g->av_in);
+ free(g->av_out);
+ free(g->av_gen);
+ free(g->av_kill);
+ free(g->rd_in);
+ free(g->rd_out);
+ free(g->rd_gen);
+ free(g->rd_kill);
+ free(g->ae_in);
+ free(g->ae_out);
+ free(g->ae_gen);
+ free(g->ae_kill);
+ free(g->cp_in);
+ free(g->cp_out);
+ free(g->cp_gen);
+ free(g->cp_kill);
+ free_pt(g->pt);
+
+ pm=g->normalout;
+ free(g);
+ g=pm;
+ }
+}
+static void mark_reachable(flowgraph *fg)
+/* negiert den index aller Bloecke, die reachable sind */
+{
+ fg->index=-fg->index;
+ if(fg->branchout&&fg->branchout->index>=0)
+ mark_reachable(fg->branchout);
+ if(fg->normalout&&(!fg->end||fg->end->code!=BRA)&&fg->normalout->index>=0)
+ mark_reachable(fg->normalout);
+}
+flowgraph *jump_optimization(void)
+/* entfernt ueberfluessige Spruenge etc. */
+{
+ flowgraph *fg,*g;IC *p;int changed,i;
+ flowlist *lp;
+ do{
+ changed=0;
+ fg=construct_flowgraph();
+ mark_reachable(fg);
+ if(DEBUG&1024) {printf("jump_optimization() pass\n");print_flowgraph(fg);}
+ g=fg;
+ while(g){
+ /* tote Bloecke entfernen */
+ if(g->index<0){
+ g->index=-g->index;
+ }else{
+ IC *m;
+ if(DEBUG&1024) printf("deleting dead block %d\n",g->index);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ p=g->start;i=0;
+ while(p&&!i){
+ if(p==g->end) i=1;
+ if(DEBUG&1024) pric2(stdout,p);
+ m=p->next;
+ remove_IC_fg(g,p);changed=gchanged=1;
+ p=m;
+ }
+ if(g->branchout){
+ /* Eintrag in Ziel loeschen (nur einmal, falls auch normalout) */
+ lp=g->branchout->in;
+ while(lp){
+ if(lp->graph==g){ lp->graph=0;break;}
+ lp=lp->next;
+ }
+ g->branchout=0;
+ }
+ g=g->normalout;continue;
+ }
+ /* Spruenge zum folgenden Code entfernen */
+ if(g->normalout&&g->normalout==g->branchout){
+ p=g->end;
+ if(!p||p->code<BEQ||p->code>BRA) ierror(0);
+ if(DEBUG&1024){printf("branch to following label deleted:\n");pric2(stdout,p);}
+ remove_IC_fg(g,p);g->branchout=0;changed=gchanged=1;
+ p=g->end;
+ /* vorangehenden Vergleich auch entfernen */
+ if(p&&(p->code==COMPARE||p->code==TEST)){
+ if(DEBUG&1024){printf("preceding comparison also deleted:\n");pric2(stdout,p);}
+ remove_IC_fg(g,p);
+ }
+ }
+
+ /* bcc l1;bra l2;l1 aendern */
+ p=g->end;
+ if(p&&p->code>=BEQ&&p->code<BRA&&g->normalout){
+ if(g->normalout->start&&g->normalout->start->code==BRA){
+ if(g->normalout->normalout==g->branchout){
+ g->branchout=g->normalout->branchout;
+ i=p->typf;
+ p->typf=g->normalout->start->typf;
+ if(DEBUG&1024) printf("changing bcc l%d;bra l%d;l%d to b!cc l%d\n",i,p->typf,i,p->typf);
+ switch(p->code){
+ case BEQ: p->code=BNE;break;
+ case BNE: p->code=BEQ;break;
+ case BLT: p->code=BGE;break;
+ case BGE: p->code=BLT;break;
+ case BGT: p->code=BLE;break;
+ case BLE: p->code=BGT;break;
+ }
+ g->normalout->branchout=g->normalout->normalout;
+ g->normalout->start->typf=i;
+ changed=gchanged=1;
+ }
+ }
+ }
+ /* Haben alle Vorgaenger eines Blocks die selbe Anweisung am */
+ /* Blockende und keinen weiteren Nachfolger, dann kann die */
+ /* Anweisung in den Nachfogerblock geschoben werden */
+ i=0;p=0;
+ for(lp=g->in;lp;lp=lp->next){
+ if(lp->graph){
+ IC *np;
+ flowgraph *ng=lp->graph;
+ flowlist *l2;
+ /* doppelte Bloecke loeschen und ueberspringen */
+ for(l2=g->in;l2;l2=l2->next)
+ if(l2!=lp&&l2->graph==ng) break;
+ if(l2){ lp->graph=0;continue;}
+ np=ng->end;
+ if(!np){ i=-1;break;}
+ if(ng->branchout&&(np->code!=BRA||ng->branchout!=g)){i=-1;break;}
+ if(np->code==BRA) np=np->prev;
+ if(!np){ i=-1;break;}
+ if(!p){
+ i=1;
+ p=np;
+ }else{
+ if(p->code==np->code&&p->typf==np->typf&&
+ p->code!=CALL&&p->code!=GETRETURN&&p->code!=PUSH&&(p->code<TEST||p->code>COMPARE)&&
+ !compare_objs(&p->q1,&np->q1,p->typf)&&
+ !compare_objs(&p->q2,&np->q2,p->typf)&&
+ !compare_objs(&p->z,&np->z,p->typf)){
+ i++;
+ }else{
+ i=-1;
+ break;
+ }
+ }
+ }
+ }
+ if(i>1&&g->start){
+ IC *new=new_IC();
+ if(DEBUG&1024){ printf("moving instruction from preceding blocks to successor:\n");pric2(stdout,p);}
+ changed=gchanged=1;
+ memcpy(new,p,ICS);
+ new->use_cnt=new->change_cnt=0;
+ new->use_list=new->change_list=0;
+ if(g->start->code==LABEL){
+ insert_IC_fg(g,g->start,new);
+ }else{
+ insert_IC_fg(g,g->start->prev,new);
+ }
+ for(lp=g->in;lp;lp=lp->next){
+ flowgraph *ng=lp->graph;
+ if(ng){
+ if(!ng->end) ierror(0);
+ if(ng->end->code==BRA){
+ remove_IC_fg(ng,ng->end->prev);
+ }else{
+ remove_IC_fg(ng,ng->end);
+ }
+ }
+ }
+ }
+ /* Haben alle Nachfolger eines Blocks die selbe Anweisung am */
+ /* Blockbeginn und keinen weiteren Vorgaenger, dann kann die */
+ /* Anweisung in den Vorgaengerblock geschoben werden */
+ if(g->branchout&&g->normalout&&g->branchout!=g->normalout&&g->end&&g->end->code!=BRA){
+ flowgraph *a=g->normalout,*b=g->branchout;
+ IC *as=a->start,*bs=b->start,*tp;
+ int destroys;
+ if(as&&as->code==LABEL&&as!=a->end) as=as->next;
+ if(bs&&bs->code==LABEL&&bs!=b->end) bs=bs->next;
+
+ if(as&&bs&&as->code==bs->code&&as->code!=PUSH&&(as->code<TEST||as->code>COMPARE)&&as->typf==bs->typf&&
+ !compare_objs(&as->q1,&bs->q1,as->typf)&&
+ !compare_objs(&as->q2,&bs->q2,as->typf)&&
+ !compare_objs(&as->z,&bs->z,as->typf)){
+ i=0;
+ for(lp=a->in;lp;lp=lp->next)
+ if(lp->graph&&lp->graph!=g&&(lp->graph->branchout==a||!lp->graph->end||lp->graph->end->code!=BRA)) i=1;
+ for(lp=b->in;lp;lp=lp->next)
+ if(lp->graph&&lp->graph!=g&&(lp->graph->branchout==b||!lp->graph->end||lp->graph->end->code!=BRA)) i=1;
+ if(as->code==CALL&&as->next&&(as->next->code==GETRETURN||as->code==NOP)) i=1;
+ if(bs->code==CALL&&bs->next&&(bs->next->code==GETRETURN||bs->code==NOP)) i=1;
+ if(!i){
+ if(!(tp=g->end->prev)) ierror(0);
+ if(tp->code!=TEST&&tp->code!=COMPARE)
+ ierror(0);
+ /* schauen, ob die Anweisung eine evtl. TEST */
+ /* oder COMPARE-Anweisung beeinflusst */
+ destroys=0;
+ if(as->z.flags&DREFOBJ) destroys|=1;
+ if(as->code==CALL) destroys|=2;
+ if(tp->q1.flags&VAR){
+ if(destroys&3){
+ if((tp->q1.v->flags&USEDASADR)||
+ (tp->q1.flags&DREFOBJ)||
+ (tp->q1.v->storage_class==EXTERN)||
+ (tp->q1.v->nesting==0))
+ i=1;
+ if((destroys&2)&&tp->q1.v->storage_class==STATIC)
+ i=1;
+ }
+ if((as->z.flags&VAR)&&as->z.v==tp->q1.v)
+ i=1;
+ }
+ if(tp->q2.flags&VAR){
+ if(destroys&3){
+ if((tp->q2.v->flags&USEDASADR)||
+ (tp->q2.flags&DREFOBJ)||
+ (tp->q2.v->storage_class==EXTERN)||
+ (tp->q2.v->nesting==0))
+ i=1;
+ if((destroys&2)&&tp->q2.v->storage_class==STATIC)
+ i=1;
+ }
+ if((as->z.flags&VAR)&&as->z.v==tp->q2.v)
+ i=1;
+ }
+ if(!i&&!(disable&2)){
+ if(DEBUG&1024){ printf("moving instruction from following blocks to predecessor:\n");pric2(stdout,as);}
+ p=new_IC();
+ memcpy(p,as,ICS);
+ remove_IC_fg(a,as);
+ remove_IC_fg(b,bs);
+ p->use_cnt=p->change_cnt=0;
+ p->use_list=p->change_list=0;
+ insert_IC_fg(g,g->end->prev->prev,p);
+ changed=gchanged=1;
+ }
+ }
+ }
+ }
+ g=g->normalout;
+ }
+ g=fg;
+ while(g){
+ /* Spruenge zu Spruengen umsetzen; einige Zeiger im Flussgraph */
+ /* werden nicht korrekt aktualisiert, aber das sollte egal sein*/
+ p=g->start;
+ for(i=0;i<2;i++){
+ if(i){if(p&&p->code==LABEL) p=p->next; else break;}
+ if(p&&p->code>=BEQ&&p->code<=BRA){
+ lp=g->in;
+ while(lp){
+ if(lp->graph&&lp->graph->branchout==g&&(/*lp->graph->end->code==p->code||*/p->code==BRA)&&lp->graph->end->typf!=p->typf){
+ if(DEBUG&1024){printf("branch bypassed to L%d:\n",p->typf);pric2(stdout,lp->graph->end);}
+ if(lp->graph->end->code<BEQ||lp->graph->end->code>BRA) ierror(0);
+ lp->graph->branchout=g->branchout;
+ lp->graph->end->typf=p->typf;changed=gchanged=1;
+ }
+ lp=lp->next;
+ }
+ }
+ }
+
+
+ g=g->normalout;
+ }
+ if(changed) free_flowgraph(fg);
+ }while(changed);
+ return fg;
+}
+
+void insert_IC_fg(flowgraph *fg,IC *p,IC *new)
+/* fuegt ein IC hinter p ein unter Beibehaltung des Flussgraphen */
+{
+ if(fg->start){
+ if(!p||p==fg->start->prev) fg->start=new;
+ if(p==fg->end) fg->end=new;
+ }else{
+ fg->start=fg->end=new;
+ }
+ insert_IC(p,new);
+}
diff --git a/frontend/vc.c b/frontend/vc.c
new file mode 100644
index 0000000..e94e643
--- /dev/null
+++ b/frontend/vc.c
@@ -0,0 +1,770 @@
+/* Frontend for vbcc */
+/* (c) in 1995-2016 by Volker Barthelmann */
+/* #define AMIGA for Amiga version */
+/* #define ATARI for Atari version */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef AMIGA
+#pragma amiga-align
+#ifdef __amigaos4__
+#include <dos/anchorpath.h>
+#else
+#include <dos/dosasl.h>
+#endif
+#include <dos/dosextens.h>
+#include <dos/dostags.h>
+#include <exec/libraries.h>
+#include <proto/dos.h>
+#pragma default-align
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 20
+#endif
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+
+#if !defined(__amigaos4__) && !defined(__MORPHOS__)
+extern struct DosLibrary *DOSBase;
+#endif
+
+/* Must be 32bit-aligned - I know it will be if compiled with vbcc. */
+struct FileInfoBlock fib;
+#endif
+
+struct NameList{
+ struct NameList *next;
+ char *obj;
+} *first_obj=0,*last_obj=0,*first_scratch=0,*last_scratch=0;
+
+/* Limit fuer Laenge der Namen (wegen Wildcards) */
+#define NAMEBUF 1000 /* MUST BE >= ~TMPNAM_L+7 */
+#define USERLIBS 1000
+
+/* Ab dieser Laenge werden Objektfiles nicht direkt uebergeben, */
+/* sondern aus einem File an den Linker uebergeben */
+#ifdef AMIGA
+int MAXCLEN=500;
+#else
+int MAXCLEN=32000;
+#endif
+
+#define WPO 16384
+#define CROSSMODULE 8192
+#define SCHEDULER 4096
+#define NOTMPFILE 2048
+#define OUTPUTSET 1024
+#define NOSTDLIB 512
+#define VERBOSE 256
+#define VERYVERBOSE 128
+#define KEEPSCRATCH 64
+
+#define PPSRC 1
+#define CCSRC 2
+#define SCSRC 3
+#define ASSRC 4
+#define OBJ 5
+
+char *vbccenv;
+char empty[]="";
+/* Namen der einzelnen Phasen */
+char *ppname=empty,*ccname=empty,*asname=empty,*ldname=empty,*l2name=empty;
+char *rmname=empty,*scname=empty;
+/* dasselbe fuer VERBOSE */
+char *ppv=empty,*ccv=empty,*asv=empty,*ldv=empty,*l2v=empty;
+char *rmv=empty,*scv=empty;
+
+/* Linker-Commandfile */
+char *cf="@%s";
+char *nodb="";
+char *staticflag="";
+char *ul="-l%s";
+
+#if defined(AMIGA)
+const char *config_name="vc.config";
+const char *search_dirs[]={"","ENV:","VBCC:config/","VBCC:"};
+#elif defined(_WIN32) || defined(MSDOS)
+const char *config_name="vc.cfg";
+const char *search_dirs[]={"","%VCCFG%\\"};
+#elif defined(ATARI)
+const char *config_name="vc.cfg";
+const char *search_dirs[]={"","C:\\"};
+#else
+const char *config_name="vc.config";
+const char *search_dirs[]={"","~/","/etc/"};
+#endif
+
+/* String fuer die Default libraries */
+char userlibs[USERLIBS];
+char *nomem="Not enough memory!\n";
+
+char *destname="a.out";
+char namebuf[NAMEBUF+1],namebuf2[NAMEBUF+1];
+char *oldfile;
+
+char *cmfiles,*cmoutput,*cmname;
+#if defined(AMIGA)||defined(_WIN32)||defined(MSDOS)
+#undef USECMDFILE
+#define USECMDFILE 1
+#endif
+#ifdef USECMDFILE
+FILE *cmdfile;
+#endif
+int final;
+int compressor;
+
+char *config;
+char **confp;
+
+char *command,*options,*linkcmd,*objects,*libs,*ppopts;
+#ifdef AMIGA
+struct AnchorPath *ap;
+#endif
+
+int linklen=10,flags=0;
+
+#if defined(MSDOS)||defined(ATARI)
+char *tmpnam(char *p)
+{
+ static int c=1675;
+ static char tmp[NAMEBUF];
+ char *env;
+
+ env=getenv("TEMP");
+ if(!env) env=".";
+ if(!p) p=tmp;
+ snprintf(p,NAMEBUF,"%s\\vbcc%04x",env,++c);
+ return p;
+}
+#endif
+
+static void free_namelist(struct NameList *p)
+{
+ struct NameList *m;
+ while(p){
+ m=p->next;
+ if(flags&VERYVERBOSE){
+ puts("free p->obj");
+ if(!p->obj) puts("IS ZERO!!"); else puts(p->obj);
+ }
+ free((void *)p->obj);
+ if(flags&VERYVERBOSE){puts("free p"); if(!p) puts("IS ZERO!!");}
+ free((void *)p);
+ p=m;
+ }
+}
+
+static void raus(int rc)
+{
+ if(confp) free(confp);
+ if(config) free(config);
+ if(objects) free(objects);
+ if(libs) free(libs);
+ if(command) free(command);
+ if(ppopts) free(ppopts);
+ if(options) free(options);
+ if(linkcmd) free(linkcmd);
+#ifdef AMIGA
+ if(ap)
+#ifdef __amigaos4__
+ FreeDosObject(DOS_ANCHORPATH,ap);
+#else
+ free(ap);
+#endif
+#endif
+ free_namelist(first_obj);
+ free_namelist(first_scratch);
+ exit(rc);
+}
+
+#ifdef NO_LONGER_NEEDED
+/* Launch command from "$VBCC\bin\", when no absolute path was specified. */
+static int runcmd(char *cmd)
+{
+ char *p;
+
+ for(p=cmd;*p!=0&&*p>' ';p++){
+ if(*p==':') /* absolute path */
+ goto do_cmd;
+ }
+ if(vbccenv){
+ /* prepend "$VBCC\bin\" in front of our command */
+ int len=strlen(vbccenv);
+ if(vbccenv[len-1]=='\\') len--;
+ memmove(cmd+len+5,cmd,strlen(cmd)+1);
+ memcpy(cmd,vbccenv,len);
+ memcpy(cmd+len,"\\bin\\",5);
+ }
+do_cmd:
+ return system(cmd);
+}
+#else
+#define runcmd(c) system(c)
+#endif
+
+static void del_scratch(struct NameList *p)
+{
+ while(p){
+ sprintf(command,rmname,p->obj);
+ if(flags&VERBOSE) printf("%s\n",command);
+ if(runcmd(command)){printf("%s failed\n",command);raus(EXIT_FAILURE);}
+ p=p->next;
+ }
+}
+
+static void add_name(char *obj,struct NameList **first,struct NameList **last)
+{
+ struct NameList *new;
+ if(flags&VERYVERBOSE) printf("add_name: %s\n",obj);
+ if(!(new=malloc(sizeof(struct NameList))))
+ {printf(nomem);raus(EXIT_FAILURE);}
+ if(!(new->obj=malloc(strlen(obj)+1)))
+ {free((void *)new);printf(nomem);raus(EXIT_FAILURE);}
+ if(first==&first_obj) linklen+=strlen(obj)+1;
+ strcpy(new->obj,obj);
+ new->next=0;
+ if(!*first){
+ *first=*last=new;
+ }else{
+ (*last)->next=new;*last=new;
+ }
+}
+
+static int read_config(const char *cfg_name)
+{
+ int i,count; long size;
+ char *p,*name;
+ FILE *file=0;
+ for(i=0;i<sizeof(search_dirs)/sizeof(search_dirs[0]);i++){
+ name=malloc(strlen(search_dirs[i])+strlen(cfg_name)+1);
+ if(!name) {printf(nomem);raus(EXIT_FAILURE);}
+ strcpy(name,search_dirs[i]);
+ strcat(name,cfg_name);
+ file=fopen(name,"r");
+ free(name);
+ if(file) break;
+ }
+ if(!file){
+ if(p=vbccenv){
+ name=malloc(strlen(p)+strlen(cfg_name)+20);
+ if(!name){printf(nomem);raus(EXIT_FAILURE);}
+ strcpy(name,p);
+#if defined(_WIN32)||defined(MSDOS)||defined(ATARI)
+ strcat(name,"\\config\\");
+ strcat(name,cfg_name);
+#elif defined(AMIGA)
+ AddPart(name,"config",strlen(p)+strlen(cfg_name)+20);
+ AddPart(name,(STRPTR)cfg_name,strlen(p)+strlen(cfg_name)+20);
+#else
+ strcat(name,"/config/");
+ strcat(name,cfg_name);
+#endif
+ file=fopen(name,"r");
+ free(name);
+ }
+ }
+ if(!file) {puts("No config file!");raus(EXIT_FAILURE);}
+ if(fseek(file,0,SEEK_END)) return 0;
+ size=ftell(file);
+ if(fseek(file,0,SEEK_SET)) return 0;
+ config=malloc(size+1);
+ if(!config){printf(nomem);raus(EXIT_FAILURE);}
+ size=fread(config,1,size,file);
+ fclose(file);
+ count=0;p=config;
+ while(p<config+size&&*p){
+ count++;
+ while(p<config+size&&*p!='\n') p++;
+ if(*p=='\n') *p++=0;
+ }
+ config[size]=0;
+ confp=malloc(count*sizeof(char *));
+ for(p=config,i=0;i<count;i++){
+ confp[i]=p;
+ while(*p) p++;
+ p++;
+ }
+ return count;
+}
+
+static int typ(char *fp)
+{
+ char *p=strrchr(fp,'.');
+ if(p&&(!strcmp(p,".c")||!strcmp(p,".C"))) return ppname==empty?CCSRC:PPSRC;
+ if(p&&!strcmp(p,".i")) return CCSRC;
+ if(p&&(!strcmp(p,".s")||!strcmp(p,".S")||!strcmp(p,".asm"))) return ASSRC;
+ if(p&&!strcmp(p,".scs")) return SCSRC;
+ if(!p||!strcmp(p,".o")||!strcmp(p,".obj")){
+ FILE *f;
+ if(f=fopen(fp,"r")){
+ if(fgetc(f)==0&&fgetc(f)=='V'&&fgetc(f)=='B'&&fgetc(f)=='C'&&fgetc(f)=='C'){
+ fclose(f);
+ return CCSRC;
+ }
+ fclose(f);
+ }
+ return OBJ;
+ }
+ return OBJ;
+}
+
+static char *add_suffix(char *s,char *suffix)
+{
+ static char str[NAMEBUF+3],*p;
+ if(strlen(s)+strlen(suffix)>NAMEBUF){printf("string too long\n");raus(EXIT_FAILURE);}
+ if(s!=str) strcpy(str,s);
+ p=strrchr(str,'.');
+ if(!p) p=str+strlen(s);
+ if(!p||p==str||(p==str+1&&str[0]=='\"')) p=str+strlen(s);
+ strcpy(p,suffix);
+ strcat(p,"\"");
+ return str;
+}
+
+#if defined(_WIN32)||defined(MSDOS)||defined(ATARI)||defined(AMIGA)
+static char *convert_path(char *path)
+{
+ char c,*p,*newpath;
+ newpath=p=malloc(strlen(path)+1);
+ while(c=*path++){
+#ifdef AMIGA
+ if(c=='.'){
+ if(*path=='/') continue;
+ if(*path=='.'&&*(path+1)=='/'){
+ path++;
+ continue;
+ }
+ }
+#else
+ if(c=='/') c='\\';
+#endif
+ *p++=c;
+ }
+ *p=0;
+ return newpath;
+}
+#else
+#define convert_path(p) (p)
+#endif
+
+int main(int argc,char *argv[])
+{
+ int tfl,i,len=10,pm,count,db=0,staticmode=0,deps=0;
+ char *parm;
+ long opt=1;
+ int rc=EXIT_SUCCESS;
+
+ for(i=1;i<argc;i++){
+ if(argv[i][0]=='+'){
+ config_name=argv[i]+1;
+ argv[i][0]=0;
+ break;
+ }
+ }
+ vbccenv=getenv("VBCC");
+ count=read_config(config_name);
+#ifdef AMIGA
+#if !defined(__amigaos4__) && !defined(__MORPHOS__)
+ if(pm=DOSBase->dl_lib.lib_Version>=36)
+#else
+ if(pm=1)
+#endif
+ {
+#ifdef __amigaos4__
+ if(!(ap=(struct AnchorPath *)AllocDosObjectTags(DOS_ANCHORPATH,
+ ADO_Strlen,NAMEBUF,
+ TAG_DONE)))
+ pm=0;
+#else
+ if(ap=(struct AnchorPath *)calloc(sizeof(struct AnchorPath)+NAMEBUF,1))
+ {ap->ap_Strlen=NAMEBUF;ap->ap_BreakBits=0;} else pm=0;
+#endif
+ }
+#endif
+ for(i=1;i<argc+count;i++){
+ if(i<argc) parm=argv[i]; else parm=confp[i-argc];
+ if(!strncmp(parm,"-ul=",4)){ul=parm+4;*parm=0;}
+ }
+ for(i=1;i<argc+count;i++){
+ if(i<argc) parm=argv[i]; else parm=confp[i-argc];
+/* printf("Parameter %d=%s\n",i,parm);*/
+ if(!strncmp(parm,"-rmcfg-",7)){
+ int j,len=strlen(parm);
+ for(j=0;j<count;j++)
+ if(!strncmp(confp[j],parm+6,len-6)) confp[j][0]=0;
+ parm[0]=0;
+ continue;
+ }
+ if(!strncmp(parm,"-ldnodb=",8)){nodb=parm+8;*parm=0;}
+ if(!strncmp(parm,"-ldstatic=",10)){staticflag=parm+10;*parm=0;}
+ if(!strcmp(parm,"-g")) db=1;
+ if(!strcmp(parm,"-deps")) deps=1;
+ if(!strcmp(parm,"-static")){staticmode=1;*parm=0;}
+ if(!strncmp(parm,"-ml=",4)){MAXCLEN=atoi(parm+4);*parm=0;}
+ if(!strncmp(parm,"-pp=",4)){ppname=parm+4;*parm=0;}
+ if(!strncmp(parm,"-cc=",4)){ccname=parm+4;*parm=0;}
+ if(!strncmp(parm,"-as=",4)){asname=parm+4;*parm=0;}
+ if(!strncmp(parm,"-ld=",4)){ldname=parm+4;*parm=0;}
+ if(!strncmp(parm,"-l2=",4)){l2name=parm+4;*parm=0;}
+ if(!strncmp(parm,"-rm=",4)){rmname=parm+4;*parm=0;}
+ if(!strncmp(parm,"-ppv=",5)){ppv=parm+5;*parm=0;}
+ if(!strncmp(parm,"-ccv=",5)){ccv=parm+5;*parm=0;}
+ if(!strncmp(parm,"-asv=",5)){asv=parm+5;*parm=0;}
+ if(!strncmp(parm,"-ldv=",5)){ldv=parm+5;*parm=0;}
+ if(!strncmp(parm,"-l2v=",5)){l2v=parm+5;*parm=0;}
+ if(!strncmp(parm,"-rmv=",5)){rmv=parm+5;*parm=0;}
+ if(!strncmp(parm,"-cf=",4)){cf=parm+4;*parm=0;}
+ if(!strncmp(parm,"-isc=",5)){scname=parm+5;*parm=0;}
+ if(!strncmp(parm,"-iscv=",6)){scv=parm+6;*parm=0;}
+ /* TODO: we re-use scheduler for compressor */
+ if(!strncmp(parm,"-cpr=",5)){scname=parm+5;*parm=0;compressor=1;}
+ if(!strncmp(parm,"-cprv=",6)){scv=parm+6;*parm=0;compressor=1;}
+ if(!strcmp(parm,"-schedule")) {flags|=SCHEDULER;*parm=0;}
+ if(!strcmp(parm,"-notmpfile")) {flags|=NOTMPFILE;*parm=0;}
+ /*if(!strcmp(parm,"-E")) {flags|=CCSRC;*parm=0;}*/
+ if(!strcmp(parm,"-S")) {flags|=ASSRC;*parm=0;}
+ if(!strcmp(parm,"-SCS")) {flags|=SCSRC;*parm=0;}
+ if(!strcmp(parm,"-c")) {flags|=OBJ;*parm=0;}
+ if(!strcmp(parm,"-v")) {flags|=VERBOSE;*parm=0;}
+ if(!strcmp(parm,"-h")) {flags|=VERBOSE;*parm=0;}
+ if(!strcmp(parm,"-k")) {flags|=KEEPSCRATCH;*parm=0;}
+ if(!strcmp(parm,"-vv")) {flags|=VERBOSE|VERYVERBOSE;*parm=0;}
+ if(!strcmp(parm,"-nostdlib")) {flags|=NOSTDLIB;*parm=0;}
+ if(parm[0] == ';') {*parm=0;}
+ if(!strncmp(parm,"-O",2)){
+ static int had_opt;
+ if(had_opt){
+ puts("Optimization flags specified multiple times");
+ exit(EXIT_FAILURE);
+ }
+ had_opt=1;
+ if(parm[2]=='0') opt=0;
+ else if(parm[2]=='1'||parm[2]==0) opt=991;
+ else if(parm[2]=='2') {opt=1023;flags|=SCHEDULER;}
+ else if(parm[2]=='3') {opt=~0;flags|=(SCHEDULER|CROSSMODULE);}
+ else if(parm[2]>='4'&&parm[2]<='9') {opt=~0;flags|=(SCHEDULER|WPO);}
+
+ else if(parm[2]=='=') opt=atoi(&parm[3]);
+ *parm=0;
+ }
+ if(!strcmp(parm,"-o")&&i<argc-1) {
+ *argv[i++]=0;destname=convert_path(argv[i]);
+ flags|=OUTPUTSET;argv[i]="";continue;
+ }
+ if(!strncmp(parm,"-o=",3)){
+ destname=convert_path(parm+3);
+ flags|=OUTPUTSET;*parm=0;continue;
+ }
+ if(parm[0]=='-'&&parm[1]=='l'){
+ size_t l=strlen(userlibs);
+ if((l+strlen(parm)-2+strlen(ul)+1)>=USERLIBS){puts("Userlibs too long");exit(EXIT_FAILURE);}
+ userlibs[l]=' ';
+ sprintf(userlibs+l+1,ul,parm+2);
+ *parm=0;continue;
+ }
+ if(parm[0]=='-'&&parm[1]=='L'){
+ size_t l=strlen(userlibs);
+ if((l+strlen(parm)+1)>=USERLIBS){puts("Userlibs too long");exit(EXIT_FAILURE);}
+ userlibs[l]=' ';
+ sprintf(userlibs+l+1,"%s",parm);
+ *parm=0;continue;
+ }
+ len+=strlen(parm)+10;
+#ifdef ATARI
+ if(vbccenv)
+ len+=strlen(vbccenv)+5;
+#endif
+ }
+ if(!db&&*nodb){
+ if(strlen(userlibs)+2+strlen(nodb)>=USERLIBS){
+ puts("Userlibs too long");exit(EXIT_FAILURE);
+ }
+ strcat(userlibs," ");
+ strcat(userlibs,nodb);
+ }
+ if(staticmode&&*staticflag){
+ size_t ulen=strlen(userlibs);
+ size_t slen=strlen(staticflag);
+ if(ulen+2+slen>=USERLIBS){
+ puts("Userlibs too long");exit(EXIT_FAILURE);
+ }
+ memmove(userlibs+slen+1,userlibs,ulen+1);
+ memcpy(userlibs,staticflag,slen);
+ userlibs[slen]=' ';
+ }
+ if(flags&VERBOSE){
+ printf("vc frontend for vbcc (c) in 1995-2020 by Volker Barthelmann\n");
+#ifdef SPECIAL_COPYRIGHT
+ printf("%s\n",SPECIAL_COPYRIGHT);
+#endif
+ }
+ if(!(flags&7)) flags|=OBJ+1;
+ tfl=flags&7;
+ if((flags&WPO)&&tfl!=OBJ){
+ flags&=~WPO;
+ flags|=CROSSMODULE;
+ }
+ if(scname==empty) flags&=~SCHEDULER;
+ if(flags&VERYVERBOSE){
+ ppname=ppv;ccname=ccv;asname=asv;ldname=ldv;
+ rmname=rmv;l2name=l2v;scname=scv;
+ }
+ if(flags&NOSTDLIB){ldname=l2name;}
+ /* Nummer sicher... */
+ len+=strlen(ppname)+strlen(ccname)+strlen(asname)+
+ strlen(rmname)+strlen(scname)+strlen(userlibs)+NAMEBUF+100;
+ if(!(command=malloc(len))){printf(nomem);raus(EXIT_FAILURE);}
+ if(!(oldfile=malloc(len))){printf(nomem);raus(EXIT_FAILURE);}
+ if(!(options=malloc(len))){printf(nomem);raus(EXIT_FAILURE);}
+ if(!(ppopts=malloc(len))){printf(nomem);raus(EXIT_FAILURE);}
+ *options=0;*ppopts=0;
+ for(i=1;i<argc+count;i++){
+ if(i<argc) parm=argv[i]; else parm=confp[i-argc];
+ if(*parm=='-'){
+ if(ppname==empty||(parm[1]!='D'&&parm[1]!='I'&&parm[1]!='+')){
+ strcat(options,parm);strcat(options," ");
+ }else{
+ strcat(ppopts,parm);strcat(ppopts," ");
+ }
+ }
+ }
+ if(flags&VERYVERBOSE) printf("flags=%d opt=%ld len=%d\n",flags,opt,len);
+ namebuf[0]='\"'; namebuf2[0]='\"';
+ for(i=1;i<argc+count+((flags&CROSSMODULE)!=0);i++){
+ int t,j;char *file;
+#ifdef AMIGA
+ BPTR lock;
+#endif
+ if(i<argc)
+ parm=argv[i];
+ else if(i<argc+count)
+ parm=confp[i-argc];
+ else
+ parm=cmfiles;
+ if(!parm||(*parm=='-'&&parm!=cmfiles)||!*parm) continue;
+ if(flags&VERYVERBOSE) printf("Argument %d:%s\n",i,parm);
+#ifdef AMIGA
+ if(pm&&parm!=cmfiles)
+ if(MatchFirst((STRPTR)convert_path(parm),ap)){
+ MatchEnd(ap);
+ printf("No match for %s\n",parm);
+ rc=RETURN_WARN;
+ continue;
+ }
+#endif
+ do{
+ if(parm==cmfiles){
+ file=parm;
+ t=CCSRC;
+ }else{
+#ifdef AMIGA
+#ifdef __amigaos4__
+ if(pm) file=(char *)ap->ap_Buffer; else file=parm;
+#else
+ if(pm) file=(char *)&ap->ap_Buf[0]; else file=parm;
+#endif
+#else
+ file=convert_path(parm);
+#endif
+ t=typ(file);
+ strcpy(namebuf+1,file);
+ strcat(namebuf,"\"");
+ file=namebuf;
+ }
+ if(flags&VERYVERBOSE) printf("File %s=%d\n",file,t);
+ if(!cmname&&(flags&CROSSMODULE)&&t<=CCSRC){
+ cmname=malloc(NAMEBUF);
+ if(!cmname){printf(nomem);exit(EXIT_FAILURE);}
+ if(tfl==OBJ){
+ strcpy(cmname,file);
+ }else{
+ cmname[0]='\"';
+ tmpnam(cmname+1);
+ strcat(cmname,".");
+ }
+ }
+ for(j=t;j<tfl;j++){
+ if(j==OBJ){
+ if(j==t) add_name(file,&first_obj,&last_obj);
+ continue;
+ }
+ strcpy(oldfile,file);
+ if(file==cmfiles){
+ file=cmoutput;
+ }else{
+ if(j==t&&j!=tfl-1&&!(flags&(NOTMPFILE|KEEPSCRATCH))){
+ file=namebuf2;
+ tmpnam(file+1);
+ strcat(file,".");
+ }
+ if(j==tfl-1||(flags&WPO)) file=namebuf;
+ }
+ if(j==PPSRC){
+ file=add_suffix(file,".i");
+ if(tfl==CCSRC&&(flags&OUTPUTSET)) file=destname;
+ sprintf(command,ppname,ppopts,oldfile,file);
+ if((tfl)!=CCSRC) add_name(file,&first_scratch,&last_scratch);
+ }
+ /* MUST come before CCSRC-handling! */
+ if(j==SCSRC){
+ /*if(final) file=cmname;*/
+ file=add_suffix(file,".asm");
+ if(tfl==ASSRC&&(flags&OUTPUTSET)) file=destname;
+ sprintf(command,scname,oldfile,file);
+ if(tfl!=ASSRC) add_name(file,&first_scratch,&last_scratch);
+ }
+ if(j==CCSRC){
+ if(file!=cmoutput){
+ if(flags&WPO){
+ if(flags&OUTPUTSET)
+ file=destname;
+ else
+ file=add_suffix(file,".o");
+ }else if(flags&SCHEDULER){
+ file=add_suffix(file,".scs");
+ }else{
+ if(++j==tfl-1) file=namebuf;
+ file=add_suffix(file,".asm");
+ }
+ if(tfl==j+1&&(flags&OUTPUTSET)) file=destname;
+ if(flags&CROSSMODULE){
+#ifdef USECMDFILE
+ if(!cmdfile){
+ char *s;
+ s=tmpnam(0);
+ cmfiles=malloc(strlen(s)+16);
+ if(!cmfiles){printf(nomem);exit(EXIT_FAILURE);}
+ sprintf(cmfiles,"-cmd= \"%s\"",s);
+ cmdfile=fopen(s,"w");
+ if(!cmdfile){printf("Could not open <%s>!\n",s);exit(EXIT_FAILURE);}
+ add_name(s,&first_scratch,&last_scratch);
+ }
+ fputs(oldfile,cmdfile);
+ fputs("\n",cmdfile);
+#else
+ if(!cmfiles){
+ cmfiles=malloc(strlen(oldfile)+3);
+ if(!cmfiles){printf(nomem);exit(EXIT_FAILURE);}
+ strcpy(cmfiles,oldfile);
+ }else{
+ cmfiles=realloc(cmfiles,strlen(cmfiles)+strlen(oldfile)+3);
+ if(!cmfiles){printf(nomem);exit(EXIT_FAILURE);}
+ strcat(cmfiles," ");strcat(cmfiles,oldfile);
+ }
+#endif
+ if(!cmoutput){
+ cmoutput=malloc(strlen(file)+1);
+ if(!cmoutput){printf(nomem);exit(EXIT_FAILURE);}
+ strcpy(cmoutput,file);
+ }
+ break;
+ }
+ }
+ if(flags&CROSSMODULE){
+#ifdef USECMDFILE
+ fclose(cmdfile);
+ cmdfile=0;
+#endif
+ final=1;
+ }
+ if((flags&(CROSSMODULE|SCHEDULER))==CROSSMODULE) j++;
+ sprintf(command,ccname,oldfile,file,options,opt);
+ if(flags&WPO){
+ strcat(command," -wpo");
+ j=OBJ;
+ }else{
+ if(tfl!=j+1) add_name(file,&first_scratch,&last_scratch);
+ }
+ if(deps&&tfl==OBJ&&(flags&OUTPUTSET)){
+ strcat(command," -depobj=");
+ strcat(command,destname);
+ }
+ }
+ if(j==ASSRC){
+ if(final) file=cmname;
+ file=add_suffix(file,".o");
+ if(tfl==OBJ&&(flags&OUTPUTSET)) file=destname;
+ sprintf(command,asname,oldfile,file);
+ add_name(file,&first_obj,&last_obj);
+ if((tfl)!=OBJ) add_name(file,&first_scratch,&last_scratch);
+ }
+ if(flags&VERBOSE) printf("%s\n",command);
+#ifdef AMIGA
+#if !defined(__amigaos4__) && !defined(__MORPHOS__)
+ if(DOSBase->dl_lib.lib_Version>=36){
+#else
+ if(1){
+#endif
+ if(SystemTags(command,NP_Priority,-2,TAG_DONE)){
+ printf("%s failed\n",command);
+ if(pm) MatchEnd(ap);
+ raus(EXIT_FAILURE);
+ }
+ }else
+#endif
+ if(runcmd(command)){printf("%s failed\n",command);raus(EXIT_FAILURE);}
+ }
+#ifdef AMIGA
+ }while(pm&&!MatchNext(ap));
+ if(pm) MatchEnd(ap);
+#else
+ }while(0);
+#endif
+ }
+ if((tfl)>OBJ){
+ /* Zu Executable linken */
+ struct NameList *p;
+ FILE *objfile=0;
+ char *tfname;
+ objects=malloc(linklen);
+ if(!objects){printf(nomem);raus(EXIT_FAILURE);}
+ linklen+=strlen(ldname)+strlen(destname)+strlen(userlibs)+10;
+#ifdef ATARI
+ if(vbccenv) linklen+=strlen(vbccenv)+5;
+#endif
+ if(flags&VERYVERBOSE) printf("linklen=%d\n",linklen);
+ if(!(linkcmd=malloc(linklen))){printf(nomem);raus(EXIT_FAILURE);}
+ p=first_obj;
+ if(linklen>=MAXCLEN){
+ tfname=tmpnam(0);
+ sprintf(objects,cf,tfname);
+ if(!(objfile=fopen(tfname,"w"))){
+ printf("Could not open <%s>!\n",tfname);
+ raus(EXIT_FAILURE);
+ }
+ }else *objects=0;
+ while(p){
+ if(p->obj){
+ if(linklen>=MAXCLEN){
+ fputs(p->obj,objfile);
+ fputs("\n",objfile);
+ }else{
+ strcat(objects,p->obj);strcat(objects," ");
+ }
+ }
+ p=p->next;
+ }
+ if(objfile) fclose(objfile);
+ if(*objects){
+ sprintf(linkcmd,ldname,objects,userlibs,destname);
+ if(flags&VERBOSE) printf("%s\n",linkcmd);
+ /* hier wird objfile bei Fehler nicht geloescht */
+ if(runcmd(linkcmd)){printf("%s failed\n",linkcmd);raus(EXIT_FAILURE);}
+#ifdef AMIGA
+ if(flags&VERBOSE){
+ BPTR l;
+ if(l=Lock((STRPTR)destname,-2)){
+ if(Examine(l,&fib)) printf("Size of executable: %lu bytes\n",(unsigned long)fib.fib_Size);
+ UnLock(l);
+ }
+ }
+#endif
+ }else puts("No objects to link");
+ if(objfile) remove(tfname);
+ }
+ if(!(flags&KEEPSCRATCH)) del_scratch(first_scratch);
+ raus(rc);
+}
diff --git a/ic.c b/ic.c
new file mode 100644
index 0000000..4e76920
--- /dev/null
+++ b/ic.c
@@ -0,0 +1,2802 @@
+/* $VER: vbcc (ic.c) $Revision: 1.65 $ */
+
+#include "vbc.h"
+#include "opt.h"
+
+#define RNOSAVE 32 /* register does not have to be saved across call */
+#define RHALF 64 /* half of a register pair was already allocated */
+
+static char FILE_[]=__FILE__;
+
+static IC *first_pushed;
+static unsigned int opushed;
+static int volatile_convert;
+
+int do_arith(np,IC *,np,obj *);
+static obj *postop_obj;
+static int postop_type;
+np gen_libcall(char *fname,np arg1,type *t1,np arg2,type *t2);
+
+static void handle_reglist(regargs_list *,obj *);
+
+static void fix_pushic(IC **pushic,IC *new)
+{
+ IC *p=last_ic;
+ while(p&&p->code==FREEREG) p=p->prev;
+ if(new==*pushic&&new!=p){
+ if(DEBUG&1){
+ printf("pushic converted to:\n");
+ pric2(stdout,p);
+ }
+ *pushic=p;
+ }
+}
+
+#if HAVE_LIBCALLS
+/* avoid calling use_libcall with illegal operands */
+static char *use_libcall_wrap(int c,int t,int t2)
+{
+ if(optflags&2)
+ return 0;
+
+ if(c==PMULT) c=MULT;
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=KOMPLEMENT)||c==COMPARE||c==CONVERT||c==MINUS||c==TEST)
+ return use_libcall(c,t,t2);
+ return 0;
+}
+#endif
+
+void gen_test(obj *o,int t,int branch,int label)
+/* Generiert ein test o, branch label und passt auf, dass */
+/* kein TEST const generiert wird. */
+{
+ IC *new;
+ if(o->flags&KONST){
+ eval_const(&o->val,t);
+ if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
+ if(branch==BEQ) branch=BRA; else branch=0;
+ }else{
+ if(branch==BNE) branch=BRA; else branch=0;
+ }
+ }else{
+#if HAVE_LIBCALLS
+ static node n={TEST},nn={REINTERPRET};
+ static type nt,it={INT};
+ char *libname;
+ n.left=&nn;
+ n.ntyp=⁢
+ nn.ntyp=&nt;
+ nt.flags=t;
+ n.o=nn.o=*o;
+ if(libname=use_libcall_wrap(TEST,t,0)){
+ new=new_IC();
+ new->code=TEST;
+ new->q2.flags=new->z.flags=0;
+ new->typf=INT;
+ new->q1=gen_libcall(libname,&nn,&nt,0,0)->o;
+ add_IC(new);
+ }else{
+#endif
+ new=new_IC();
+ new->code=TEST;
+ new->q2.flags=new->z.flags=0;
+ new->typf=t;
+ new->q1=*o;
+ add_IC(new);
+#if HAVE_LIBCALLS
+ }
+#endif
+ }
+ if(branch){
+ new=new_IC();
+ new->code=branch;
+ new->typf=label;
+ add_IC(new);
+ }
+}
+
+/* remove a freereg if a scratch register is needed more than once */
+static void keep_reg(int r)
+{
+ IC *n;
+ if(nocode) return;
+ n=last_ic;
+ while(n){
+ if(n->code==CALL&®scratch[r]){
+ IC *ret;
+ regs[r]=1;
+ savescratch(MOVEFROMREG,n->prev,0,&n->q1);
+ ret=n->next;
+ while(ret->code==ALLOCREG||ret->code==FREEREG)
+ ret=ret->next;
+ if(ret->code==GETRETURN){
+ if((ret->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ret->z.reg==r)
+ ret->z.flags&=~REG;
+ }else
+ ret=ret->prev;
+ savescratch(MOVETOREG,ret,0,&n->q1);
+ }
+ if(n->code==FREEREG&&n->q1.reg==r){
+ remove_IC(n);
+ if(!nocode)
+ regs[r]=1;
+ break;
+ }
+ n=n->prev;
+ }
+}
+
+/* Generate code to insert a bitfield */
+void insert_bitfield(obj *dest,obj *src,obj *val,int bfs,int bfo,int t,int isclear)
+{
+ /*FIXME: shortcut beachten? */
+ IC *new;
+ obj tmp1,tmp2,tmp3;
+ int vmerk;
+ bfo=bflayout(bfo,bfs,t);
+ if((dest->flags®)&&!regs[dest->reg])
+ keep_reg(dest->reg);
+ new=new_IC();
+ new->code=AND;
+ new->typf=t;
+ new->q1=*src;
+ new->q1.flags&=~SCRATCH;
+ new->q2.flags=KONST;
+ gval.vmax=zmsub(zmlshift(l2zm(1L),l2zm((int)bfs)),l2zm(1L));
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q2.val,t);
+ get_scratch(&new->z,t,0,0);
+ tmp1=new->z;
+ if((new->q1.flags&(KONST|DREFOBJ))==KONST){
+ calc(AND,new->typf,&new->q1.val,&new->q2.val,&new->q1.val,0);
+ new->code=ASSIGN;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[new->typf&NQ];
+ }
+ *val=tmp1;
+ vmerk=val->flags;
+ tmp1.flags&=~SCRATCH;
+ add_IC(new);
+ if(bfo!=0){
+ new=new_IC();
+ new->code=LSHIFT;
+ new->typf=t;
+ new->typf2=INT;
+ new->q1=tmp1;
+ new->q2.flags=KONST;
+ new->q2.val.vint=zm2zi(l2zm((long)bfo));
+ get_scratch(&new->z,t,0,0);
+ tmp3=new->z;
+ add_IC(new);
+ }else{
+ tmp3=tmp1;
+ }
+ if(!isclear){
+ new=new_IC();
+ new->code=AND;
+ new->typf=t;
+ new->q1=*dest;
+ new->q1.flags&=~SCRATCH;
+ new->q2.flags=KONST;
+ gval.vmax=zmkompl(zmlshift(zmsub(zmlshift(l2zm(1L),l2zm((int)bfs)),l2zm(1L)),l2zm((long)bfo)));
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q2.val,t);
+ get_scratch(&new->z,t,0,0);
+ tmp2=new->z;
+ add_IC(new);
+ }
+ new=new_IC();
+ new->code=OR;
+ new->typf=t;
+ if(isclear)
+ new->q1=*dest;
+ else
+ new->q1=tmp2;
+ new->q2=tmp3;
+ new->z=*dest;
+ add_IC(new);
+ if(dest->flags&(REG|SCRATCH)) free_reg(dest->reg);
+ val->flags=vmerk;
+}
+
+void inline_memcpy(np z,np q,zmax size)
+/* fuegt ein ASSIGN-IC ein, das memcpy(z,q,size) entspricht */
+{
+ IC *new=new_IC();
+ if(!ISPOINTER(z->ntyp->flags)) {error(39);return;}
+ if(!ISPOINTER(q->ntyp->flags)) {error(39);return;}
+
+ if(z->flags==ADDRESS||z->flags==ADDRESSA||z->flags==ADDRESSS){
+ gen_IC(z,0,0);
+ new->z=z->left->o;
+ if(z->flags!=ADDRESSS&&z->left->flags==IDENTIFIER&&is_vlength(z->left->ntyp)){
+ /* variable length array */
+ new->z.flags|=DREFOBJ;
+ new->z.dtyp=POINTER_TYPE(z->ntyp->next);
+ }
+ }else{
+ gen_IC(z,0,0);
+ if(z->o.flags&DREFOBJ){
+ IC *n2=new_IC();
+ n2->code=ASSIGN;
+ n2->typf=q->ntyp->flags;
+ n2->q1=z->o;
+ get_scratch(&n2->z,z->ntyp->flags,z->ntyp->next->flags,z->ntyp);
+ n2->q2.flags=0;
+ n2->q2.val.vmax=sizetab[POINTER_TYPE(z->ntyp->next)];
+ new->z=n2->z;
+ add_IC(n2);
+ }else{
+ new->z=z->o;
+ }
+ if(new->z.flags&VARADR){
+ new->z.flags&=~VARADR;
+ }else{
+ new->z.flags|=DREFOBJ;
+ new->z.dtyp=POINTER_TYPE(z->ntyp->next);
+ }
+ }
+ if(z->ntyp->next->flags&VOLATILE){
+ if(new->z.flags&DREFOBJ)
+ new->z.dtyp|=PVOLATILE;
+ }
+ if(q->flags==ADDRESS||q->flags==ADDRESSA||q->flags==ADDRESSS){
+ gen_IC(q,0,0);
+ new->q1=q->left->o;
+ if(q->flags!=ADDRESSS&&q->left->flags==IDENTIFIER&&is_vlength(q->left->ntyp)){
+ /* variable length array */
+ new->q1.flags|=DREFOBJ;
+ new->q1.dtyp=POINTER_TYPE(q->ntyp->next);
+ }
+ }else{
+ gen_IC(q,0,0);
+ if(q->o.flags&DREFOBJ){
+ IC *n2=new_IC();
+ n2->code=ASSIGN;
+ n2->typf=q->ntyp->flags;
+ n2->q1=q->o;
+ get_scratch(&n2->z,q->ntyp->flags,q->ntyp->next->flags,q->ntyp);
+ n2->q2.flags=0;
+ n2->q2.val.vmax=sizetab[POINTER_TYPE(q->ntyp->next)];
+
+ new->q1=n2->z;
+ add_IC(n2);
+ }else{
+ new->q1=q->o;
+ }
+ if(new->q1.flags&VARADR){
+ new->q1.flags&=~VARADR;
+ }else{
+ new->q1.flags|=DREFOBJ;
+ new->q1.dtyp=POINTER_TYPE(q->ntyp->next);
+ }
+ }
+ if(q->ntyp->next->flags&VOLATILE){
+ if(new->q1.flags&DREFOBJ)
+ new->q1.dtyp|=PVOLATILE;
+ }
+ new->code=ASSIGN;
+ new->typf=UNSIGNED|CHAR;
+ new->q2.flags=0;
+ new->q2.val.vmax=size;
+
+ if(!zmeqto(size,Z0))
+ add_IC(new);
+}
+
+void add_IC(IC *new)
+/* fuegt ein IC ein */
+{
+ int code;
+ if(!new) return;
+ if(nocode) {
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ /*free(new);*/ /* building a list to free later would be nice... */
+ return;
+ }
+ new->next=0;
+ new->q1.am=new->q2.am=new->z.am=0;
+ new->line=line; new->file=filename;
+ code=new->code;
+ if(code>=BEQ&&code<=BRA) new->q1.flags=new->q2.flags=new->z.flags=0;
+ if(code==ALLOCREG||code==FREEREG||code==SAVEREGS||code==RESTOREREGS) new->typf=0;
+ if(DEBUG&64){ pric(stdout,first_ic);printf("new\n");pric2(stdout,new);printf("-\n");}
+ if(new->q1.flags&VAR){
+ if(!new->q1.v)
+ ierror(0);
+ new->q1.v->flags|=USEDASSOURCE;
+ if(code==ADDRESS||(new->q1.flags&VARADR))
+ if(!is_vlength(new->q1.v->vtyp))
+ new->q1.v->flags|=USEDASADR;
+ new->q1.v->priority+=currentpri;
+ }
+ if(new->q2.flags&VAR){
+ if(!new->q2.v) ierror(0);
+ new->q2.v->flags|=USEDASSOURCE;
+ if(code==ADDRESS||(new->q2.flags&VARADR))
+ if(!is_vlength(new->q2.v->vtyp))
+ new->q2.v->flags|=USEDASADR;
+ new->q2.v->priority+=currentpri;
+ }
+ if(new->z.flags&VAR){
+ if(!new->z.v) ierror(0);
+ if(new->z.flags&DREFOBJ)
+ new->z.v->flags|=USEDASSOURCE;
+ else
+ new->z.v->flags|=USEDASDEST;
+ new->z.v->priority+=currentpri;
+ }
+ if(block_vla[nesting]){
+ /* special handling for blocks with variable-length arrays */
+ llist *p;
+ if(new->code==LABEL){
+ p=mymalloc(LSIZE);
+ p->label=new->typf;
+ p->next=vladeflabels[nesting];
+ vladeflabels[nesting]=p;
+ }else if(0&&new->code==BRA&&!(new->flags&LOOP_COND_TRUE)){
+ p=mymalloc(LSIZE);
+ p->label=new->typf;
+ p->next=vlajmplabels[nesting];
+ vlajmplabels[nesting]=p;
+ p=vladeflabels[nesting];
+ while(p){
+ if(p->label==new->typf)
+ break;
+ p=p->next;
+ }
+ if(!p){
+ /* label not declared in this block so far;
+ re-adjust stack, but store the position - label may be
+ declared later in the same block and adjustement must be
+ removed */
+ vlaadjust_list *vl;
+ IC *first;
+ first=last_ic;
+ freevl();
+ first=first->next;
+ vl=mymalloc(sizeof(*vl));
+ vl->branch=new;
+ vl->first=first;
+ vl->next=vlaadjusts[nesting];
+ vlaadjusts[nesting]=vl;
+ }
+ }
+ }
+ if(/*(c_flags_val[0].l&2)&&*/code==LABEL){
+ /* entfernt Spruenge zu direkt folgenden Labels */
+ IC *p=last_ic;
+ while(p){
+ if(p->typf==new->typf&&p->code>=BEQ&&p->code<=BRA){
+ IC *n;
+ if(p->code!=BRA){
+ IC *cmp=p->prev;
+ while(cmp&&cmp->code==FREEREG) cmp=cmp->prev;
+ if(cmp->code==TEST){
+ if(is_volatile_obj(&cmp->q1))
+ break;
+ else{
+ if(DEBUG&1) printf("preceding test removed\n");
+ remove_IC(cmp);
+ }
+ }else if(cmp->code==COMPARE){
+ if(is_volatile_obj(&cmp->q1)||is_volatile_obj(&cmp->q2))
+ break;
+ else{
+ if(DEBUG&1) printf("preceding compare removed\n");
+ remove_IC(cmp);
+ }
+ }else
+ break;
+ }
+ if(vlaadjusts[nesting]){
+ /* remove it from vlaadjusts-lists, if necessary */
+ vlaadjust_list *vl=vlaadjusts[nesting];
+ while(vl){
+ if(vl->branch==p){
+ IC *np=vl->branch->prev;
+ while(np!=vl->first->prev){
+ if(!np) ierror(0);
+ np->code=NOP;
+ np->q1.flags=np->q2.flags=np->z.flags=0;
+ np=np->prev;
+ }
+ vl->branch=0;
+ }
+ vl=vl->next;
+ }
+ }
+ if(DEBUG&1) printf("%s l%d deleted\n",ename[p->code],p->typf);
+ n=p->next;
+ remove_IC(p);
+ p=n;
+ }else{
+ if(p->code!=LABEL) break;
+ p=p->prev;
+ }
+ }
+ }
+ if(last_ic){
+ if(code==ASSIGN){
+ if((last_ic->z.flags&(REG|SCRATCH|DREFOBJ))==(REG|SCRATCH)&&(new->q1.flags==last_ic->z.flags)&&last_ic->z.reg==new->q1.reg/*&&last_ic->code!=CALL*/){
+ if(USEQ2ASZ||!(last_ic->q2.flags®)||!(new->z.flags®)||last_ic->q2.reg!=new->z.reg){
+ if(USEQ2ASZ||!(last_ic->q2.flags&VAR)||!(new->z.flags&VAR)||last_ic->q2.v!=new->z.v){
+ /* verbindet op a,b->reg,move reg->c zu op a,b->c */
+ /* hier fehlt aber noch Registerfreigabe */
+ last_ic->z=new->z;
+ if(DEBUG&1) printf("move and op combined\n");
+ if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags®)))
+ free_reg(new->q1.reg);
+ free(new);
+ return;
+ }
+ }
+ }
+ if((last_ic->z.flags&(VAR|SCRATCH|DREFOBJ))==(VAR|SCRATCH)&&(new->q1.flags==last_ic->z.flags)&&last_ic->z.v==new->q1.v/*&&last_ic->code!=CALL*/){
+ if(USEQ2ASZ||!(last_ic->q2.flags®)||!(new->z.flags®)||last_ic->q2.reg!=new->z.reg){
+ if(USEQ2ASZ||!(last_ic->q2.flags&VAR)||!(new->z.flags&VAR)||last_ic->q2.v!=new->z.v){
+ /* verbindet op a,b->scratch,move scratch->c zu op a,b->c */
+ /* hier fehlt aber noch Registerfreigabe */
+ last_ic->z=new->z;
+ if(DEBUG&1) printf("move and op combined(2)\n");
+/* if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags®)))
+ free_reg(new->q1.reg);*/
+ free(new);
+ return;
+ }
+ }
+ }
+
+ }
+ if(last_ic->code==BRA){
+ if(!dontdelete&&code!=LABEL&&code!=ALLOCREG&&code!=FREEREG){
+ /* loescht alles nach bra bis ein Label kommt */
+ /* momentan noch nicht perfekt, da es bei alloc/freereg stoppt */
+ free(new);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(DEBUG&1) printf("Unreachable Statement deleted\n");
+ return;
+ }
+ if(last_ic->prev&&code==LABEL){
+ /* ersetzt bcc l1;bra l2;l1 durch b!cc l2 */
+ if(last_ic->prev->code>=BEQ&&last_ic->prev->code<=BGT&&new->typf==last_ic->prev->typf){
+ if(last_ic->next) pric2(stdout,last_ic->next);
+ if(DEBUG&1) printf("%s l%d;%s l%d; substituted\n",ename[last_ic->prev->code],last_ic->prev->typf,ename[last_ic->code],last_ic->typf);
+ if(last_ic->prev->code&1)
+ last_ic->prev->code--;
+ else
+ last_ic->prev->code++;
+ last_ic->prev->typf=last_ic->typf;
+ last_ic=last_ic->prev;
+ free(last_ic->next);
+ last_ic->next=new;new->prev=last_ic;
+ last_ic=new;
+ return;
+ }
+ }
+ }
+/* }*/
+ new->prev=last_ic;
+ last_ic->next=new;
+ last_ic=new;
+ }else{
+ last_ic=new;first_ic=new;new->prev=0;
+ }
+ ic_count++;
+
+#if HAVE_POF2OPT
+ if(((new->code==MULT)||((new->code==DIV||new->code==MOD)&&(new->typf&UNSIGNED)))&&(new->q2.flags&KONST)&&ISINT(new->typf)){
+ /* ersetzt mul etc. mit Zweierpotenzen */
+ long ln;
+ eval_const(&new->q2.val,new->typf);
+ if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+ if(ln=get_pof2(vumax)){
+ if(new->code==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ new->code=AND;
+ }else{
+ if(new->code==DIV) new->code=RSHIFT; else new->code=LSHIFT;
+ vmax=l2zm(ln-1);
+ }
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q2.val,new->typf);
+ new->typf2=new->typf;
+ }
+ }
+ }
+#endif
+
+ /* Merken, on Fliesskomma benutzt wurde */
+ if(code!=LABEL&&(code<BEQ||code>BRA)){
+ if(ISFLOAT(new->typf)) float_used=1;
+ if(code==CONVERT&&ISFLOAT(new->typf2)) float_used=1;
+ }
+ if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(!(new->z.flags®)||new->q1.reg!=new->z.reg))
+ free_reg(new->q1.reg);
+ if((new->q2.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(!(new->z.flags®)||new->q2.reg!=new->z.reg))
+ free_reg(new->q2.reg);
+}
+
+np gen_libcall(char *fname,np arg1,type *t1,np arg2,type *t2)
+/* generate call to a library function (emulate operation) */
+{
+ np new;
+ argument_list *al=0,*t;
+ new=new_node();
+ new->flags=CALL;
+ new->right=0;
+ new->left=new_node();
+ new->left->flags=IDENTIFIER;
+ new->left->left=new->left->right=0;
+ new->left->identifier=add_identifier(fname,strlen(fname));
+ new->left->ntyp=0;
+ new->left->sidefx=0;
+ new->left->val.vmax=l2zm(0L);
+ new->alist=0;
+ if(arg1){
+ al=mymalloc(sizeof(*al));
+ if(postop_obj){
+ al->arg=new_node();
+ al->arg->o=*postop_obj;
+ al->arg->ntyp=new_typ();
+ al->arg->ntyp->flags=postop_type;
+ al->arg->flags=REINTERPRET;
+ }else
+ al->arg=arg1;
+ al->next=0;
+ if(t1){
+ np cnv=new_node();
+ cnv->flags=CAST;
+ cnv->left=arg1;
+ cnv->right=0;
+ cnv->ntyp=t1;
+ al->arg=cnv;
+ }
+ }
+ if(arg2){
+ t=mymalloc(sizeof(*t));
+ t->arg=arg2;
+ t->next=0;
+ al->next=t;
+ if(t2){
+ np cnv=new_node();
+ cnv->flags=CAST;
+ cnv->left=arg2;
+ cnv->right=0;
+ cnv->ntyp=t2;
+ t->arg=cnv;
+ }
+ }
+ new->alist=al;
+ /* Kann man type_expr nochmal auf die Argumente anwenden? */
+ if(t1||t2)
+ no_cast_free=1;
+ if(!type_expression(new,0))
+ ierror(0);
+ no_cast_free=0;
+ gen_IC(new,0,0);
+ return new;
+}
+
+
+void gen_IC(np p,int ltrue,int lfalse)
+/* Erzeugt eine IC-Liste aus einer expression */
+{
+ IC *new; regargs_list *rl;
+ if(!p) return;
+
+ if(p->flags==STRING){
+ Var *v=0;
+ if(merge_strings){
+ for(v=first_var[0];v;v=v->next){
+ if(v->vtyp->flags==ARRAY&&(v->vtyp->next->flags&STRINGCONST)&&zmleq(p->ntyp->size,v->vtyp->size)){
+ zmax i;const_list *cl1=p->cl,*cl2=v->clist;
+ for(i=Z0;!zmleq(p->ntyp->size,i)&&cl1&&cl2;cl1=cl1->next,cl2=cl2->next,i=zmadd(i,Z1)){
+ if(!zumeqto(zuc2zum(cl1->other->val.vuchar),zuc2zum(cl2->other->val.vuchar)))
+ break;
+ }
+ if(zmleq(p->ntyp->size,i)) break;
+ }
+ }
+ }
+ if(!v){
+ p->o.v=add_var(empty,clone_typ(p->ntyp),STATIC,p->cl);
+ p->o.v->flags|=DEFINED;
+ }else
+ p->o.v=v;
+ p->o.flags=VAR;
+ p->o.reg=0;
+ p->o.val=p->val;
+ return;
+ }
+ if(p->flags==LITERAL){
+ int sc;
+ if(nesting==0||(is_const(p->ntyp)&&zmeqto(p->val.vmax,l2zm(0L))))
+ sc=STATIC;
+ else
+ sc=AUTO;
+ p->o.v=add_var(empty,clone_typ(p->ntyp),sc,p->cl);
+ p->o.v->flags|=DEFINED;
+ p->o.flags=VAR;
+ p->o.reg=0;
+ p->o.val.vmax=l2zm(0L);
+ if(sc==AUTO)
+ init_local_compound(p->o.v);
+ return;
+ }
+ if(p->flags==IDENTIFIER){
+/* p->o.v=find_var(p->identifier,0);*/
+ p->o.flags=VAR;
+ p->o.reg=0;
+ p->o.val=p->val;
+ return;
+ }
+ if(p->flags==CEXPR||p->flags==PCEXPR){
+ if(p->left){
+ if(p->left->flags==POSTINC) p->left->flags=PREINC;
+ if(p->left->flags==POSTDEC) p->left->flags=PREDEC;
+ gen_IC(p->left,0,0);
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+ }
+ if(p->right){
+ if(p->right->flags==POSTINC) p->right->flags=PREINC;
+ if(p->right->flags==POSTDEC) p->right->flags=PREDEC;
+ gen_IC(p->right,0,0);
+ if((p->right->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->right->o.reg);
+ }
+ p->o.flags=KONST;
+ p->o.val=p->val;
+ p->o.reg=0;
+ return;
+ }
+ if(p->flags==KOMMA){
+ if(p->left->sidefx){
+ gen_IC(p->left,0,0);
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+ }else if(!(p->left->ntyp->flags&VOLATILE))
+ error(129);
+ gen_IC(p->right,0,0);
+ p->o=p->right->o;
+ return;
+ }
+ if(p->flags==REINTERPRET){
+ if(p->left){
+ gen_IC(p->left,0,0);
+ p->o=p->left->o;
+ }
+ /* if no left, do nothing, use just object */
+ return;
+ }
+ if(p->flags==CAST){
+ gen_IC(p->left,0,0);
+ if((p->ntyp->flags&NQ)==VOID){
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+ p->o.flags=0;
+ }else{
+ if(ISPOINTER(p->ntyp->flags)&&(p->ntyp->next->flags&VOLATILE))
+ volatile_convert=1;
+ convert(p->left,p->ntyp->flags);
+ if(volatile_convert){
+ if((p->left->o.flags&VAR)&&p->left->o.v->vtyp->next)
+ p->left->o.v->vtyp->next->flags|=VOLATILE;
+ volatile_convert=0;
+ }
+ p->o=p->left->o;
+ }
+ return;
+ }
+ if(p->flags==FIRSTELEMENT){
+ gen_IC(p->left,0,0);
+ p->o=p->left->o;
+ return;
+ }
+
+#if HAVE_POF2OPT
+ if(((p->flags==MULT||p->flags==PMULT)||((p->flags==DIV||p->flags==MOD)&&(p->ntyp->flags&UNSIGNED)))&&(p->right->flags==CEXPR||p->right->flags==PCEXPR)&&ISINT(p->ntyp->flags)){
+ /* ersetzt mul etc. mit Zweierpotenzen */
+ long ln;
+ eval_constn(p->right);
+ if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+ if(ln=get_pof2(vumax)){
+ if(p->flags==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ p->flags=AND;
+ }else{
+ if(p->flags==DIV) p->flags=RSHIFT; else p->flags=LSHIFT;
+ vmax=l2zm(ln-1);
+ }
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ insert_constn(p->right);
+ }
+ }
+ }
+#endif
+
+#if HAVE_LIBCALLS
+ if(!(optflags&2)){
+ char *libname;
+ if(libname=use_libcall_wrap(p->flags,p->ntyp->flags,0)){
+ np lc;type *t1,*t2;
+ if(p->flags==LSHIFT||p->flags==RSHIFT){
+ t1=clone_typ(p->ntyp);
+ t2=new_typ();
+ t2->flags=INT;
+ }else{
+ if(p->right){
+ t1=arith_typ(p->left->ntyp,p->right->ntyp);
+ t2=clone_typ(t1);
+ }else{
+ t1=arith_typ(p->left->ntyp,p->left->ntyp);
+ t2=0;
+ }
+ }
+ lc=gen_libcall(libname,p->left,t1,p->right,t2);
+ *p=*lc;
+ free(lc);
+ return;
+ }
+ }
+#endif
+ new=new_IC();
+ new->typf=p->ntyp->flags;
+ new->q1.reg=new->q2.reg=new->z.reg=0;
+ new->q1.flags=new->q2.flags=new->z.flags=0;
+ if((p->flags>=LSHIFT&&p->flags<=MOD)||(p->flags>=OR&&p->flags<=AND)||p->flags==PMULT){
+ do_arith(p,new,0,0);
+ return;
+ }
+ if(p->flags==CONTENT){
+ gen_IC(p->left,0,0);
+ if(p->left->o.flags&VARADR){
+ free(new);
+ p->o=p->left->o;
+ p->o.flags&=~VARADR;
+ return;
+ }
+ if(!(p->left->o.flags&DREFOBJ)){
+ free(new);
+ p->o=p->left->o;
+ p->o.flags|=DREFOBJ;
+ p->o.dtyp=p->left->ntyp->flags;
+ }else{
+ if((p->left->o.flags&SCRATCH)&&p->left->o.dtyp==POINTER_TYPE(p->ntyp)){
+ new->z=p->left->o;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ get_scratch(&new->z,p->left->ntyp->flags,p->ntyp->flags,p->left->ntyp);
+ }
+ new->code=ASSIGN;new->typf=POINTER_TYPE(p->ntyp);
+ new->q1=p->left->o;
+ new->q2.val.vmax=sizetab[new->typf&NQ];
+ p->o=new->z;
+ add_IC(new);
+ p->o.flags|=DREFOBJ;
+ p->o.dtyp=POINTER_TYPE(p->ntyp);
+ }
+ if(p->left->ntyp->next->flags&VOLATILE) p->o.dtyp|=PVOLATILE;
+ return;
+ }
+ if(p->flags==ASSIGN){
+ if(p->left->flags==BITFIELD){
+ gen_IC(p->right,0,0);
+ gen_IC(p->left->left,0,0);
+ convert(p->right,p->ntyp->flags);
+ insert_bitfield(&p->left->left->o,&p->right->o,&p->o,p->left->bfs,p->left->bfo,p->ntyp->flags&NU,0);
+ return;
+ }
+ new->code=ASSIGN;
+ gen_IC(p->right,0,0);
+ gen_IC(p->left,0,0);
+ convert(p->right,p->ntyp->flags);
+ new->q1=p->right->o;
+ new->z=p->left->o;
+ new->q2.val.vmax=szof(p->left->ntyp);
+ p->o=new->z;
+ if(!ISSCALAR(p->ntyp->flags))
+ new->typf2=zm2l(falign(p->ntyp));
+ add_IC(new);
+ return;
+ }
+ if(p->flags==ASSIGNOP){
+ /* das hier ist nicht besonders schoen */
+ obj o,q;IC *n;int f;char *libname;
+ np lc;
+ if(p->right->right==0){
+ /* sowas wie a+=0 wurde wegoptimiert */
+ free(new);
+ p->o=p->left->o;
+ return;
+ }
+#if HAVE_LIBCALLS
+ if(libname=use_libcall_wrap(p->right->flags,p->right->ntyp->flags,(p->right->flags==LSHIFT||p->right->flags==RSHIFT)?INT:0)){
+ type *t1,*t2;
+ np a1;
+ gen_IC(p->left,0,0);
+ a1=new_node();
+ a1->o=p->left->o;
+ a1->flags=REINTERPRET;
+ a1->o.flags&=~SCRATCH;
+ a1->ntyp=clone_typ(p->left->ntyp);
+ t1=clone_typ(p->right->ntyp);
+ if(p->right->flags==LSHIFT||p->right->flags==RSHIFT){
+ t2=new_typ();
+ t2->flags=INT;
+ }else
+ t2=clone_typ(t1);
+ lc=gen_libcall(libname,a1/*p->right->left*/,t1,p->right->right,t2);
+ /**p->right=*lc;*/
+ o=p->left->o;
+ free(a1);
+ /*p->left=0;*/
+ /*free(lc);*/
+ }else
+#endif
+ {
+ lc=0;
+ f=do_arith(p->right,new,p->left,&o);
+ if(!f) ierror(0);
+ if(f>1) ierror(0);
+ }
+ if((o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&!regs[o.reg])
+ keep_reg(o.reg);
+ if(lc)
+ convert(lc,p->ntyp->flags);
+ else
+ convert(p->right,p->ntyp->flags);
+ if(p->left&&p->left->flags==BITFIELD){
+ if(lc) ierror(0);
+ insert_bitfield(&p->left->left->o,&p->right->o,&p->o,p->left->bfs,p->left->bfo,p->ntyp->flags&NU,0);
+ if((p->right->o.flags&(REG|SCRATCH))==(REG|SCRATCH)&®s[p->right->o.reg])
+ free_reg(p->right->o.reg);
+ return;
+ }
+ new=new_IC();
+ new->typf=p->ntyp->flags;
+ new->q2.flags=0;
+ new->code=ASSIGN;
+ if(lc){
+ new->q1=lc->o;
+ /*free(lc);*/
+ }else
+ new->q1=p->right->o;
+ new->z=o;
+ new->q2.val.vmax=szof(p->ntyp);
+ p->o=new->z;
+ add_IC(new);
+ return;
+ }
+ if(p->flags==MINUS||p->flags==KOMPLEMENT){
+ new->code=p->flags;
+ gen_IC(p->left,0,0);
+ convert(p->left,p->ntyp->flags);
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->left->o.reg,p->ntyp->flags,0)){
+ new->z=p->left->o;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ get_scratch(&new->z,p->ntyp->flags,0,p->ntyp);
+ }
+ new->q1=p->left->o;
+ p->o=new->z;
+ add_IC(new);
+ return;
+ }
+ if(p->flags==ADDRESS||p->flags==ADDRESSA||p->flags==ADDRESSS){
+ if(p->flags!=ADDRESSS&&p->left->flags==IDENTIFIER&&is_vlength(p->left->ntyp)){
+ gen_IC(p->left,0,0);
+ if(!(p->left->o.flags&VAR))
+ ierror(0);
+ free(new);
+ p->o=p->left->o;
+ return;
+ }
+ new->code=ADDRESS;
+ new->typf=p->left->ntyp->flags;
+ new->typf2=POINTER_TYPE(p->left->ntyp);
+ gen_IC(p->left,0,0);
+ if(p->left->o.flags&VAR) p->left->o.v->flags|=(USEDASSOURCE|USEDASDEST);
+ if(p->left->o.flags&DREFOBJ){
+ free(new);
+ p->o=p->left->o;
+ p->o.flags&=~DREFOBJ;
+ return;
+ }
+ if((p->left->o.flags&VAR)&&!(p->left->o.flags&VARADR)
+ &&(p->left->o.v->storage_class==EXTERN||p->left->o.v->storage_class==STATIC)){
+ free(new);
+ p->o=p->left->o;
+ p->o.flags|=VARADR;
+ return;
+ }
+ new->q1=p->left->o;
+ get_scratch(&new->z,POINTER_TYPE(p->ntyp->next),p->ntyp->next->flags,0);
+ p->o=new->z;
+ add_IC(new);
+ return;
+ }
+ if(p->flags==LAND||p->flags==LOR){
+ int l1,l2,l3,l4;
+/* printf("%s true=%d false=%d\n",ename[p->flags],ltrue,lfalse);*/
+
+ if(ISVECTOR(p->ntyp->flags)){
+ do_arith(p,new,0,0);
+ return;
+ }
+
+ l1=++label;
+ if(!ltrue) {l2=++label;l3=++label;l4=++label;}
+ if(!ltrue){
+ if(p->flags==LAND)
+ gen_IC(p->left,l1,l3);
+ else
+ gen_IC(p->left,l3,l1);
+ }else{
+ if(p->flags==LAND)
+ gen_IC(p->left,l1,lfalse);
+ else
+ gen_IC(p->left,ltrue,l1);
+ }
+ if(p->left->o.flags!=0){
+ if(p->flags==LAND)
+ gen_test(&p->left->o,p->left->ntyp->flags,BEQ,((!ltrue)?l3:lfalse));
+ else
+ gen_test(&p->left->o,p->left->ntyp->flags,BNE,((!ltrue)?l3:ltrue));
+ }
+ gen_label(l1);
+ if(!ltrue){
+ if(p->flags==LAND)
+ gen_IC(p->right,l2,l3);
+ else
+ gen_IC(p->right,l3,l2);
+ }else
+ gen_IC(p->right,ltrue,lfalse);
+ if(p->right->o.flags!=0){
+ if(p->flags==LAND)
+ gen_test(&p->right->o,p->right->ntyp->flags,BEQ,((!ltrue)?l3:lfalse));
+ else
+ gen_test(&p->right->o,p->right->ntyp->flags,BNE,((!ltrue)?l3:ltrue));
+ }
+ if(!ltrue){
+ gen_label(l2);
+ if(p->flags==LAND) gen_cond(&p->o,0,l3,l4); else gen_cond(&p->o,1,l3,l4);
+ }else{
+ new=new_IC();
+ new->code=BRA;
+ if(p->flags==LAND) new->typf=ltrue; else new->typf=lfalse;
+ add_IC(new);
+ }
+ if(ltrue) p->o.flags=0;
+ return;
+ }
+ if(p->flags==NEGATION){
+ int l1,l2,l3;
+ if(ISVECTOR(p->ntyp->flags)){
+ gen_IC(p->left,0,0);
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->left->o.reg,p->ntyp->flags,0)){
+ new->z=p->left->o;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ get_scratch(&new->z,p->left->ntyp->flags,0,p->left->ntyp);
+ }
+ new->typf=p->left->ntyp->flags;
+ new->q1=p->left->o;
+ p->o=new->z;
+ new->code=NEGATION;
+ add_IC(new);
+ return;
+ }
+ if(!ltrue) {l1=++label;l2=++label;l3=++label;}
+ if(ltrue)
+ gen_IC(p->left,lfalse,ltrue);
+ else
+ gen_IC(p->left,l1,l3);
+ if(!p->left->o.flags){
+ free(new);p->o.flags=0;
+ }else{
+ gen_test(&p->left->o,p->left->ntyp->flags,BNE,((!ltrue)?l1:lfalse));
+ }
+ if(ltrue){
+ new=new_IC();
+ new->code=BRA;
+ if(!ltrue) new->typf=l2; else new->typf=ltrue;
+ add_IC(new);
+ p->o.flags=0;
+ }else{
+ gen_label(l3);
+ gen_cond(&p->o,0,l1,l2);
+ }
+ return;
+ }
+ if(p->flags>=EQUAL&&p->flags<=GREATEREQ){
+ int l1,l2,l3,tl,tr;
+ type *at=0;
+ char *libname;
+ if(ISVECTOR(p->ntyp->flags)){
+ do_arith(p,new,0,0);
+ return;
+ }
+ if(!ltrue) {l1=++label;l2=++label;l3=++label;}
+ if(p->left->flags==CEXPR){
+ /* Konstanten nach rechts */
+ np merk;merk=p->left;p->left=p->right;p->right=merk;
+ if(p->flags==LESS) p->flags=GREATER;
+ else if(p->flags==LESSEQ) p->flags=GREATEREQ;
+ else if(p->flags==GREATER) p->flags=LESS;
+ else if(p->flags==GREATEREQ) p->flags=LESSEQ;
+ }
+#if HAVE_LIBCALLS
+ at=arith_typ(p->left->ntyp,p->right->ntyp);
+ if(libname=use_libcall_wrap(COMPARE,at->flags,0)){
+ new->q1=gen_libcall(libname,p->left,at,p->right,clone_typ(at))->o;
+ new->code=COMPARE;
+ new->typf=LIBCALL_CMPTYPE;
+ new->q2.flags=KONST;
+ gval.vmax=Z0;
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q2.val,LIBCALL_CMPTYPE);
+ }else{
+#endif
+ new->code=COMPARE;
+ tl=p->left->ntyp->flags&NU;tr=p->right->ntyp->flags&NU;
+ if(p->right->flags==CEXPR&&ISINT(tr)&&ISINT(tl)&&zm2l(sizetab[tl&NQ])<=zm2l(sizetab[tr&NQ])&&((tl&NQ)>=INT||shortcut(COMPARE,tl))){
+ int negativ;
+ eval_constn(p->right);
+ if(zmleq(vmax,l2zm(0L))) negativ=1; else negativ=0;
+ if((tl&UNSIGNED)||(tr&UNSIGNED)) negativ=0;
+ if((!negativ||zmleq(t_min(tl),vmax))&&(negativ||zumleq(vumax,t_max(tl)))){
+ if((tl&UNSIGNED)||!(tr&UNSIGNED)||p->flags==EQUAL||p->flags==INEQUAL){
+ convert(p->right,tl);
+ tr=tl;
+ }
+ }
+ }
+ if(ISARITH(tl)&&(tl!=tr||!shortcut(COMPARE,tl))){
+ type *t;
+ t=arith_typ(p->left->ntyp,p->right->ntyp);
+ new->typf=t->flags;
+ freetyp(t);
+ }else{
+ new->typf=p->left->ntyp->flags;
+ }
+ gen_IC(p->left,0,0);
+ convert(p->left,new->typf);
+ gen_IC(p->right,0,0);
+ convert(p->right,new->typf);
+ new->q1=p->left->o;
+ new->q2=p->right->o;
+ new->z.flags=0;
+ if(p->flags==EQUAL||p->flags==INEQUAL){
+ /* generate TEST, if possible */
+ if(new->q2.flags&KONST){
+ eval_const(&new->q2.val,new->typf);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+ new->code=TEST;
+ new->q2.flags=0;
+ }
+ }
+ }
+#if HAVE_LIBCALLS
+ }
+#endif
+ freetyp(at);
+ add_IC(new);
+ new=new_IC();
+ if(p->flags==EQUAL) new->code=BEQ;
+ if(p->flags==INEQUAL) new->code=BNE;
+ if(p->flags==LESS) new->code=BLT;
+ if(p->flags==LESSEQ) new->code=BLE;
+ if(p->flags==GREATER) new->code=BGT;
+ if(p->flags==GREATEREQ) new->code=BGE;
+ if(ltrue) new->typf=ltrue; else new->typf=l1;
+ add_IC(new);
+ if(ltrue){
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lfalse;
+ add_IC(new);
+ p->o.flags=0;
+ }else{
+ gen_label(l3);
+ gen_cond(&p->o,1,l1,l2);
+ }
+ return;
+ }
+ if(p->flags==CALL){
+ int r=0,radrpush=0;
+ obj *op,cfunc,ret_obj;
+ zmax sz;
+ int mregs[MAXR+1];
+ IC *callic;
+#ifdef ORDERED_PUSH
+ IC *merk_fp,*lp;
+ unsigned int merk_opushed=opushed;
+#endif
+ if(p->left->flags==ADDRESS&&p->left->left->flags==IDENTIFIER){
+ Var *v;
+ gen_IC(p->left,0,0); r=1;
+ v=p->left->o.v;
+ if(v->fi&&v->fi->first_ic&&!cross_module&&(c_flags_val[0].l&4096)){
+ /* function call inlining */
+ argument_list *al;
+ Var *vp,**argl1,**argl2;
+ IC *ip;int lc;
+ int arg_cnt=0,i;
+ if(DEBUG&1024){
+ printf("inlining call to <%s>\n",v->identifier);
+ for(vp=v->fi->vars;vp;vp=vp->next)
+ printf("%s(%ld)/%p\n",vp->identifier,zm2l(vp->offset),(void*)vp);
+ }
+ for(vp=v->fi->vars;vp;vp=vp->next){
+ /*FIXME: zmeqto hier ok? siehe cross_module_inline */
+ if((zmeqto(vp->offset,l2zm(0L))||vp->reg)&&*vp->identifier&&(vp->storage_class==AUTO||vp->storage_class==REGISTER)) arg_cnt++;
+ }
+
+ /* Argumente in die ersten Parametervariablen kopieren */
+ argl1=mymalloc(arg_cnt*sizeof(Var *));
+ argl2=mymalloc(arg_cnt*sizeof(Var *));
+
+ al=p->alist;vp=v->fi->vars;i=0;
+ while(al){
+ /*FIXME: zmeqto hier ok? siehe cross_module_inline */
+ while(vp&&(!*vp->identifier||(!zmeqto(vp->offset,l2zm(0L))&&!vp->reg)||(vp->storage_class!=REGISTER&&vp->storage_class!=AUTO))) vp=vp->next;
+ if(!vp){ error(39); break; }
+ if(i>=arg_cnt) ierror(0);
+ if(DEBUG&1024) printf("arg: %s(%ld)\n",vp->identifier,zm2l(vp->offset));
+ argl1[i]=vp;
+ argl2[i]=add_var(empty,clone_typ(vp->vtyp),vp->storage_class,0);
+ if(!al->arg) ierror(0);
+ gen_IC(al->arg,0,0);
+ convert(al->arg,vp->vtyp->flags);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->q1=al->arg->o;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(vp->vtyp);
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ new->z.v=argl2[i];
+ new->typf=vp->vtyp->flags;
+ new->typf2=falign(vp->vtyp);
+ add_IC(new);
+ i++;
+ al=al->next;
+ vp=vp->next;
+ }
+ if(i<arg_cnt){ error(83); arg_cnt=i;}
+
+ /* Kopien der Variablen erzeugen */
+ for(vp=v->fi->vars;vp;vp=vp->next){
+ vp->inline_copy=0;
+ }
+ for(i=0;i<arg_cnt;i++){
+ if(argl1[i]){
+ if(!argl2[i]) ierror(0);
+ argl1[i]->inline_copy=argl2[i];
+ }
+ }
+
+ /* Rueckgabewert */
+ if((p->ntyp->flags&NQ)!=VOID){
+ p->o.flags=SCRATCH|VAR;
+ p->o.reg=0;p->o.val.vmax=l2zm(0L);
+ p->o.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+ }else{
+ p->o.flags=0;
+ }
+
+ free(argl1);
+ free(argl2);
+
+ /* Code einfuegen und Labels umschreiben */
+ ip=v->fi->first_ic;lc=0;
+ while(ip){
+ Var *iv;
+ int c;
+ new=new_IC();
+ *new=*ip;
+ ip->copy=new;
+ c=ip->code;
+ /* evtl. ist ein IC praktisch ein SETRETURN, falls das */
+ /* Rueckgabeziel ueber Parameterzeiger angespr. wird */
+ if(ip->z.flags&VAR){
+ iv=ip->z.v;
+ if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+ if(!*iv->identifier&&zmeqto(iv->offset,l2zm(0L))){
+ new->z=p->o;
+ }else{
+ if(!iv->inline_copy){
+ iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+ iv->inline_copy->reg=iv->reg;
+ }
+ new->z.v=iv->inline_copy;
+ }/*else if(iv->inline_copy) ierror(0);*/
+ }
+ }
+ /* Kopien aller auto/register Variablen erzeugen */
+ if(ip->q1.flags&VAR){
+ iv=ip->q1.v;
+ if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+ if(!iv->inline_copy){
+ iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+ iv->inline_copy->reg=iv->reg;
+ }
+ new->q1.v=iv->inline_copy;
+ }/*else if(iv->inline_copy) ierror(0);*/
+ }
+ if(ip->q2.flags&VAR){
+ iv=ip->q2.v;
+ if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+ if(!iv->inline_copy){
+ iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+ iv->inline_copy->reg=iv->reg;
+ }
+ new->q2.v=iv->inline_copy;
+ }/*else if(iv->inline_copy) ierror(0);*/
+ }
+ if(c==CALL){
+ int i;
+ function_calls+=currentpri;
+ new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+ for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=ip->arg_list[i]->copy;
+ }
+ if(c==LABEL||(c>=BEQ&&c<=BRA)){
+ if(new->typf>lc) lc=new->typf;
+ new->typf+=label;
+ }
+ if(c==SETRETURN){
+ new->code=ASSIGN;
+ new->z=p->o;
+ }
+ add_IC(new);
+ ip=ip->next;
+ }
+ label+=lc;
+ return;
+ }
+ /* einige spezielle Inline-Funktionen; das setzt voraus, dass */
+ /* diese in den Headerfiles passend deklariert werden */
+ if(v->storage_class==EXTERN){
+ if((optflags&2)&&(!strcmp(v->identifier,"strlen")||!strcmp(v->identifier,"__asm_strlen"))&&p->alist&&p->alist->arg){
+ np n=p->alist->arg;
+ if(n->flags==ADDRESSA&&n->left->flags==STRING&&zmeqto(n->left->val.vmax,l2zm(0L))){
+ const_list *cl;zumax len=ul2zum(0UL);
+ cl=n->left->cl;
+ while(cl){
+ if(zmeqto(l2zm(0L),zc2zm(cl->other->val.vchar))) break;
+ len=zumadd(len,ul2zum(1UL));
+ cl=cl->next;
+ }
+ p->o.val.vumax=len;
+ eval_const(&p->o.val,UNSIGNED|MAXINT);
+ insert_constn(p);
+ insert_const(&p->o.val,p->ntyp->flags);
+ p->flags=CEXPR;
+ p->o.flags=KONST;
+ return;
+ }
+ }
+
+ if(inline_memcpy_sz>0&&(optflags&2)){
+ if((!strcmp(v->identifier,"strcpy")||!strcmp(v->identifier,"__asm_strcpy"))&&p->alist&&p->alist->next&&p->alist->next->arg){
+ np n=p->alist->next->arg;
+ if(n->flags==ADDRESSA&&n->left->flags==STRING&&zmeqto(n->left->val.vmax,l2zm(0L))){
+ const_list *cl;zmax len=l2zm(0L);
+ cl=n->left->cl;
+ while(cl){
+ len=zmadd(len,l2zm(1L));
+ if(zmeqto(zc2zm(cl->other->val.vchar),l2zm(0L))) break;
+ cl=cl->next;
+ }
+ if(zmleq(len,l2zm((long)inline_memcpy_sz))){
+ inline_memcpy(p->alist->arg,n,len);
+ p->o=p->alist->arg->o;
+ return;
+ }
+ }
+ }
+ if(!strcmp(v->identifier,"memcpy")||!strcmp(v->identifier,"__asm_memcpy")){
+ if(p->alist&&p->alist->next&&p->alist->next->next
+ &&p->alist->next->next->arg
+ &&p->alist->next->next->arg->flags==CEXPR){
+ eval_constn(p->alist->next->next->arg);
+ if(zmleq(vmax,l2zm((long)inline_memcpy_sz))){
+ inline_memcpy(p->alist->arg,p->alist->next->arg,vmax);
+ p->o=p->alist->arg->o;
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ rl=0;
+ if(!(optflags&2)){
+ int r;
+ for(r=1;r<=MAXR;r++){mregs[r]=regs[r];regs[r]&=~(RNOSAVE|RHALF);}
+ }else{
+ gen_IC(p->left,0,0);
+ }
+#ifdef ORDERED_PUSH
+ merk_fp=first_pushed;
+ first_pushed=0;
+ lp=last_ic;
+#endif
+#ifdef HAVE_REGPARMS
+ if(!ffreturn(p->ntyp)&&(p->ntyp->flags&NQ)!=VOID){
+ IC *new2;static type ptyp={0};
+ treg_handle reg_handle=empty_reg_handle;
+ int reg;
+ ptyp.next=p->ntyp;
+ ptyp.flags=POINTER_TYPE(p->ntyp);
+ reg=reg_parm(®_handle,&ptyp,0,p->left->ntyp->next);
+ if(reg){
+ new2=new_IC();
+ new2->code=ADDRESS;
+ new2->typf=p->ntyp->flags;
+ new2->typf2=POINTER_TYPE(p->ntyp);
+ new2->q1.flags=VAR;
+ new2->q1.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+ new2->q1.val.vmax=l2zm(0L);
+ op=&new2->q1;
+ new2->q2.flags=0;
+ get_scratch(&new2->z,POINTER_TYPE(p->ntyp),p->ntyp->flags,0);
+ ret_obj=new2->z;
+ add_IC(new2);
+ sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,&ret_obj,p->ntyp,reg,p->left->ntyp);
+ if(optflags&2)
+ handle_reglist(rl,&ret_obj);
+ }else{
+ sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,0,p->ntyp,reg,p->left->ntyp);
+ radrpush=1;
+ if(optflags&2)
+ handle_reglist(rl,0);
+ }
+ }else{
+ treg_handle reg_handle=empty_reg_handle;
+ sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,0,0,-1,p->left->ntyp);
+ if(optflags&2)
+ handle_reglist(rl,0);
+ }
+#else
+ sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl);
+ if(optflags&2)
+ handle_reglist(rl,0);
+#endif
+ if(!r&&!(optflags&2)) gen_IC(p->left,0,0);
+ if(!(p->left->o.flags&DREFOBJ)){
+ free(new);
+ p->o=p->left->o;
+ if(p->o.flags&VARADR){
+ p->o.flags&=~VARADR;
+ }else{
+ p->o.flags|=DREFOBJ;
+ p->o.dtyp=p->left->ntyp->flags;
+ }
+ }else{
+ if(p->left->o.flags&VARADR){
+ free(new);
+ p->o=p->left->o;
+ p->o.flags&=~VARADR;
+ }else{
+ if((p->left->o.flags&SCRATCH)&&p->ntyp->flags==p->left->ntyp->flags){
+ new->z=p->left->o;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ get_scratch(&new->z,p->left->ntyp->flags,FUNKT,p->left->ntyp);
+ }
+ new->code=ASSIGN;
+ new->typf=p->left->ntyp->flags;
+ new->q1=p->left->o;
+ new->q2.val.vmax=sizetab[new->typf&NQ];
+ new->q2.flags=0;
+ p->o=new->z;
+ add_IC(new);
+ p->o.flags|=DREFOBJ;
+ p->o.dtyp=p->left->ntyp->flags;
+ }
+ }
+/* p->left->o.flags-=DREFOBJ|VARADR; Was sollte das?? */
+
+#if 0
+ if(optflags&2){
+ while(rl){
+ regargs_list *m;
+ new=new_IC();
+ new->code=NOP;
+ new->q1.flags=VAR;
+ new->q1.v=rl->v;
+ new->q1.val.vmax=l2zm(0L);
+ new->typf=0;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ m=rl->next;free(rl);rl=m;
+ }
+ }
+#endif
+
+ /* gegebenenfalls Adresse des Ziels auf den Stack */
+#ifdef HAVE_REGPARMS
+ if(radrpush)
+#else
+ if(!ffreturn(p->ntyp)&&(p->ntyp->flags&NQ)!=VOID)
+#endif
+ {
+#if defined(ORDERED_PUSH) && defined(HAVE_REGPARMS)
+ ierror(0);
+#endif
+ new=new_IC();
+ new->code=ADDRESS;
+ new->typf=p->ntyp->flags;
+ new->typf2=POINTER_TYPE(p->ntyp);
+ new->q1.flags=VAR;
+ new->q1.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+ new->q1.val.vmax=l2zm(0L);
+ op=&new->q1;
+ new->q2.flags=0;
+ get_scratch(&new->z,POINTER_TYPE(p->ntyp),p->ntyp->flags,0);
+ ret_obj=new->z;
+ add_IC(new);
+ new=new_IC();
+ new->code=PUSH;
+ new->typf=POINTER_TYPE(p->ntyp);
+ new->q1=ret_obj;
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sizetab[new->typf&NQ];
+ new->z.val.vmax=new->q2.val.vmax;
+ add_IC(new);
+ sz=zmadd(sz,sizetab[new->typf&NQ]);
+ }
+
+ /* Scratchregister evtl. sichern */
+ cfunc=p->o;
+ if(!nocode)
+ savescratch(MOVEFROMREG,last_ic,0,&cfunc);
+ function_calls+=currentpri;
+ new=new_IC();
+ new->code=CALL;
+ callic=new;
+ if(p->alist){
+ /* insert list of argument ICs */
+ int i=0;
+ argument_list *a=p->alist;
+ while(a){i++;a=a->next;}
+ new->arg_cnt=i;
+ new->arg_list=mymalloc(sizeof(*new->arg_list)*i);
+ for(a=p->alist,i=0;a;a=a->next,i++) new->arg_list[i]=a->pushic;
+ }else{
+ new->arg_cnt=0;
+ new->arg_list=0;
+ }
+ new->typf=FUNKT;
+ new->q1=p->o;
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sz; /* Groesse der Parameter auf dem Stack */
+ add_IC(new);
+
+ //pric2(stdout,new);
+
+ if(optflags&2){
+ while(rl){
+ regargs_list *m;
+ new=new_IC();
+ new->code=NOP;
+ new->q1.flags=VAR;
+ new->q1.v=rl->v;
+ new->q1.val.vmax=l2zm(0L);
+ new->typf=0;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ m=rl->next;free(rl);rl=m;
+ }
+ }
+
+ r=0;
+ if((p->ntyp->flags&NQ)!=VOID){
+ new=new_IC();
+ new->code=GETRETURN;
+ new->q1.flags=new->q2.flags=0;
+ new->q1.reg=ffreturn(p->ntyp);
+ new->q2.val.vmax=szof(p->ntyp);
+ new->typf=p->ntyp->flags;
+ if(ffreturn(p->ntyp)){
+ int t=p->ntyp->flags&NQ;
+ if(ISSTRUCT(t)||ISUNION(t)){
+ new->z.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ }else{
+ if(optflags&2){
+ get_scratch(&new->z,p->ntyp->flags,0,p->ntyp);
+ }else{
+ /* Suche geeignetes Register, um Rueckgabewert zu speichern. */
+ regargs_list *l2;
+ int r;
+ r=new->q1.reg;
+ if(regs[r]||!regok(r,p->ntyp->flags,0)||(reg_pair(r,&rp)&&(regs[rp.r1]||regs[rp.r2]))){
+ r=0;
+ }else{
+ for(l2=rl;l2;l2=l2->next){
+ if(l2->v&&abs(l2->reg)==r) {r=0;break;}
+ }
+ }
+ if(r==0){
+ for(r=1;r<=MAXR;r++){
+ if(!regs[r]&®ok(r,p->ntyp->flags,0)&&(!reg_pair(r,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){
+ for(l2=rl;l2;l2=l2->next){
+ if(l2->v&&abs(l2->reg)==r) break;
+ }
+ if(l2) continue;
+ break;
+ }
+ }
+ }
+ if(r>=1&&r<=MAXR){
+ alloc_hardreg(r);
+ new->z.flags=(REG|SCRATCH);
+ new->z.reg=r;
+ }else{
+ get_scratch(&new->z,p->ntyp->flags,0,p->ntyp);
+ }
+ }
+ }
+ } else
+ new->z=*op;
+ if((new->z.flags&(REG|DREFOBJ))==REG) r=new->z.reg;
+ p->o=new->z;
+ add_IC(new);
+ }else{
+ p->o.flags=0;
+ }
+ /* Scratchregister evtl. wiederherstellen */
+ if(!nocode)
+ savescratch(MOVETOREG,last_ic,r,&cfunc);
+ if(!(optflags&2)){
+ int r;
+ for(r=1;r<=MAXR;r++){
+ if(regs[r])
+ regs[r]|=(mregs[r]&RNOSAVE);
+ }
+ }
+ /* Evtl. gespeicherte Registerargumente wiederherstellen. */
+ while(rl){
+ regargs_list *m;
+ if(rl->v){
+ int r;
+ for(r=MAXR;r>=1;r--){
+ if(regs[r]&®_pair(r,&rp)&&(rp.r1==abs(rl->reg)||rp.r2==abs(rl->reg)))
+ break;
+ }
+ if(r<=1) r=abs(rl->reg);
+ new=new_IC();
+ new->code=MOVETOREG;
+ new->typf=0;
+ new->q1.flags=VAR|DONTREGISTERIZE;
+ new->q1.v=rl->v;
+ new->q1.val.vmax=l2zm(0L);
+ new->z.flags=REG;
+ if(rl->rsaved)
+ new->z.reg=rl->rsaved;
+ else
+ new->z.reg=abs(r);
+ new->q2.flags=0;
+ new->q2.val.vmax=regsize[r];
+ add_IC(new);
+ if(rl->rsaved)
+ free_reg(abs(rl->reg));
+ }else{
+ free_reg(abs(rl->reg));
+ }
+ m=rl->next;free(rl);rl=m;
+ }
+#ifdef ORDERED_PUSH
+ /* If arguments have been pushed nested we have to copy them and */
+ /* push them later. */
+ if(merk_fp&&opushed!=merk_opushed){
+ IC *p,*m=0,*np;
+ if(!lp) ierror(0);
+ for(p=merk_fp;p;){
+ np=p->next;
+ if(p->code==PUSH){
+ new=new_IC();
+ *new=*p;
+ /* be careful about the address because of arg_list! */
+ if(p->prev) p->prev->next=new;
+ new->prev=p->prev;
+ if(p->next) p->next->prev=new;
+ new->next=p->next;
+ if(p==last_ic) last_ic=new;
+ if(p==first_ic) first_ic=new;
+ if(new->q1.flags&&!(p->flags&ORDERED_PUSH_COPY)){
+ new->code=ASSIGN;
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ /* typ allocated in push_args and not used there */
+ /* if(!p->ityp) ierror(0);*/
+ new->z.v=add_tmp_var(clone_typ(p->ityp)); /*FIXME??*/
+ p->q1=new->z;
+ /* p->ityp=0;*/
+ }else{
+ remove_IC(new);
+ }
+ p->next=p->prev=0;
+ p->flags|=ORDERED_PUSH_COPY;
+ add_IC(p);
+ if(!m&&!nocode) m=p;
+ }
+ if(p==lp) break;
+ p=np;
+ }
+ if(!m) ierror(0);
+ first_pushed=m;
+ }else
+ first_pushed=merk_fp;
+#endif
+ return;
+ }
+ if(p->flags>=PREINC&&p->flags<=POSTDEC){
+ obj o;
+#if HAVE_LIBCALLS
+ char *libname;
+ node tn={ADD},one={CEXPR};
+#endif
+ gen_IC(p->left,0,0);
+ if((p->flags==POSTINC||p->flags==POSTDEC)){
+ /*new=new_IC();*/
+ new->code=ASSIGN;
+ new->typf=p->ntyp->flags;
+ new->q2.val.vmax=sizetab[p->ntyp->flags&NQ];
+ new->q1=p->left->o;
+ postop_obj=&new->q1;
+ postop_type=new->typf;
+ new->q1.flags&=~SCRATCH;
+ get_scratch(&new->z,p->left->ntyp->flags,0,p->left->ntyp);
+ new->q2.flags=0;
+ o=new->z;
+ add_IC(new);
+ new=new_IC();
+ }else
+ o=p->left->o;
+#if HAVE_LIBCALLS
+ if(p->flags==PREDEC||p->flags==POSTDEC)
+ tn.flags=SUB;
+ tn.left=p->left;
+ tn.right=&one;
+ tn.ntyp=p->ntyp;
+ one.flags=CEXPR;
+ one.ntyp=p->ntyp;
+ gval.vmax=l2zm(1L);
+ eval_const(&gval,MAXINT);
+ insert_const(&one.val,p->ntyp->flags&NU);
+ if(libname=use_libcall_wrap(tn.flags,tn.ntyp->flags,0)){
+ np lc;
+ lc=gen_libcall(libname,p->left,0,&one,0);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=p->ntyp->flags;
+ new->q2.val.vmax=sizetab[p->ntyp->flags&NQ];
+ new->q1=lc->o;
+ new->q1.flags&=~SCRATCH;
+ new->z=p->left->o;
+ add_IC(new);
+ new=new_IC();
+ free(lc);
+ }else
+#endif
+ if(ISPOINTER(p->left->ntyp->flags)){
+ if(p->flags==PREINC||p->flags==POSTINC)
+ new->code=ADDI2P;
+ else
+ new->code=SUBIFP;
+ vmax=szof(p->left->ntyp->next);
+ new->q2.val.vint=zm2zi(vmax);
+ new->typf=INT;
+ new->typf2=p->left->ntyp->flags;
+ new->q1=p->left->o;
+ new->z=p->left->o;
+ new->q2.flags=KONST;
+ add_IC(new);
+ }else{
+ if(p->flags==PREINC||p->flags==POSTINC)
+ new->code=ADD;
+ else
+ new->code=SUB;
+ new->typf=p->ntyp->flags;
+ new->q1=p->left->o;
+ new->z=p->left->o;
+ new->q2.flags=KONST;
+ gval.vint=zm2zi(l2zm(1L));
+ eval_const(&gval,INT);
+ insert_const(&new->q2.val,new->typf);
+ add_IC(new);
+ }
+ if(p->left->flags==BITFIELD){
+ insert_bitfield(&p->left->left->o,&new->z,&p->o,p->left->bfs,p->left->bfo,p->ntyp->flags,0);
+ if(p->flags!=POSTINC&&p->flags!=POSTDEC){
+ o=p->o;
+ }else{
+ if((p->o.flags&(REG|SCRATCH))==(REG|SCRATCH))
+ free_reg(p->o.reg);
+ }
+ }
+ if(p->flags==POSTINC||p->flags==POSTDEC||p->left->flags==BITFIELD){
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG))
+ free_reg(p->left->o.reg);
+ }
+
+ postop_obj=0;
+ p->o=o;
+ return;
+ }
+ if(p->flags==COND){
+ int ltrue,lfalse,lout;
+ ltrue=++label;lfalse=++label;lout=++label;
+ gen_IC(p->left,ltrue,lfalse);
+ if(!p->left->o.flags){
+ free(new);
+ }else{
+ if(p->left->flags!=CEXPR){
+ gen_test(&p->left->o,p->left->ntyp->flags,BEQ,lfalse);
+ }else{
+ eval_constn(p->left);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+ gen_IC(p->right->right,0,0);
+ p->o=p->right->right->o;
+ }else{
+ gen_IC(p->right->left,0,0);
+ p->o=p->right->left->o;
+ }
+ return;
+ }
+ }
+ gen_label(ltrue);
+ gen_IC(p->right->left,0,0);
+ if((p->ntyp->flags&NQ)!=VOID){
+ convert(p->right->left,p->ntyp->flags);
+ if((p->right->left->o.flags&(SCRATCH|DREFOBJ))==SCRATCH){
+ p->o=p->right->left->o;
+ }else{
+ get_scratch(&p->o,p->ntyp->flags,0,p->ntyp);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->q1=p->right->left->o;
+ new->z=p->o;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(p->ntyp);
+ new->typf=p->ntyp->flags;
+ p->o=new->z;
+ add_IC(new);
+ }
+ }else
+ p->o.flags=0;
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lout;
+ add_IC(new);
+ gen_label(lfalse);
+ gen_IC(p->right->right,0,0);
+ if((p->ntyp->flags&NQ)!=VOID){
+ convert(p->right->right,p->ntyp->flags);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->q1=p->right->right->o;
+ new->z=p->o;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(p->ntyp);
+ new->typf=p->ntyp->flags;
+ add_IC(new);
+ }
+ gen_label(lout);
+ return;
+ }
+ if(p->flags==BITFIELD){
+ int lsc,rsc,bfo;
+ obj tmp;
+ bfo=bflayout(p->bfo,p->bfs,p->ntyp->flags);
+ lsc=zm2l(zmmult(sizetab[p->ntyp->flags&NQ],char_bit))-p->bfs-bfo;
+ rsc=lsc+bfo;
+ gen_IC(p->left,0,0);
+ new->code=LSHIFT;
+ new->typf=p->ntyp->flags;
+ new->typf2=INT;
+ new->q1=p->left->o;
+ new->q2.flags=KONST;
+ new->q2.val.vint=zm2zi(l2zm((long)lsc));
+ get_scratch(&new->z,new->typf,0,0);
+ tmp=new->z;
+ add_IC(new);
+ new=new_IC();
+ new->code=RSHIFT;
+ new->typf=p->ntyp->flags;
+ new->typf2=INT;
+ new->q1=tmp;
+ new->q2.flags=KONST;
+ new->q2.val.vint=zm2zi(l2zm((long)rsc));
+ new->z=tmp;
+ p->o=new->z;
+ add_IC(new);
+ return;
+ }
+ printf("Operation: %d=%s\n",p->flags,ename[p->flags]);
+ ierror(0);
+ free(new);
+ p->o.flags=0;
+}
+
+static void handle_reglist(regargs_list *nrl,obj *radr)
+{
+ IC *new;
+ /* Letztes Argument; jetzt in Register laden. */
+#ifdef HAVE_REGPARMS
+ int didradr=0;
+#endif
+ while(nrl){
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=nrl->v->vtyp->flags/*|VOLATILE*/;
+ new->q1.flags=VAR;
+ new->q1.v=nrl->v;
+ new->q1.val.vmax=l2zm(0L);
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(nrl->v->vtyp);
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ new->z.v=add_var(empty,clone_typ(nrl->v->vtyp),AUTO,0);
+ new->z.v->reg=nrl->reg;
+ new->z.v->vtyp->flags|=VOLATILE;
+ nrl->v=new->z.v;
+ add_IC(new);
+
+#ifdef HAVE_REGPARMS
+ if(radr&&!didradr){
+ didradr=1;
+ }else{
+#endif
+ nrl->al->pushic=new;
+ fix_pushic(&nrl->al->pushic,new);
+#ifdef HAVE_REGPARMS
+ }
+#endif
+ nrl=nrl->next;
+ }
+}
+
+#ifdef HAVE_REGPARMS
+zmax push_args(argument_list *al,struct_declaration *sd,int n,regargs_list **rl,treg_handle *reg_handle,obj *radr,type *rtype,int rreg,type *fkt)
+#else
+zmax push_args(argument_list *al,struct_declaration *sd,int n,regargs_list **rl)
+#endif
+/* Legt die Argumente eines Funktionsaufrufs in umgekehrter Reihenfolge */
+/* auf den Stack. Es wird Integer-Erweiterung vorgenommen und float wird */
+/* nach double konvertiert, falls kein Prototype da ist. */
+{
+ int t,reg,regpush,evaluated=0;type *ft;
+ IC *new;regargs_list *nrl;zmax sz,rsz,of;obj *arg;
+#ifdef HAVE_REGPARMS
+ int stdreg;
+ if(!al&&!radr) return(0);
+ if(radr){
+ stdreg=rreg;
+ }else{
+ if(n<sd->count){
+ stdreg=reg_parm(reg_handle,(*sd->sl)[n].styp,0,fkt->next);
+ }else{
+ if(sd->count)
+ stdreg=reg_parm(reg_handle,al->arg->ntyp,1,fkt->next);
+ else{
+ if(short_push&&ISINT(al->arg->ntyp->flags)){
+ static type t;
+ t.flags=int_erw(al->arg->ntyp->flags);
+ stdreg=reg_parm(reg_handle,&t,0,fkt->next);
+ }else{
+ stdreg=reg_parm(reg_handle,al->arg->ntyp,0,fkt->next);
+ }
+ }
+ }
+ }
+ reg=stdreg;
+#else
+ if(!al) return(0);
+ reg=0;
+#endif
+#ifdef HAVE_REGPARMS
+ if(!radr){
+#endif
+ if(!al->arg) ierror(0);
+ if(!sd) ierror(0);
+ if(n<sd->count){
+ ft=clone_typ((*sd->sl)[n].styp);sz=szof(ft);
+ t=ft->flags;
+ reg=(*sd->sl)[n].reg;
+ }else{
+ ft=clone_typ(al->arg->ntyp);sz=szof(ft);
+ t=ft->flags;
+ }
+ if(ISINT(t)){
+ if(n>=sd->count||!short_push)
+ t=int_erw(t);
+ ft->flags=t;
+ sz=sizetab[t&NQ];
+ }
+ if((t&NQ)==FLOAT&&n>=sd->count) {t=DOUBLE;ft->flags=t;sz=sizetab[t&NQ];}
+#ifdef HAVE_REGPARMS
+ }else{
+ ft=new_typ();
+ ft->flags=t=POINTER_TYPE(rtype);
+ ft->next=clone_typ(rtype);
+ sz=sizetab[t&NQ];
+ }
+#endif
+ if(reg<0) {reg=-reg;regpush=1;} else regpush=0;
+ rsz=sz;
+ sz=zmmult(zmdiv(zmadd(sz,zmsub(stackalign,l2zm(1L))),stackalign),stackalign);
+#ifdef ORDERED_PUSH
+ if(reg==0||regpush){
+ new=new_IC();
+#ifdef HAVE_REGPARMS
+ if(!radr&&!evaluated){
+#endif
+ gen_IC(al->arg,0,0);
+ convert(al->arg,t);
+ evaluated=1;
+ new->q1=al->arg->o;
+ al->pushic=new;
+#ifdef HAVE_REGPARMS
+ }else
+ new->q1=*radr;
+#endif
+ /* Parameteruebergabe ueber Stack. */
+ new->code=PUSH;
+ new->typf=t;
+ new->ityp=ft;
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sz;
+ new->z.val.vmax=rsz;
+ if(regpush){
+ if(c_flags[26]&USEDFLAG){
+ new->q1.am=new->q2.am=new->z.am=0;
+ new->line=line; new->file=filename;
+ insert_IC(last_ic,new);
+ }else{
+ new->q1.flags=0;
+ add_IC(new);
+ if(al) fix_pushic(&al->pushic,new);
+ }
+ }else{
+ add_IC(new);
+ if(al) fix_pushic(&al->pushic,new);
+ }
+ opushed++;
+ if(!first_pushed&&!nocode) first_pushed=new;
+ if(al&&!al->next&&!regpush) return sz;
+ }
+#endif
+#ifdef HAVE_REGPARMS
+ if(radr){
+ if(al) of=push_args(al,sd,0,rl,reg_handle,0,0,0,fkt); else of=l2zm(0L);
+ }else{
+ if(al->next) of=push_args(al->next,sd,n+1,rl,reg_handle,0,0,0,fkt); else of=l2zm(0L);
+ }
+#else
+ if(al->next) of=push_args(al->next,sd,n+1,rl); else of=l2zm(0L);
+#endif
+#ifdef ORDERED_PUSH
+ if(reg==0) return zmadd(of,sz);
+#endif
+
+ if(regpush) of=zmadd(of,sz);
+
+#ifdef HAVE_REGPARMS
+ if(radr){
+ arg=radr;
+ }else{
+ if(!evaluated){
+ gen_IC(al->arg,0,0);
+ convert(al->arg,t);
+ evaluated=1;
+ }
+ arg=&al->arg->o;
+ }
+#else
+ if(!evaluated){
+ gen_IC(al->arg,0,0);
+ convert(al->arg,t);
+ evaluated=1;
+ }
+ arg=&al->arg->o;
+#endif
+#ifndef ORDERED_PUSH
+ if(reg==0||regpush){
+ /* Parameteruebergabe ueber Stack. */
+ new=new_IC();
+ new->code=PUSH;
+ new->typf=t;
+ new->q1=*arg;
+ if(regpush&&!(c_flags[26]&USEDFLAG)) new->q1.flags=0;
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sz;
+ new->z.val.vmax=rsz;
+ add_IC(new);
+ al->pushic=new;
+ fix_pushic(&al->pushic,new);
+ if(!regpush) return(zmadd(of,sz));
+ }
+#endif
+ if(reg){
+ /* Parameteruebergabe in Register. */
+ Var *v=0; type *t2;
+ int rsaved=0;
+ if(optflags&2){
+ /* Version fuer Optimizer. */
+ t2=new_typ();
+ t2->flags=t;
+ if(ISPOINTER(t)){
+ t2->next=new_typ();
+ t2->next->flags=VOID;
+ }
+ v=add_var(empty,t2,AUTO,0);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=t;
+ new->q1=*arg;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[t&NQ];
+ new->z.flags=VAR;
+ new->z.v=v;
+ new->z.val.vmax=l2zm(0L);
+ add_IC(new);
+ nrl=mymalloc(sizeof(*nrl));
+ nrl->next=*rl;
+ nrl->reg=reg;
+ nrl->v=v;
+ nrl->al=al;
+ *rl=nrl;
+ return of;
+ }else{
+ /* Nicht-optimierende Version. */
+
+ if(DEBUG&16){
+ printf("reg[%s]=%d ",regnames[reg],regs[reg]);
+ if(reg_pair(reg,&rp))
+ printf("reg[%s]=%d reg[%s]=%d ",regnames[rp.r1],regs[rp.r1],regnames[rp.r2],regs[rp.r2]);
+ printf("\n");
+ }
+ if(reg_pair(reg,&rp)&&(arg->flags&(REG|SCRATCH))==(REG|SCRATCH)&&(arg->reg==rp.r1||arg->reg==rp.r2)){
+ /* rx->reg_pair(rx,ry): make a copy */
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=t;
+ new->q1=*arg;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[t&NQ];
+ scratch_var(&new->z,t,0);
+ add_IC(new);
+ *arg=new->z;
+ free_reg(arg->reg);
+ }
+ if(!regs[reg]&&(!reg_pair(reg,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))&&!nocode){
+ new=new_IC();
+ new->code=ALLOCREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q1.reg=reg;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ regs[reg]=(1|RNOSAVE);regused[reg]++;
+ if(DEBUG&16) printf("allocated %s (1)\n",regnames[reg]);
+ if(reg_pair(reg,&rp)){
+ regs[rp.r1]=1|RNOSAVE;regused[rp.r1]++;
+ regs[rp.r2]=1|RNOSAVE;regused[rp.r2]++;
+ }
+ }else if(!regs[reg]&®_pair(reg,&rp)&&(regs[rp.r1]||regs[rp.r2])&&!nocode){
+ int r=0;
+ regargs_list *p;
+
+ new=new_IC();
+ new->code=ALLOCREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q2.flags=new->z.flags=0;
+ if(regs[rp.r1]){
+ new->q1.reg=rp.r2;
+ r=rp.r1;
+ regs[r]|=RHALF;
+ }else{
+ new->q1.reg=rp.r1;
+ r=rp.r2;
+ regs[r]|=RHALF;
+ }
+ regs[new->q1.reg]=(1|RNOSAVE);regused[new->q1.reg]++;
+ regs[reg]=(1|RNOSAVE);regused[reg]++;
+ add_IC(new);
+ if(DEBUG&16) printf("allocated %s (half)\n",regnames[new->q1.reg]);
+ rsaved=r;
+ /* Testen, ob Quellregister gesichert wurde. Unschoen. */
+ for(p=*rl;p;p=p->next){
+ int ri;
+ if(p->v&&(ri=abs(p->reg))){
+ if(ri==r) break;
+ if(reg_pair(ri,&rp)&&(rp.r1==r||rp.r2==r)) break;
+ }
+ }
+
+ if(r&&!p){
+ t2=clone_typ(regtype[r]);
+ v=add_var(empty,t2,AUTO,0);
+ v->flags|=USEDASADR;
+ new=new_IC();
+ new->code=MOVEFROMREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q1.reg=r;
+ new->q2.flags=0;
+ new->q2.val.vmax=regsize[r];
+ new->z.flags=VAR|DONTREGISTERIZE;
+ new->z.v=v;
+ new->z.val.vmax=l2zm(0L);
+ add_IC(new);
+ }
+ }else{
+ if((arg->flags&(REG|SCRATCH))!=(REG|SCRATCH)||arg->reg!=reg){
+ int r=0;
+ regargs_list *p;
+
+ /* register pairs */
+ if(reg_pair(reg,&rp)){
+ if(regs[reg]||regs[rp.r1]||regs[rp.r2])
+ r=reg;
+ }else{
+ for(r=MAXR;r>=1;r--){
+ if(regs[r]&®_pair(r,&rp)&&(rp.r1==reg||rp.r2==reg))
+ break;
+ }
+ if(r<1) r=reg;
+ }
+
+
+ /* Testen, ob Quellregister gesichert wurde. Unschoen. */
+ for(p=*rl;p;p=p->next){
+ int ri;
+ if(p->v&&(ri=abs(p->reg))){
+ if(ri==r||(reg_pair(r,&rp)&&(rp.r1==ri||rp.r2==ri))) {break;}
+ if(reg_pair(ri,&rp)&&(rp.r1==r||rp.r2==r)) {break;}
+ }
+ }
+
+ if(r&&!p){
+ t2=clone_typ(regtype[r]);
+ v=add_var(empty,t2,AUTO,0);
+ v->flags|=USEDASADR;
+ new=new_IC();
+ new->code=MOVEFROMREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q1.reg=r;
+ new->q2.flags=0;
+ new->q2.val.vmax=regsize[r];
+ new->z.flags=VAR|DONTREGISTERIZE;
+ new->z.v=v;
+ new->z.val.vmax=l2zm(0L);
+ add_IC(new);
+ }
+ }else{
+ regs[reg]|=RNOSAVE;
+ }
+ }
+ new=new_IC();
+#ifdef HAVE_REGPARMS
+ if(!radr){
+ al->pushic=new;
+ }
+#else
+ al->pushic=new;
+#endif
+ new->code=ASSIGN;
+ new->typf=t;
+ new->q1=*arg;
+ /* Testen, ob Quellregister gesichert wurde. Unschoen. */
+ if((new->q1.flags®)){
+ regargs_list *p;
+ for(p=*rl;p;p=p->next){
+ int r;
+ if(p->v&&(r=abs(p->reg))){
+ if(new->q1.reg==r||(reg_pair(new->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))) {new->q1.v=p->v;new->q1.val.vmax=l2zm(0L);break;}
+ /*FIXME: andersrum bei LITTLEENDIAN?? */
+ if(reg_pair(r,&rp)&&rp.r1==new->q1.reg) {new->q1.v=p->v;new->q1.val.vmax=l2zm(0L);break;}
+ if(reg_pair(r,&rp)&&rp.r2==new->q1.reg) {new->q1.v=p->v;new->q1.val.vmax=regsize[rp.r1];break;}
+
+ }
+ }
+ if(p&&new->q1.v){
+ if(!(new->q1.flags&DREFOBJ)&&must_convert(new->typf,regtype[new->q1.reg]->flags,0)){
+ new->code=CONVERT;
+ new->typf2=regtype[new->q1.reg]->flags;
+ }
+ new->q1.flags&=~REG;
+ new->q1.flags|=VAR;
+ /*new->q1.val.vmax=l2zm(0L);*/
+ }
+ }
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sizetab[t&NQ];
+ new->z.flags=REG;
+ new->z.reg=reg;
+ add_IC(new);
+ if(al) fix_pushic(&al->pushic,new);
+ nrl=mymalloc(sizeof(*nrl));
+ nrl->next=*rl;
+ nrl->reg=reg;
+ nrl->v=v;
+ nrl->rsaved=rsaved; /* if only part of a pair was saved */
+ rsaved=0;
+ *rl=nrl;
+ return of;
+ }
+ }
+}
+
+void convert(np p,int f)
+/* konvertiert das Objekt in p->o in bestimmten Typ */
+/* wenn volatile_convert gesetzt ist, wird immer IC erzeugt */
+{
+ IC *new;
+ int o=p->ntyp->flags;
+ int to,tn,mc,dr;
+ static node n,nn;
+ static type nt;
+ char *libname;
+ if((f&NQ)==VOID) return;
+
+ if(p->flags==CEXPR||p->flags==PCEXPR){
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ eval_constn(p);
+ p->ntyp->flags=f;
+ insert_constn(p);
+ p->o.val=p->val;
+ return;
+ }
+ if((AVOID_FLOAT_TO_UNSIGNED&&ISFLOAT(o)&&(f&UNSIGNED))||
+ (AVOID_UNSIGNED_TO_FLOAT&&ISFLOAT(f)&&(o&UNSIGNED))){
+ union atyps val;
+ int l1,l2,it;
+ Var *tmp;
+ np t;
+ type *ttyp;
+ if(f&UNSIGNED)
+ it=f&NQ;
+ else
+ it=o&NQ;
+ ttyp=clone_typ(p->ntyp);
+ ttyp->flags=f;
+ tmp=add_tmp_var(ttyp);
+ new=new_IC();
+ new->code=COMPARE;
+ new->typf=o;
+ new->q1=p->o;
+ new->q1.flags&=~SCRATCH;
+ new->q2.flags=KONST;
+ new->q2.val.vumax=t_max[it];
+ eval_const(&new->q2.val,MAXINT|UNSIGNED);
+ insert_const(&new->q2.val,o);
+ val=new->q2.val;
+ add_IC(new);
+ new=new_IC();
+ new->code=BLE;
+ l1=++label;
+ new->typf=l1;
+ add_IC(new);
+ new=new_IC();
+ new->code=SUB;
+ new->typf=o;
+ new->q1=p->o;
+ new->q1.flags&=~SCRATCH;
+ new->q2.flags=KONST;
+ new->q2.val=val;
+ new->z.flags=VAR;
+ get_scratch(&new->z,o,0,0);
+ t=new_node();
+ t->ntyp=clone_typ(p->ntyp);
+ t->ntyp->flags&=~UNSIGNED;
+ t->o=new->z;
+ add_IC(new);
+ convert(t,f&NQ);
+ new=new_IC();
+ new->code=ADD;
+ new->typf=f;
+ new->q1=t->o;
+ new->q1.flags&=~SCRATCH;
+ freetyp(t->ntyp);
+ free(t);
+ new->q2.flags=KONST;
+ new->q2.val.vumax=t_max[it];
+ eval_const(&new->q2.val,MAXINT|UNSIGNED);
+ insert_const(&new->q2.val,f);
+ new->z.flags=VAR;
+ new->z.v=tmp;
+ new->z.val.vmax=l2zm(0L);
+ add_IC(new);
+ new=new_IC();
+ new->code=BRA;
+ l2=++label;
+ new->typf=l2;
+ add_IC(new);
+ new=new_IC();
+ new->code=LABEL;
+ new->typf=l1;
+ add_IC(new);
+ p->ntyp->flags&=~UNSIGNED;
+ convert(p,f&NQ);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=f;
+ new->q1=p->o;
+ new->z.flags=VAR;
+ new->z.v=tmp;
+ new->z.val.vmax=l2zm(0L);
+ new->q2.val.vmax=sizetab[f&NQ];
+ p->o=new->z;
+ p->ntyp->flags=f;
+ add_IC(new);
+ new=new_IC();
+ new->code=LABEL;
+ new->typf=l2;
+ add_IC(new);
+ return;
+ }
+ if(ISVECTOR(f)&&ISSCALAR(o)){
+ o=VECTYPE(f);
+ convert(p,o);
+ }
+ if(!volatile_convert&&((o&(NU&~UNSIGNED))==(f&(NU&~UNSIGNED))||(!(mc=must_convert(o,f,const_expr))&&(const_expr||!(optflags&2))))){
+ p->ntyp->flags=f;
+ if(!ISPOINTER(f)&&!ISARRAY(f)){freetyp(p->ntyp->next);p->ntyp->next=0;}
+ return;
+ }
+ /* do not create direct converts between float and small types
+ if the backend does not like that */
+ if(ISFLOAT(o)&&ISINT(f)&&(f&NQ)<MIN_FLOAT_TO_INT_TYPE)
+ tn=MIN_FLOAT_TO_INT_TYPE|(f&UNSIGNED);
+ else
+ tn=f;
+ libname=0;
+ if(ISFLOAT(f)&&ISINT(o)&&(o&NQ)<MIN_INT_TO_FLOAT_TYPE){
+#if HAVE_LIBCALLS
+ if((libname=use_libcall_wrap(CONVERT,tn,o))&&mc){
+ to=o;
+ libname=use_libcall_wrap(CONVERT,tn,MIN_INT_TO_FLOAT_TYPE|(o&UNSIGNED));
+ if(!libname) ierror(0);
+ }else
+#endif
+ {
+ to=MIN_INT_TO_FLOAT_TYPE|(o&UNSIGNED);
+ convert(p,to);
+ }
+ }else{
+ to=o;
+ }
+#if HAVE_LIBCALLS
+ n.flags=CONVERT;
+ n.ntyp=&nt;
+ nt.flags=f;
+ n.left=&nn;
+ nn.ntyp=p->ntyp;
+ if((libname||(libname=use_libcall_wrap(CONVERT,tn,to)))&&mc){
+ node *n=new_node();
+ n->flags=REINTERPRET;
+ n->o=p->o;
+ n->ntyp=p->ntyp;
+ p->o=gen_libcall(libname,n,p->ntyp,0,0)->o;
+ }else{
+#endif
+ new=new_IC();
+ new->q1=p->o;
+ new->q2.flags=0;
+ new->code=CONVERT;
+ new->typf2=to;
+ new->typf=tn;
+ if((p->o.flags&(SCRATCH|REG))!=(SCRATCH|REG)||!regok(p->o.reg,tn,0)){
+ get_scratch(&new->z,tn,0,0);
+ }else{
+ new->z=p->o;new->z.flags&=~DREFOBJ;
+ }
+ p->o=new->z;
+ /* hmm... */
+ if(!mc&&libname){
+ new->code=ASSIGN;
+ new->q2.val.vmax=sizetab[tn&NQ];
+ }
+ add_IC(new);
+#if HAVE_LIBCALLS
+ }
+#endif
+ if(f!=tn){
+ p->ntyp->flags=tn;
+ convert(p,f);
+ }
+}
+
+void alloc_hardreg(int r)
+/* Belegt Register r. */
+{
+ IC *new;
+ if(nocode) return;
+ if(DEBUG&16) printf("allocated %s\n",regnames[r]);
+ regs[r]=1;regused[r]++;
+ new=new_IC();
+ new->code=ALLOCREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q1.reg=r;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ if(reg_pair(r,&rp)){
+ regs[rp.r1]=1;regused[rp.r1]++;
+ regs[rp.r2]=1;regused[rp.r2]++;
+ }
+}
+
+int allocreg(int f,int mode)
+/* Fordert Register fuer Typ f an. */
+{
+ int i,r=0,prio=-1;
+ if(nocode) return(1);
+ for(i=1;i<=MAXR;i++){
+ if(!regs[i]&®_prio[i]>prio&®ok(i,f,mode)&&(!reg_pair(i,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){
+ r=i;
+ prio=reg_prio[i];
+ }
+ }
+ if(r){
+ if(DEBUG&16) printf("alloc %s\n",regnames[r]);
+ alloc_hardreg(r);
+ return r;
+ }
+ if(DEBUG&1) printf("Couldn't allocate register for type %d\n",f);
+ return 0;
+}
+void free_reg(int r)
+/* Gibt Register r frei */
+{
+ IC *new;
+ if(!r||nocode) return;
+ if(regs[r]==0&&!cross_module)
+ {printf("Register %d(%s):\n",r,regnames[r]);ierror(0);}
+ if(DEBUG&16) printf("freed %s\n",regnames[r]);
+ new=new_IC();
+ new->code=FREEREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q1.reg=r;
+ new->q2.flags=new->z.flags=0;
+ regs[r]=0;
+ if(reg_pair(r,&rp)){
+ if(regs[rp.r1]&RHALF){
+ if(DEBUG&16) printf("keep %s\n",regnames[rp.r1]);
+ regs[rp.r1]&=~RHALF;
+ new->q1.reg=rp.r2;
+ }else
+ regs[rp.r1]=0;
+ if(regs[rp.r2]&RHALF){
+ if(DEBUG&16) printf("keep %s\n",regnames[rp.r2]);
+ regs[rp.r2]&=~RHALF;
+ new->q1.reg=rp.r1;
+ }else
+ regs[rp.r2]=0;
+ }
+ add_IC(new);
+}
+void gen_label(int l)
+/* Erzeugt ein Label */
+{
+ IC *new;
+ new=new_IC();
+ new->code=LABEL;
+ new->typf=l;
+ new->q1.flags=new->q2.flags=new->z.flags=0;
+ add_IC(new);
+}
+void gen_cond(obj *p,int m,int l1,int l2)
+/* Generiert code, der 0 oder 1 in Register schreibt. Schreibt obj nach p. */
+{
+ IC *new;
+ obj omerk;
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=INT;
+ new->q1.flags=KONST;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[INT];
+ if(!m) vmax=l2zm(1L); else vmax=l2zm(0L);
+ new->q1.val.vint=zm2zi(vmax);
+ get_scratch(&new->z,INT,0,0);
+ omerk=new->z;
+ add_IC(new);
+ new=new_IC();
+ new->code=BRA;
+ new->typf=l2;
+ add_IC(new);
+ gen_label(l1);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=INT;
+ new->q1.flags=KONST;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[INT];
+ if(!m) vmax=l2zm(0L); else vmax=l2zm(1L);
+ new->q1.val.vint=zm2zi(vmax);
+ new->z=omerk;
+/* new->z.reg=r;
+ new->z.flags=SCRATCH|REG;*/
+ add_IC(new);
+ gen_label(l2);
+ *p=omerk;
+}
+void scratch_var(obj *o,int t,type *typ)
+/* liefert eine temporaere Variable */
+/* nicht effizient, aber wer hat schon so wenig Register... */
+{
+ type *nt;
+ if(!ISSCALAR(t)&&!ISVECTOR(t)){
+ if(!typ) ierror(0);
+ nt=clone_typ(typ);
+ }else{
+ nt=new_typ();
+ nt->flags=t;
+ if(ISPOINTER(t)){
+ nt->next=new_typ();
+ nt->next->flags=VOID;
+ }
+ }
+ o->flags=SCRATCH|VAR;o->reg=0;
+ o->v=add_var(empty,nt,AUTO,0);
+ o->val.vmax=l2zm(0L);
+}
+void get_scratch(obj *o,int t1,int t2,type *typ)
+/* liefert ein Scratchregister oder eine Scratchvariable */
+{
+ if(!(optflags&2)&&(o->reg=allocreg(t1,t2))){
+ o->flags=SCRATCH|REG;
+ }else{
+ scratch_var(o,t1,typ);
+ }
+}
+int do_arith(np p,IC *new,np dest,obj *o)
+/* erzeugt IC new fuer einen arithmetischen Knoten und speichert das */
+/* Resultat vom Unterknoten dest in o (fuer a op= b) */
+/* liefert 0, wenn dest nicht gefunden */
+{
+ int f=0,mflags;
+ new->code=p->flags;
+ if(new->code==PMULT) new->code=MULT;
+ gen_IC(p->left,0,0);
+ if(dest&&p->left==dest){
+ *o=p->left->o;f++;
+ if(p->left->flags==BITFIELD){
+ *o=p->left->left->o;
+ if((o->flags&(REG|SCRATCH))==(REG|SCRATCH))
+ keep_reg(o->reg);
+ }
+ }
+ gen_IC(p->right,0,0);
+ if(dest&&p->right==dest) {*o=p->right->o;f++;}
+ if(dest){
+ mflags=dest->o.flags;
+ if(p->left->flags!=BITFIELD)
+ dest->o.flags&=(~SCRATCH);
+ }
+
+ if(ISPOINTER(p->left->ntyp->flags)&&ISPOINTER(p->right->ntyp->flags)){
+ /* Subtrahieren zweier Pointer */
+ int dt=PTRDIFF_T(p->left->ntyp->flags);
+ if(p->flags!=SUB) ierror(0);
+ new->typf=dt;
+ new->typf2=p->left->ntyp->flags;
+ new->code=SUBPFP;
+ new->q1=p->left->o;
+ new->q2=p->right->o;
+ if(!dest&&(p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->left->o.reg,dt,0)){
+ new->z=p->left->o;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ if(USEQ2ASZ&&(p->right->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->right->o.reg,dt,0)){
+ new->z=p->right->o;
+ new->z.flags&=(~DREFOBJ);
+ }else{
+ get_scratch(&new->z,dt,0,0);
+ }
+ }
+ p->o=new->z;
+ add_IC(new);
+ if(!zmleq(szof(p->left->ntyp->next),l2zm(1L))){
+ long ln;
+ new=new_IC();
+ new->q1=p->o;
+ new->q2.flags=KONST;
+ gval.vmax=szof(p->left->ntyp->next);
+ eval_const(&gval,MAXINT);
+ if(ln=get_pof2(vumax)){
+ /* Division immer ohne Rest, daher shift möglich */
+ /* TODO: Haben wir Targets ohne arith. shift right? */
+ gval.vmax=l2zm(ln-1);
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q2.val,INT);
+ new->typf2=INT;
+ new->code=RSHIFT;
+ }else{
+ insert_const(&new->q2.val,dt);
+ new->code=DIV;
+ }
+ new->z=p->o;
+ new->typf=dt;
+ add_IC(new);
+ }
+ if(dest) dest->o.flags=mflags;
+ return f;
+ }
+ if((p->flags==ADD||p->flags==SUB)&&(ISPOINTER(p->left->ntyp->flags)||ISPOINTER(p->right->ntyp->flags))){
+ /* Addieren und Subtrahieren eines Integers zu einem Pointer */
+ if(p->flags==ADD){
+ new->code=ADDI2P;
+ if(!ISPOINTER(p->left->ntyp->flags)){
+ np tmp=p->left;
+ p->left=p->right;
+ p->right=tmp;
+ }
+ }else
+ new->code=SUBIFP;
+ new->typf=p->right->ntyp->flags;
+ new->typf2=p->ntyp->flags;
+ new->q1=p->left->o;
+ /* kleinere Typen als MINADDI2P erst in diesen wandeln */
+ if(new->typf&UNSIGNED){
+ if((new->typf&NQ)<(MINADDUI2P&NQ)){convert(p->right,MINADDUI2P);new->typf=MINADDUI2P;}
+ }else{
+ if((new->typf&NQ)<MINADDI2P){convert(p->right,MINADDI2P);new->typf=MINADDI2P;}
+ }
+ /* groessere Typen als MAXADDI2P erst in diesen wandeln */
+ if(new->typf&UNSIGNED){
+ if((new->typf&NQ)>(MAXADDI2P&NQ)){convert(p->right,MAXADDUI2P);new->typf=MAXADDUI2P;}
+ }else{
+ if((new->typf&NQ)>MAXADDI2P){convert(p->right,MAXADDI2P);new->typf=MAXADDI2P;}
+ }
+ if((p->left->o.flags&VARADR)&&(p->right->o.flags&KONST)){
+ eval_const(&p->right->o.val,p->right->ntyp->flags);
+ p->o=p->left->o;
+ p->o.val.vmax=zmadd(vmax,p->left->o.val.vmax);
+ free(new);
+ return f;
+ }
+ new->q2=p->right->o;
+ if(!dest&&(p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(new->q1.reg,POINTER_TYPE(p->left->ntyp->next),p->left->ntyp->next->flags)){
+ new->z=p->left->o;
+ new->z.flags&=(~DREFOBJ);
+ }else{
+ /*get_scratch(&new->z,POINTER_TYPE(p->left->ntyp->next),p->left->ntyp->next->flags,0);*/
+ get_scratch(&new->z,p->ntyp->flags,p->ntyp->next->flags,0);
+ }
+ p->o=new->z;
+ add_IC(new);
+ if(dest) dest->o.flags=mflags;
+ return f;
+ }
+ if(!ISVECTOR(p->ntyp->flags)||!ISVECTOR(p->left->ntyp->flags))
+ convert(p->left,p->ntyp->flags);
+ if(p->flags==LSHIFT||p->flags==RSHIFT){
+ if(shortcut(p->flags,p->left->ntyp->flags&NU)){
+ convert(p->right,p->right->ntyp->flags);
+ new->typf2=p->right->ntyp->flags;
+ }else{
+ convert(p->right,INT);
+ new->typf2=INT;
+ }
+#if 0
+ type *st;
+ st=clone_typ(p->right->ntyp);
+ /*st->flags=int_erw(st->flags);*/
+ st->flags=INT;
+ convert(p->right,st->flags);
+ new->typf2=st->flags;
+ freetyp(st);
+#endif
+ }else{
+ if(!ISVECTOR(p->ntyp->flags)||!ISVECTOR(p->right->ntyp->flags))
+ convert(p->right,p->ntyp->flags);
+ }
+ new->q1=p->left->o;
+ new->q2=p->right->o;
+ if(ISVECTOR(p->ntyp->flags)){
+ new->typf=p->left->ntyp->flags;
+ new->typf2=p->ntyp->flags;
+ }else
+ new->typf=p->ntyp->flags;
+ /* Bei dest!=0, d.h. ASSIGNOP, darf q1 nicht als Ziel benuzt werden! */
+ if(!dest&&(new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(new->q1.reg,p->ntyp->flags,0)){
+ new->z=new->q1;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ if((new->q2.flags&SCRATCH)&®ok(new->q2.reg,p->ntyp->flags,0)){
+ if((p->flags>=OR&&p->flags<=AND)||p->flags==ADD||p->flags==MULT||p->flags==PMULT){
+ /* bei kommutativen Operatoren vertauschen */
+ new->z=new->q2;
+ new->q2=new->q1;
+ new->q1=new->z;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ if(USEQ2ASZ){
+ new->z=new->q2;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ get_scratch(&new->z,new->typf,0,0);
+ }
+ }
+ }else{
+ get_scratch(&new->z,new->typf,0,0);
+ }
+ }
+ p->o=new->z;
+ add_IC(new);
+ if(dest){
+ dest->o.flags=mflags;
+ /*
+ if((dest->o.flags®)&&!regs[dest->o.reg])
+ keep_reg(dest->o.reg);
+ */
+ }
+
+ return f;
+}
+void savescratch(int code,IC *p,int dontsave,obj *o)
+/* speichert Scratchregister bzw. stellt sie wieder her (je nach code */
+/* entweder MOVEFROMREG oder MOVETOREG) */
+{
+ int i,s,e,b,ds1,ds2;IC *new;
+ if(code==MOVETOREG){ s=1;e=MAXR+1;b=1;} else {s=MAXR;e=0;b=-1;}
+ if(reg_pair(dontsave,&rp)){
+ ds1=rp.r1;
+ ds2=rp.r2;
+ }else
+ ds1=ds2=0;
+ for(i=s;i!=e;i+=b){
+ int mustsave=0;
+ if((o->flags&(VAR|DREFOBJ))==VAR&&o->v->fi&&(o->v->fi->flags&ALL_REGS))
+ mustsave=BTST(o->v->fi->regs_modified,i);
+ else
+ mustsave=regscratch[i];
+ if(regsa[i]) mustsave=0;
+ if(mustsave) simple_scratch[i]=1;
+ if(regs[i]&&!(regs[i]&RNOSAVE)&&mustsave&&i!=dontsave&&i!=ds1&&i!=ds2&&!reg_pair(i,&rp)){
+ if(!regsbuf[i]){
+ type *t;
+ if(code!=MOVEFROMREG) continue;
+ t=clone_typ(regtype[i]);
+ regsbuf[i]=add_var(empty,t,AUTO,0);
+ regsbuf[i]->flags|=USEDASADR;
+ regbnesting[i]=nesting;
+ }
+ new=new_IC();
+ new->typf=new->q2.flags=0;
+ new->line=0;new->file=0;
+ new->code=code;
+ if(code==MOVEFROMREG){
+ new->q1.flags=REG;new->q1.reg=i;
+ new->z.flags=VAR|DONTREGISTERIZE;new->z.v=regsbuf[i];
+ new->z.val.vmax=l2zm(0L);
+ }else{
+ new->z.flags=REG;new->z.reg=i;
+ new->q1.flags=VAR|DONTREGISTERIZE;new->q1.v=regsbuf[i];
+ new->q1.val.vmax=l2zm(0L);
+ }
+ new->use_cnt=new->change_cnt=0;
+ new->use_list=new->change_list=0;
+ insert_IC(p,new);
+ }
+ }
+}
+
diff --git a/icn.c b/icn.c
new file mode 100755
index 0000000..4e4feab
--- /dev/null
+++ b/icn.c
@@ -0,0 +1,2104 @@
+/* $VER: vbcc (ic.c) V0.8 */
+
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+static struct IC *first_pushed;
+static unsigned int opushed;
+
+static int volatile_convert;
+
+int do_arith(np,struct IC *,np,struct obj *);
+
+static void handle_reglist(struct regargs_list *,struct obj *);
+
+void gen_test(struct obj *o,int t,int branch,int label)
+/* Generiert ein test o, branch label und passt auf, dass */
+/* kein TEST const generiert wird. */
+{
+ struct IC *new;
+ if(o->flags&KONST){
+ eval_const(&o->val,t);
+ if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
+ if(branch==BEQ) branch=BRA; else branch=0;
+ }else{
+ if(branch==BNE) branch=BRA; else branch=0;
+ }
+ }else{
+ new=new_IC();
+ new->code=TEST;
+ new->q2.flags=new->z.flags=0;
+ new->typf=t;
+ new->q1=*o;
+ add_IC(new);
+ }
+ if(branch){
+ new=new_IC();
+ new->code=branch;
+ new->typf=label;
+ add_IC(new);
+ }
+}
+
+void inline_memcpy(np z,np q,zmax size)
+/* fuegt ein ASSIGN-IC ein, das memcpy(z,q,size) entspricht */
+{
+ struct IC *new=new_IC();
+ if(!ISPOINTER(z->ntyp->flags)) ierror(0);
+ if(!ISPOINTER(q->ntyp->flags)) ierror(0);
+
+ if(z->flags==ADDRESS||z->flags==ADDRESSA||z->flags==ADDRESSS){
+ gen_IC(z,0,0);
+ new->z=z->left->o;
+ if(z->flags!=ADDRESSS&&z->left->flags==IDENTIFIER&&is_vlength(z->left->ntyp)){
+ /* variable length array */
+ new->z.flags|=DREFOBJ;
+ new->z.dtyp=POINTER_TYPE(z->ntyp->next);
+ }
+ }else{
+ gen_IC(z,0,0);
+ if(z->o.flags&DREFOBJ){
+ struct IC *n2=new_IC();
+ n2->code=ASSIGN;
+ n2->typf=q->ntyp->flags;
+ n2->q1=z->o;
+ get_scratch(&n2->z,z->ntyp->flags,z->ntyp->next->flags,z->ntyp);
+ n2->q2.flags=0;
+ n2->q2.val.vmax=sizetab[POINTER_TYPE(z->ntyp->next)];
+ new->z=n2->z;
+ add_IC(n2);
+ }else{
+ new->z=z->o;
+ }
+ if(new->z.flags&VARADR){
+ new->z.flags&=~VARADR;
+ }else{
+ new->z.flags|=DREFOBJ;
+ new->z.dtyp=POINTER_TYPE(z->ntyp->next);
+ }
+ }
+ if(q->flags==ADDRESS||q->flags==ADDRESSA||q->flags==ADDRESSS){
+ gen_IC(q,0,0);
+ new->q1=q->left->o;
+ if(q->flags!=ADDRESSS&&q->left->flags==IDENTIFIER&&is_vlength(q->left->ntyp)){
+ /* variable length array */
+ new->q1.flags|=DREFOBJ;
+ new->q1.dtyp=POINTER_TYPE(q->ntyp->next);
+ }
+ }else{
+ gen_IC(q,0,0);
+ if(q->o.flags&DREFOBJ){
+ struct IC *n2=new_IC();
+ n2->code=ASSIGN;
+ n2->typf=q->ntyp->flags;
+ n2->q1=q->o;
+ get_scratch(&n2->z,q->ntyp->flags,q->ntyp->next->flags,q->ntyp);
+ n2->q2.flags=0;
+ n2->q2.val.vmax=sizetab[POINTER_TYPE(q->ntyp->next)];
+
+ new->q1=n2->z;
+ add_IC(n2);
+ }else{
+ new->q1=q->o;
+ }
+ if(new->q1.flags&VARADR){
+ new->q1.flags&=~VARADR;
+ }else{
+ new->q1.flags|=DREFOBJ;
+ new->q1.dtyp=POINTER_TYPE(q->ntyp->next);
+ }
+ }
+ new->code=ASSIGN;
+ new->typf=UNSIGNED|CHAR;
+ new->q2.flags=0;
+ new->q2.val.vmax=size;
+ add_IC(new);
+}
+
+void add_IC(struct IC *new)
+/* fuegt ein IC ein */
+{
+ int code;
+ if(!new) return;
+ if(nocode) {
+#ifdef HAVE_MISRA
+ misra_neu(52,14,1,-1);
+#endif
+ free(new);return;}
+ new->next=0;
+ new->q1.am=new->q2.am=new->z.am=0;
+ new->line=line; new->file=filename;
+ code=new->code;
+ if(code>=BEQ&&code<=BRA) new->q1.flags=new->q2.flags=new->z.flags=0;
+ if(code==ALLOCREG||code==FREEREG||code==SAVEREGS||code==RESTOREREGS) new->typf=0;
+ if(DEBUG&64){ pric(stdout,first_ic);printf("new\n");pric2(stdout,new);printf("-\n");}
+ if(new->q1.flags&VAR){
+ if(!new->q1.v) ierror(0);
+ new->q1.v->flags|=USEDASSOURCE;
+ if(code==ADDRESS||(new->q1.flags&VARADR))
+ if(!is_vlength(new->q1.v->vtyp))
+ new->q1.v->flags|=USEDASADR;
+ new->q1.v->priority+=currentpri;
+ }
+ if(new->q2.flags&VAR){
+ if(!new->q2.v) ierror(0);
+ new->q2.v->flags|=USEDASSOURCE;
+ if(code==ADDRESS||(new->q2.flags&VARADR))
+ if(!is_vlength(new->q2.v->vtyp))
+ new->q2.v->flags|=USEDASADR;
+ new->q2.v->priority+=currentpri;
+ }
+ if(new->z.flags&VAR){
+ if(!new->z.v) ierror(0);
+ if(new->z.flags&DREFOBJ)
+ new->z.v->flags|=USEDASSOURCE;
+ else
+ new->z.v->flags|=USEDASDEST;
+ new->z.v->priority+=currentpri;
+ }
+ if(block_vla[nesting]){
+ /* special handling for blocks with variable-length arrays */
+ struct llist *p;
+ if(new->code==LABEL){
+ p=mymalloc(LSIZE);
+ p->label=new->typf;
+ p->next=vladeflabels[nesting];
+ vladeflabels[nesting]=p;
+ }else if(0&&new->code==BRA&&!(new->flags&LOOP_COND_TRUE)){
+ p=mymalloc(LSIZE);
+ p->label=new->typf;
+ p->next=vlajmplabels[nesting];
+ vlajmplabels[nesting]=p;
+ p=vladeflabels[nesting];
+ while(p){
+ if(p->label==new->typf)
+ break;
+ p=p->next;
+ }
+ if(!p){
+ /* label not declared in this block so far;
+ re-adjust stack, but store the position - label may be
+ declared later in the same block and adjustement must be
+ removed */
+ struct vlaadjust_list *vl;
+ struct IC *first;
+ first=last_ic;
+ freevl();
+ first=first->next;
+ vl=mymalloc(sizeof(*vl));
+ vl->branch=new;
+ vl->first=first;
+ vl->next=vlaadjusts[nesting];
+ vlaadjusts[nesting]=vl;
+ }
+ }
+ }
+ if(/*(c_flags_val[0].l&2)&&*/code==LABEL){
+ /* entfernt Spruenge zu direkt folgenden Labels */
+ struct IC *p=last_ic;
+ while(p){
+ if(p->typf==new->typf&&p->code>=BEQ&&p->code<=BRA){
+ struct IC *n;
+ if(p->code!=BRA){
+ struct IC *cmp=p->prev;
+ while(cmp&&cmp->code==FREEREG) cmp=cmp->prev;
+ if(cmp->code==TEST){
+ if(is_volatile_obj(&cmp->q1))
+ break;
+ else{
+ if(DEBUG&1) printf("preceding test removed\n");
+ remove_IC(cmp);
+ }
+ }else if(cmp->code==COMPARE){
+ if(is_volatile_obj(&cmp->q1)||is_volatile_obj(&cmp->q2))
+ break;
+ else{
+ if(DEBUG&1) printf("preceding compare removed\n");
+ remove_IC(cmp);
+ }
+ }else
+ break;
+ }
+ if(vlaadjusts[nesting]){
+ /* remove it from vlaadjusts-lists, if necessary */
+ struct vlaadjust_list *vl=vlaadjusts[nesting];
+ while(vl){
+ if(vl->branch==p){
+ struct IC *np=vl->branch->prev;
+ while(np!=vl->first->prev){
+ if(!np) ierror(0);
+ np->code=NOP;
+ np->q1.flags=np->q2.flags=np->z.flags=0;
+ np=np->prev;
+ }
+ vl->branch=0;
+ }
+ vl=vl->next;
+ }
+ }
+ if(DEBUG&1) printf("%s l%d deleted\n",ename[p->code],p->typf);
+ n=p->next;
+ remove_IC(p);
+ p=n;
+ }else{
+ if(p->code!=LABEL) break;
+ p=p->prev;
+ }
+ }
+ }
+ if(last_ic){
+ if(code==ASSIGN){
+ if((last_ic->z.flags&(REG|SCRATCH|DREFOBJ))==(REG|SCRATCH)&&(new->q1.flags==last_ic->z.flags)&&last_ic->z.reg==new->q1.reg/*&&last_ic->code!=CALL*/){
+ if(USEQ2ASZ||!(last_ic->q2.flags®)||!(new->z.flags®)||last_ic->q2.reg!=new->z.reg){
+ if(USEQ2ASZ||!(last_ic->q2.flags&VAR)||!(new->z.flags&VAR)||last_ic->q2.v!=new->z.v){
+ /* verbindet op a,b->reg,move reg->c zu op a,b->c */
+ /* hier fehlt aber noch Registerfreigabe */
+ last_ic->z=new->z;
+ if(DEBUG&1) printf("move and op combined\n");
+ if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags®)))
+ free_reg(new->q1.reg);
+ free(new);
+ return;
+ }
+ }
+ }
+ if((last_ic->z.flags&(VAR|SCRATCH|DREFOBJ))==(VAR|SCRATCH)&&(new->q1.flags==last_ic->z.flags)&&last_ic->z.v==new->q1.v/*&&last_ic->code!=CALL*/){
+ if(USEQ2ASZ||!(last_ic->q2.flags®)||!(new->z.flags®)||last_ic->q2.reg!=new->z.reg){
+ if(USEQ2ASZ||!(last_ic->q2.flags&VAR)||!(new->z.flags&VAR)||last_ic->q2.v!=new->z.v){
+ /* verbindet op a,b->scratch,move scratch->c zu op a,b->c */
+ /* hier fehlt aber noch Registerfreigabe */
+ last_ic->z=new->z;
+ if(DEBUG&1) printf("move and op combined(2)\n");
+/* if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags®)))
+ free_reg(new->q1.reg);*/
+ free(new);
+ return;
+ }
+ }
+ }
+
+ }
+ if(last_ic->code==BRA){
+ if(code!=LABEL&&code!=ALLOCREG&&code!=FREEREG){
+ /* loescht alles nach bra bis ein Label kommt */
+ /* momentan noch nicht perfekt, da es bei alloc/freereg stoppt */
+ free(new);
+#ifdef HAVE_MISRA
+ misra_neu(52,14,1,-1);
+#endif
+ if(DEBUG&1) printf("Unreachable Statement deleted\n");
+ return;
+ }
+ if(last_ic->prev&&code==LABEL){
+ /* ersetzt bcc l1;bra l2;l1 durch b!cc l2 */
+ if(last_ic->prev->code>=BEQ&&last_ic->prev->code<=BGT&&new->typf==last_ic->prev->typf){
+ if(last_ic->next) pric2(stdout,last_ic->next);
+ if(DEBUG&1) printf("%s l%d;%s l%d; substituted\n",ename[last_ic->prev->code],last_ic->prev->typf,ename[last_ic->code],last_ic->typf);
+ if(last_ic->prev->code&1)
+ last_ic->prev->code--;
+ else
+ last_ic->prev->code++;
+ last_ic->prev->typf=last_ic->typf;
+ last_ic=last_ic->prev;
+ free(last_ic->next);
+ last_ic->next=new;new->prev=last_ic;
+ last_ic=new;
+ return;
+ }
+ }
+ }
+/* }*/
+ new->prev=last_ic;
+ last_ic->next=new;
+ last_ic=new;
+ }else{
+ last_ic=new;first_ic=new;new->prev=0;
+ }
+ ic_count++;
+ /* Merken, on Fliesskomma benutzt wurde */
+ if(code!=LABEL&&(code<BEQ||code>BRA)){
+ if(ISFLOAT(new->typf)) float_used=1;
+ if(code==CONVERT&&ISFLOAT(new->typf2)) float_used=1;
+ }
+ if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags®)))
+ free_reg(new->q1.reg);
+ if((new->q2.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q2.reg!=new->z.reg||!(new->z.flags®)))
+ free_reg(new->q2.reg);
+}
+
+np gen_libcall(char *fname,np arg1,struct Typ *t1,np arg2,struct Typ *t2)
+/* generate call to a library function (emulate operation) */
+{
+ np new;
+ struct argument_list *al=0,*t;
+ new=mymalloc(NODES);
+ new->flags=CALL;
+ new->right=0;
+ new->left=mymalloc(NODES);
+ new->left->flags=IDENTIFIER;
+ new->left->left=new->left->right=0;
+ new->left->identifier=add_identifier(fname,strlen(fname));
+ new->left->ntyp=0;
+ new->left->sidefx=0;
+ new->left->val.vmax=l2zm(0L);
+ new->alist=0;
+ if(arg1){
+ al=mymalloc(sizeof(*al));
+ al->arg=arg1;
+ al->next=0;
+ if(t1){
+ np cnv=mymalloc(NODES);
+ cnv->flags=CAST;
+ cnv->left=arg1;
+
+ cnv->right=0;
+ cnv->ntyp=t1;
+ al->arg=cnv;
+ }
+ }
+ if(arg2){
+ t=mymalloc(sizeof(*t));
+ t->arg=arg2;
+ t->next=0;
+ al->next=t;
+ if(t2){
+ np cnv=mymalloc(NODES);
+ cnv->flags=CAST;
+ cnv->left=arg2;
+ cnv->right=0;
+ cnv->ntyp=t2;
+ t->arg=cnv;
+ }
+ }
+ new->alist=al;
+ /* Kann man type_expr nochmal auf die Argumente anwenden? */
+ if(!type_expression(new))
+ ierror(0);
+ gen_IC(new,0,0);
+ return new;
+}
+
+
+void gen_IC(np p,int ltrue,int lfalse)
+/* Erzeugt eine IC-Liste aus einer expression */
+{
+ struct IC *new; struct regargs_list *rl;
+ if(!p) return;
+ if(p->flags==STRING){
+ /* hier fehlt noch die Verwaltung der String-Inhalte */
+ p->o.v=add_var(empty,clone_typ(p->ntyp),STATIC,p->cl);
+ p->o.v->flags|=DEFINED;
+ p->o.flags=VAR;
+ p->o.reg=0;
+ p->o.val=p->val;
+ return;
+ }
+ if(p->flags==IDENTIFIER){
+/* p->o.v=find_var(p->identifier,0);*/
+ p->o.flags=VAR;
+ p->o.reg=0;
+ p->o.val=p->val;
+ return;
+ }
+ if(p->flags==CEXPR||p->flags==PCEXPR){
+ if(p->left){
+ if(p->left->flags==POSTINC) p->left->flags=PREINC;
+ if(p->left->flags==POSTDEC) p->left->flags=PREDEC;
+ gen_IC(p->left,0,0);
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+ }
+ if(p->right){
+ if(p->right->flags==POSTINC) p->right->flags=PREINC;
+ if(p->right->flags==POSTDEC) p->right->flags=PREDEC;
+ gen_IC(p->right,0,0);
+ if((p->right->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->right->o.reg);
+ }
+ p->o.flags=KONST;
+ p->o.val=p->val;
+ p->o.reg=0;
+ return;
+ }
+ if(p->flags==KOMMA){
+ if(p->left->sidefx){
+ gen_IC(p->left,0,0);
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+ }else if(!(p->left->ntyp->flags&VOLATILE))
+ error(129);
+ gen_IC(p->right,0,0);
+ p->o=p->right->o;
+ return;
+ }
+ if(p->flags==CAST){
+ gen_IC(p->left,0,0);
+ if((p->ntyp->flags&NQ)==VOID){
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg);
+ p->o.flags=0;
+ }else{
+ if(ISPOINTER(p->ntyp->flags)&&(p->ntyp->next->flags&VOLATILE))
+ volatile_convert=1;
+ convert(p->left,p->ntyp->flags);
+ if(volatile_convert){
+ if(!(p->left->o.flags&VAR))
+ ierror(0);
+ if(!p->left->o.v->vtyp->next)
+ ierror(0);
+ p->left->o.v->vtyp->next->flags|=VOLATILE;
+ volatile_convert=0;
+ }
+ p->o=p->left->o;
+ }
+ return;
+ }
+ if(p->flags==FIRSTELEMENT){
+ gen_IC(p->left,0,0);
+ p->o=p->left->o;
+ return;
+ }
+#if HAVE_LIBCALLS
+ { char *libname;
+ if(libname=use_libcall(p)){
+ np lc;struct Typ *t1,*t2;
+ if(p->flags==LSHIFT||p->flags==RSHIFT){
+ t1=clone_typ(p->ntyp);
+ t2=new_typ();
+ t2->flags=INT;
+ }else{
+ t1=arith_typ(p->left->ntyp,p->right->ntyp);
+ t2=clone_typ(t1);
+ }
+ lc=gen_libcall(libname,p->left,t1,p->right,t2);
+ *p=*lc;
+ free(lc);
+ return;
+ }
+ }
+#endif
+ new=new_IC();
+ new->typf=p->ntyp->flags;
+ new->q1.reg=new->q2.reg=new->z.reg=0;
+ new->q1.flags=new->q2.flags=new->z.flags=0;
+ if((p->flags>=LSHIFT&&p->flags<=MOD)||(p->flags>=OR&&p->flags<=AND)||p->flags==PMULT){
+ do_arith(p,new,0,0);
+ return;
+ }
+ if(p->flags==CONTENT){
+ gen_IC(p->left,0,0);
+ if(p->left->o.flags&VARADR){
+ free(new);
+ p->o=p->left->o;
+ p->o.flags&=~VARADR;
+ return;
+ }
+ if(!(p->left->o.flags&DREFOBJ)){
+ free(new);
+ p->o=p->left->o;
+ p->o.flags|=DREFOBJ;
+ p->o.dtyp=p->left->ntyp->flags;
+ }else{
+ if((p->left->o.flags&SCRATCH)&&p->left->o.dtyp==POINTER_TYPE(p->ntyp)){
+ new->z=p->left->o;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ get_scratch(&new->z,p->left->ntyp->flags,p->ntyp->flags,p->left->ntyp);
+ }
+ new->code=ASSIGN;new->typf=POINTER_TYPE(p->ntyp);
+ new->q1=p->left->o;
+ new->q2.val.vmax=sizetab[new->typf];
+ p->o=new->z;
+ add_IC(new);
+ p->o.flags|=DREFOBJ;
+ p->o.dtyp=POINTER_TYPE(p->ntyp);
+ }
+ return;
+ }
+ if(p->flags==ASSIGN){
+ new->code=ASSIGN;
+ gen_IC(p->right,0,0);
+ gen_IC(p->left,0,0);
+ convert(p->right,p->ntyp->flags);
+ new->q1=p->right->o;
+ new->z=p->left->o;
+ new->q2.val.vmax=szof(p->left->ntyp);
+ p->o=new->z;
+ add_IC(new);
+ return;
+ }
+ if(p->flags==ASSIGNOP){
+ /* das hier ist nicht besonders schoen */
+ struct obj o,q;struct IC *n;int f;char *libname;
+ if(p->right->right==0){
+ /* sowas wie a+=0 wurde wegoptimiert */
+ free(new);
+ p->o=p->left->o;
+ return;
+ }
+#if HAVE_LIBCALLS
+ if(libname=use_libcall(p->right)){
+ np lc;struct Typ *t1,*t2;
+ t1=clone_typ(p->ntyp);
+ if(p->right->flags==LSHIFT||p->right->flags==RSHIFT){
+ t2=new_typ();
+ t2->flags=INT;
+ }else
+ t2=clone_typ(p->ntyp);
+ lc=gen_libcall(libname,p->right->left,t1,p->right->right,t2);
+ *p->right=*lc;
+ o=p->left->o;
+ p->left=0;
+ free(lc);
+ }else
+#endif
+ {
+ f=do_arith(p->right,new,p->left,&o);
+ if(!f) ierror(0);
+ if(f>1) ierror(0);
+ }
+ if(!nocode&&(o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&!regs[o.reg]){
+ /* ueberfluessiges FREEREG entfernen */
+ n=last_ic;
+ while(n){
+ if(!nocode&&n->code==CALL&®scratch[o.reg]){
+ struct IC *ret;
+ regs[o.reg]=1;
+ savescratch(MOVEFROMREG,n->prev,0,&n->q1);
+ ret=n->next;
+ while(ret->code==ALLOCREG||ret->code==FREEREG)
+ ret=ret->next;
+ if(ret->code==GETRETURN){
+ if((ret->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ret->z.reg==o.reg) ret->z.flags&=~REG;
+ }else
+ ret=ret->prev;
+ savescratch(MOVETOREG,ret,0,&n->q1);
+ }
+ if(n->code==FREEREG&&n->q1.reg==o.reg){
+ remove_IC(n);if(!nocode) regs[o.reg]=1;
+ break;
+ }
+ n=n->prev;
+ }
+ }
+ convert(p->right,p->ntyp->flags);
+ new=new_IC();
+ new->typf=p->ntyp->flags;
+ new->q2.flags=0;
+ new->code=ASSIGN;
+ new->q1=p->right->o;
+ new->z=o;
+ new->q2.val.vmax=szof(p->ntyp);
+ p->o=new->z;
+ add_IC(new);
+ return;
+ }
+ if(p->flags==MINUS||p->flags==KOMPLEMENT){
+ new->code=p->flags;
+ gen_IC(p->left,0,0);
+ convert(p->left,p->ntyp->flags);
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->left->o.reg,p->ntyp->flags,0)){
+ new->z=p->left->o;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ get_scratch(&new->z,p->left->ntyp->flags,0,p->left->ntyp);
+ }
+ new->q1=p->left->o;
+ p->o=new->z;
+ add_IC(new);
+ return;
+ }
+ if(p->flags==ADDRESS||p->flags==ADDRESSA||p->flags==ADDRESSS){
+ if(p->flags!=ADDRESSS&&p->left->flags==IDENTIFIER&&is_vlength(p->left->ntyp)){
+ gen_IC(p->left,0,0);
+ if(!(p->left->o.flags&VAR))
+ ierror(0);
+ free(new);
+ p->o=p->left->o;
+ return;
+ }
+ new->code=ADDRESS;
+ new->typf=p->left->ntyp->flags;
+ new->typf2=POINTER_TYPE(p->left->ntyp);
+ gen_IC(p->left,0,0);
+ if(p->left->o.flags&VAR) p->left->o.v->flags|=(USEDASSOURCE|USEDASDEST);
+ if(p->left->o.flags&DREFOBJ){
+ free(new);
+ p->o=p->left->o;
+ p->o.flags&=~DREFOBJ;
+ return;
+ }
+ if((p->left->o.flags&VAR)&&!(p->left->o.flags&VARADR)
+ &&(p->left->o.v->storage_class==EXTERN||p->left->o.v->storage_class==STATIC)){
+ free(new);
+ p->o=p->left->o;
+ p->o.flags|=VARADR;
+ return;
+ }
+ new->q1=p->left->o;
+ get_scratch(&new->z,POINTER_TYPE(p->ntyp->next),p->ntyp->next->flags,0);
+ p->o=new->z;
+ add_IC(new);
+ return;
+ }
+ if(p->flags==LAND||p->flags==LOR){
+ int l1,l2,l3,l4;
+/* printf("%s true=%d false=%d\n",ename[p->flags],ltrue,lfalse);*/
+ l1=++label;
+ if(!ltrue) {l2=++label;l3=++label;l4=++label;}
+ if(!ltrue){
+ if(p->flags==LAND)
+ gen_IC(p->left,l1,l3);
+ else
+ gen_IC(p->left,l3,l1);
+ }else{
+ if(p->flags==LAND)
+ gen_IC(p->left,l1,lfalse);
+ else
+ gen_IC(p->left,ltrue,l1);
+ }
+ if(p->left->o.flags!=0){
+ if(p->flags==LAND)
+ gen_test(&p->left->o,p->left->ntyp->flags,BEQ,((!ltrue)?l3:lfalse));
+ else
+ gen_test(&p->left->o,p->left->ntyp->flags,BNE,((!ltrue)?l3:ltrue));
+ }
+ gen_label(l1);
+ if(!ltrue){
+ if(p->flags==LAND)
+ gen_IC(p->right,l2,l3);
+ else
+ gen_IC(p->right,l3,l2);
+ }else
+ gen_IC(p->right,ltrue,lfalse);
+ if(p->right->o.flags!=0){
+ if(p->flags==LAND)
+ gen_test(&p->right->o,p->right->ntyp->flags,BEQ,((!ltrue)?l3:lfalse));
+ else
+ gen_test(&p->right->o,p->right->ntyp->flags,BNE,((!ltrue)?l3:ltrue));
+ }
+ if(!ltrue){
+ gen_label(l2);
+ if(p->flags==LAND) gen_cond(&p->o,0,l3,l4); else gen_cond(&p->o,1,l3,l4);
+ }else{
+ new=new_IC();
+ new->code=BRA;
+ if(p->flags==LAND) new->typf=ltrue; else new->typf=lfalse;
+ add_IC(new);
+ }
+ if(ltrue) p->o.flags=0;
+ return;
+ }
+ if(p->flags==NEGATION){
+ int l1,l2,l3;
+ if(!ltrue) {l1=++label;l2=++label;l3=++label;}
+ if(ltrue)
+ gen_IC(p->left,lfalse,ltrue);
+ else
+ gen_IC(p->left,l1,l3);
+ if(!p->left->o.flags){
+ free(new);p->o.flags=0;
+ }else{
+ gen_test(&p->left->o,p->left->ntyp->flags,BNE,((!ltrue)?l1:lfalse));
+ }
+ if(ltrue){
+ new=new_IC();
+ new->code=BRA;
+ if(!ltrue) new->typf=l2; else new->typf=ltrue;
+ add_IC(new);
+ p->o.flags=0;
+ }else{
+ gen_label(l3);
+ gen_cond(&p->o,0,l1,l2);
+ }
+ return;
+ }
+ if(p->flags>=EQUAL&&p->flags<=GREATEREQ){
+ int l1,l2,l3,tl,tr;
+ if(!ltrue) {l1=++label;l2=++label;l3=++label;}
+ if(p->left->flags==CEXPR){
+ /* Konstanten nach rechts */
+ np merk;merk=p->left;p->left=p->right;p->right=merk;
+ if(p->flags==LESS) p->flags=GREATER;
+ else if(p->flags==LESSEQ) p->flags=GREATEREQ;
+ else if(p->flags==GREATER) p->flags=LESS;
+ else if(p->flags==GREATEREQ) p->flags=LESSEQ;
+ }
+ new->code=COMPARE;
+ tl=p->left->ntyp->flags&NU;tr=p->right->ntyp->flags&NU;
+ if(p->right->flags==CEXPR&&ISINT(tr)&&ISINT(tl)){
+ int negativ;
+ eval_constn(p->right);
+ if(zmleq(vmax,l2zm(0L))) negativ=1; else negativ=0;
+ if((tl&UNSIGNED)||(tr&UNSIGNED)) negativ=0;
+ if((!negativ||zmleq(t_min(tl),vmax))&&(negativ||zumleq(vumax,t_max(tl)))){
+ convert(p->right,tl);
+ tr=tl;
+ }
+ }
+ if(ISARITH(tl)&&(tl!=tr||!shortcut(COMPARE,tl))){
+ struct Typ *t;
+ t=arith_typ(p->left->ntyp,p->right->ntyp);
+ new->typf=t->flags;
+ freetyp(t);
+ }else{
+ new->typf=p->left->ntyp->flags;
+ }
+ gen_IC(p->left,0,0);
+ convert(p->left,new->typf);
+ gen_IC(p->right,0,0);
+ convert(p->right,new->typf);
+ new->q1=p->left->o;
+ new->q2=p->right->o;
+ new->z.flags=0;
+ if(p->flags==EQUAL||p->flags==INEQUAL){
+ /* generate TEST, if possible */
+ if(new->q2.flags&KONST){
+ eval_const(&new->q2.val,new->typf);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+ new->code=TEST;
+ new->q2.flags=0;
+ }
+ }
+ }
+ add_IC(new);
+ new=new_IC();
+ if(p->flags==EQUAL) new->code=BEQ;
+ if(p->flags==INEQUAL) new->code=BNE;
+ if(p->flags==LESS) new->code=BLT;
+ if(p->flags==LESSEQ) new->code=BLE;
+ if(p->flags==GREATER) new->code=BGT;
+ if(p->flags==GREATEREQ) new->code=BGE;
+ if(ltrue) new->typf=ltrue; else new->typf=l1;
+ add_IC(new);
+ if(ltrue){
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lfalse;
+ add_IC(new);
+ p->o.flags=0;
+ }else{
+ gen_label(l3);
+ gen_cond(&p->o,1,l1,l2);
+ }
+ return;
+ }
+ if(p->flags==CALL){
+ int r=0;struct obj *op,cfunc,ret_obj;zmax sz;
+ int mregs[MAXR+1];
+ struct IC *callic;
+#ifdef ORDERED_PUSH
+ struct IC *merk_fp,*lp;
+ unsigned int merk_opushed=opushed;
+#endif
+ if(p->left->flags==ADDRESS&&p->left->left->flags==IDENTIFIER){
+ struct Var *v;
+ gen_IC(p->left,0,0); r=1;
+ v=p->left->o.v;
+ if(v->fi&&v->fi->first_ic&&!cross_module&&(c_flags_val[0].l&4096)){
+ /* function call inlining */
+ struct argument_list *al;
+ struct Var *vp,**argl1,**argl2;
+ struct IC *ip;int lc;
+ int arg_cnt=0,i;
+ if(DEBUG&1024){
+ printf("inlining call to <%s>\n",v->identifier);
+ for(vp=v->fi->vars;vp;vp=vp->next)
+ printf("%s(%ld)/%p\n",vp->identifier,zm2l(vp->offset),(void*)vp);
+ }
+ for(vp=v->fi->vars;vp;vp=vp->next){
+ /*FIXME: zmeqto hier ok? siehe cross_module_inline */
+ if((zmeqto(vp->offset,l2zm(0L))||vp->reg)&&*vp->identifier&&(vp->storage_class==AUTO||vp->storage_class==REGISTER)) arg_cnt++;
+ }
+
+ /* Argumente in die ersten Parametervariablen kopieren */
+ argl1=mymalloc(arg_cnt*sizeof(struct Var *));
+ argl2=mymalloc(arg_cnt*sizeof(struct Var *));
+
+ al=p->alist;vp=v->fi->vars;i=0;
+ while(al){
+ /*FIXME: zmeqto hier ok? siehe cross_module_inline */
+ while(vp&&(!*vp->identifier||(!zmeqto(vp->offset,l2zm(0L))&&!vp->reg)||(vp->storage_class!=REGISTER&&vp->storage_class!=AUTO))) vp=vp->next;
+ if(!vp){ error(39); break; }
+ if(i>=arg_cnt) ierror(0);
+ if(DEBUG&1024) printf("arg: %s(%ld)\n",vp->identifier,zm2l(vp->offset));
+ argl1[i]=vp;
+ argl2[i]=add_var(empty,clone_typ(vp->vtyp),vp->storage_class,0);
+ if(!al->arg) ierror(0);
+ gen_IC(al->arg,0,0);
+ convert(al->arg,vp->vtyp->flags);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->q1=al->arg->o;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(vp->vtyp);
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ new->z.v=argl2[i];
+ new->typf=vp->vtyp->flags;
+ add_IC(new);
+ i++;
+ al=al->next;
+ vp=vp->next;
+ }
+ if(i<arg_cnt){ error(83); arg_cnt=i;}
+
+ /* Kopien der Variablen erzeugen */
+ for(vp=v->fi->vars;vp;vp=vp->next){
+ vp->inline_copy=0;
+ }
+ for(i=0;i<arg_cnt;i++){
+ if(argl1[i]){
+ if(!argl2[i]) ierror(0);
+ argl1[i]->inline_copy=argl2[i];
+ }
+ }
+
+ /* Rueckgabewert */
+ if((p->ntyp->flags&NQ)!=VOID){
+ p->o.flags=SCRATCH|VAR;
+ p->o.reg=0;p->o.val.vmax=l2zm(0L);
+ p->o.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+ }else{
+ p->o.flags=0;
+ }
+
+ free(argl1);
+ free(argl2);
+
+ /* Code einfuegen und Labels umschreiben */
+ ip=v->fi->first_ic;lc=0;
+ while(ip){
+ struct Var *iv;
+ int c;
+ new=new_IC();
+ *new=*ip;
+ ip->copy=new;
+ c=ip->code;
+ /* evtl. ist ein IC praktisch ein SETRETURN, falls das */
+ /* Rueckgabeziel ueber Parameterzeiger angespr. wird */
+ if(ip->z.flags&VAR){
+ iv=ip->z.v;
+ if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+ if(!*iv->identifier&&zmeqto(iv->offset,l2zm(0L))){
+ new->z=p->o;
+ }else{
+ if(!iv->inline_copy){
+ iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+ iv->inline_copy->reg=iv->reg;
+ }
+ new->z.v=iv->inline_copy;
+ }/*else if(iv->inline_copy) ierror(0);*/
+ }
+ }
+ /* Kopien aller auto/register Variablen erzeugen */
+ if(ip->q1.flags&VAR){
+ iv=ip->q1.v;
+ if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+ if(!iv->inline_copy){
+ iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+ iv->inline_copy->reg=iv->reg;
+ }
+ new->q1.v=iv->inline_copy;
+ }/*else if(iv->inline_copy) ierror(0);*/
+ }
+ if(ip->q2.flags&VAR){
+ iv=ip->q2.v;
+ if(iv->storage_class==AUTO||iv->storage_class==REGISTER){
+ if(!iv->inline_copy){
+ iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0);
+ iv->inline_copy->reg=iv->reg;
+ }
+ new->q2.v=iv->inline_copy;
+ }/*else if(iv->inline_copy) ierror(0);*/
+ }
+ if(c==CALL){
+ int i;
+ function_calls+=currentpri;
+ new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+ for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=ip->arg_list[i]->copy;
+ }
+ if(c==LABEL||(c>=BEQ&&c<=BRA)){
+ if(new->typf>lc) lc=new->typf;
+ new->typf+=label;
+ }
+ if(c==SETRETURN){
+ new->code=ASSIGN;
+ new->z=p->o;
+ }
+ add_IC(new);
+ ip=ip->next;
+ }
+ label+=lc;
+ return;
+ }
+ /* einige spezielle Inline-Funktionen; das setzt voraus, dass */
+ /* diese in den Headerfiles passend deklariert werden */
+ if(v->storage_class==EXTERN){
+ if((optflags&2)&&!strcmp(v->identifier,"strlen")&&p->alist&&p->alist->arg){
+ np n=p->alist->arg;
+ if(n->flags==ADDRESSA&&n->left->flags==STRING&&zmeqto(n->left->val.vmax,l2zm(0L))){
+ struct const_list *cl;zumax len=ul2zum(0UL);
+ cl=n->left->cl;
+ while(cl){
+ if(zmeqto(l2zm(0L),zc2zm(cl->other->val.vchar))) break;
+ len=zumadd(len,ul2zum(1UL));
+ cl=cl->next;
+ }
+ p->o.val.vumax=len;
+ eval_const(&p->o.val,UNSIGNED|MAXINT);
+ insert_constn(p);
+ insert_const(&p->o.val,p->ntyp->flags);
+ p->flags=CEXPR;
+ p->o.flags=KONST;
+ return;
+ }
+ }
+
+ if(INLINEMEMCPY>0&&(optflags&2)){
+ if(!strcmp(v->identifier,"strcpy")&&p->alist&&p->alist->next&&p->alist->next->arg){
+ np n=p->alist->next->arg;
+ if(n->flags==ADDRESSA&&n->left->flags==STRING&&zmeqto(n->left->val.vmax,l2zm(0L))){
+ struct const_list *cl;zmax len=l2zm(0L);
+ cl=n->left->cl;
+ while(cl){
+ len=zmadd(len,l2zm(1L));
+ if(zmeqto(zc2zm(cl->other->val.vchar),l2zm(0L))) break;
+ cl=cl->next;
+ }
+ if(zmleq(len,l2zm((long)INLINEMEMCPY))){
+ inline_memcpy(p->alist->arg,n,len);
+ p->o=p->alist->arg->o;
+ return;
+ }
+ }
+ }
+ if(!strcmp(v->identifier,"memcpy")){
+ if(p->alist&&p->alist->next&&p->alist->next->next
+ &&p->alist->next->next->arg
+ &&p->alist->next->next->arg->flags==CEXPR){
+ eval_constn(p->alist->next->next->arg);
+ if(zmleq(vmax,l2zm((long)INLINEMEMCPY))){
+ inline_memcpy(p->alist->arg,p->alist->next->arg,vmax);
+ p->o=p->alist->arg->o;
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ rl=0;
+ if(!(optflags&2)){
+ int r;
+ for(r=1;r<=MAXR;r++){mregs[r]=regs[r];regs[r]&=~32;}
+ }
+#ifdef ORDERED_PUSH
+ merk_fp=first_pushed;
+ first_pushed=0;
+ lp=last_ic;
+#endif
+#ifdef HAVE_REGPARMS
+ if(!freturn(p->ntyp)&&(p->ntyp->flags&NQ)!=VOID){
+ struct IC *new2;static struct Typ ptyp={0};
+ struct reg_handle reg_handle=empty_reg_handle;
+ int reg;
+ new2=new_IC();
+ new2->code=ADDRESS;
+ new2->typf=p->ntyp->flags;
+ new2->typf2=POINTER_TYPE(p->ntyp);
+ new2->q1.flags=VAR;
+ new2->q1.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+ new2->q1.val.vmax=l2zm(0L);
+ op=&new2->q1;
+ new2->q2.flags=0;
+ get_scratch(&new2->z,POINTER_TYPE(p->ntyp),p->ntyp->flags,0);
+ ret_obj=new2->z;
+ add_IC(new2);
+ ptyp.next=p->ntyp;
+ ptyp.flags=POINTER_TYPE(p->ntyp);
+ reg=reg_parm(®_handle,&ptyp,0,p->left->ntyp);
+ if(!reg) ierror(0);
+ sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,&ret_obj,p->ntyp,reg,p->left->ntyp);
+ if(optflags&2)
+ handle_reglist(rl,&ret_obj);
+ }else{
+ struct reg_handle reg_handle=empty_reg_handle;
+ sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,0,0,-1,p->left->ntyp);
+ if(optflags&2)
+ handle_reglist(rl,0);
+ }
+#else
+ sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl);
+ if(optflags&2)
+ handle_reglist(rl,0);
+#endif
+ if(!r) gen_IC(p->left,0,0);
+ if(!(p->left->o.flags&DREFOBJ)){
+ free(new);
+ p->o=p->left->o;
+ if(p->o.flags&VARADR){
+ p->o.flags&=~VARADR;
+ }else{
+ p->o.flags|=DREFOBJ;
+ p->o.dtyp=p->left->ntyp->flags;
+ }
+ }else{
+ if(p->left->o.flags&VARADR){
+ free(new);
+ p->o=p->left->o;
+ p->o.flags&=~VARADR;
+ }else{
+ if((p->left->o.flags&SCRATCH)&&p->ntyp->flags==p->left->ntyp->flags){
+ new->z=p->left->o;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ get_scratch(&new->z,p->left->ntyp->flags,FUNKT,p->left->ntyp);
+ }
+ new->code=ASSIGN;
+ new->typf=p->left->ntyp->flags;
+ new->q1=p->left->o;
+ new->q2.val.vmax=sizetab[new->typf];
+ new->q2.flags=0;
+ p->o=new->z;
+ add_IC(new);
+ p->o.flags|=DREFOBJ;
+ p->o.dtyp=p->left->ntyp->flags;
+ }
+ }
+/* p->left->o.flags-=DREFOBJ|VARADR; Was sollte das?? */
+
+#if 0
+ if(optflags&2){
+ while(rl){
+ struct regargs_list *m;
+ new=new_IC();
+ new->code=NOP;
+ new->q1.flags=VAR;
+ new->q1.v=rl->v;
+ new->q1.val.vmax=l2zm(0L);
+ new->typf=0;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ m=rl->next;free(rl);rl=m;
+ }
+ }
+#endif
+
+#ifndef HAVE_REGPARMS
+ /* gegebenenfalls Adresse des Ziels auf den Stack */
+ if(!freturn(p->ntyp)&&(p->ntyp->flags&NQ)!=VOID){
+#ifdef ORDERED_PUSH
+ ierror(0);
+#endif
+ new=new_IC();
+ new->code=ADDRESS;
+ new->typf=p->ntyp->flags;
+ new->typf2=POINTER_TYPE(p->ntyp->next);
+ new->q1.flags=VAR;
+ new->q1.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+ new->q1.val.vmax=l2zm(0L);
+ op=&new->q1;
+ new->q2.flags=0;
+ get_scratch(&new->z,POINTER_TYPE(p->ntyp),p->ntyp->flags,0);
+ ret_obj=new->z;
+ add_IC(new);
+ new=new_IC();
+ new->code=PUSH;
+ new->typf=POINTER_TYPE(p->ntyp);
+ new->q1=ret_obj;
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sizetab[new->typf];
+ new->z.val.vmax=new->q2.val.vmax;
+ add_IC(new);
+ sz=zmadd(sz,sizetab[new->typf]);
+ }
+#endif
+
+ /* Scratchregister evtl. sichern */
+ cfunc=p->o;
+ if(!nocode)
+ savescratch(MOVEFROMREG,last_ic,0,&cfunc);
+ function_calls+=currentpri;
+ new=new_IC();
+ new->code=CALL;
+ callic=new;
+ if(p->alist){
+ /* insert list of argument ICs */
+ int i=0;
+ struct argument_list *a=p->alist;
+ while(a){i++;a=a->next;}
+ new->arg_cnt=i;
+ new->arg_list=mymalloc(sizeof(*new->arg_list)*i);
+ for(a=p->alist,i=0;a;a=a->next,i++) new->arg_list[i]=a->pushic;
+ }else{
+ new->arg_cnt=0;
+ new->arg_list=0;
+ }
+ new->typf=FUNKT;
+ new->q1=p->o;
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sz; /* Groesse der Parameter auf dem Stack */
+ add_IC(new);
+
+ if(optflags&2){
+ while(rl){
+ struct regargs_list *m;
+ new=new_IC();
+ new->code=NOP;
+ new->q1.flags=VAR;
+ new->q1.v=rl->v;
+ new->q1.val.vmax=l2zm(0L);
+ new->typf=0;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ m=rl->next;free(rl);rl=m;
+ }
+ }
+
+ r=0;
+ if((p->ntyp->flags&NQ)!=VOID){
+ new=new_IC();
+ new->code=GETRETURN;
+ new->q1.flags=new->q2.flags=0;
+ new->q1.reg=freturn(p->ntyp);
+ new->q2.val.vmax=szof(p->ntyp);
+ new->typf=p->ntyp->flags;
+ if(freturn(p->ntyp)){
+ int t=p->ntyp->flags&NQ;
+ if(ISSTRUCT(t)||ISUNION(t)){
+ new->z.v=add_var(empty,clone_typ(p->ntyp),AUTO,0);
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ }else{
+ if(optflags&2){
+ get_scratch(&new->z,p->ntyp->flags,0,p->ntyp);
+ }else{
+ /* Suche geeignetes Register, um Rueckgabewert zu speichern. */
+ struct regargs_list *l2;
+ int r;
+ r=new->q1.reg;
+ if(regs[r]||!regok(r,p->ntyp->flags,0)||(reg_pair(r,&rp)&&(regs[rp.r1]||regs[rp.r2]))){
+ r=0;
+ }else{
+ for(l2=rl;l2;l2=l2->next){
+ if(l2->v&&abs(l2->reg)==r) {r=0;break;}
+ }
+ }
+ if(r==0){
+ for(r=1;r<=MAXR;r++){
+ if(!regs[r]&®ok(r,p->ntyp->flags,0)&&(!reg_pair(r,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){
+ for(l2=rl;l2;l2=l2->next){
+ if(l2->v&&abs(l2->reg)==r) break;
+ }
+ if(l2) continue;
+ break;
+ }
+ }
+ }
+ if(r>=1&&r<=MAXR){
+ alloc_hardreg(r);
+ new->z.flags=(REG|SCRATCH);
+ new->z.reg=r;
+ }else{
+ get_scratch(&new->z,p->ntyp->flags,0,p->ntyp);
+ }
+ }
+ }
+ } else
+ new->z=*op;
+ if((new->z.flags&(REG|DREFOBJ))==REG) r=new->z.reg;
+ p->o=new->z;
+ add_IC(new);
+ }else{
+ p->o.flags=0;
+ }
+ /* Scratchregister evtl. wiederherstellen */
+ if(!nocode)
+ savescratch(MOVETOREG,last_ic,r,&cfunc);
+ if(!(optflags&2)){
+ int r;
+ for(r=1;r<=MAXR;r++){
+ if(regs[r])
+ regs[r]|=(mregs[r]&32);
+ }
+ }
+ /* Evtl. gespeicherte Registerargumente wiederherstellen. */
+ while(rl){
+ struct regargs_list *m;
+ if(rl->v){
+ int r;
+ for(r=MAXR;r>=1;r--){
+ if(regs[r]&®_pair(r,&rp)&&(rp.r1==abs(rl->reg)||rp.r2==abs(rl->reg)))
+ break;
+ }
+ if(r<=1) r=abs(rl->reg);
+ new=new_IC();
+ new->code=MOVETOREG;
+ new->typf=0;
+ new->q1.flags=VAR|DONTREGISTERIZE;
+ new->q1.v=rl->v;
+ new->q1.val.vmax=l2zm(0L);
+ new->z.flags=REG;
+ new->z.reg=abs(r);
+ new->q2.flags=0;
+ new->q2.val.vmax=regsize[r];
+ add_IC(new);
+ }else{
+ new=new_IC();
+ new->code=FREEREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q2.flags=new->z.flags=0;
+ new->q1.reg=abs(rl->reg);
+ add_IC(new);
+ regs[abs(rl->reg)]=0;
+ }
+ m=rl->next;free(rl);rl=m;
+ }
+#ifdef ORDERED_PUSH
+ /* If arguments have been pushed nested we have to copy them and */
+ /* push them later. */
+ if(merk_fp&&opushed!=merk_opushed){
+ struct IC *p,*m=0,*np;
+ if(!lp) ierror(0);
+ for(p=merk_fp;p;){
+ np=p->next;
+ if(p->code==PUSH){
+ new=new_IC();
+ *new=*p;
+ /* be careful about the address because of arg_list! */
+ if(p->prev) p->prev->next=new;
+ new->prev=p->prev;
+ if(p->next) p->next->prev=new;
+ new->next=p->next;
+ if(p==last_ic) last_ic=new;
+ if(p==first_ic) first_ic=new;
+ if(new->q1.flags){
+ new->code=ASSIGN;
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ /* typ allocated in push_args and not used there */
+ /* if(!p->ityp) ierror(0);*/
+ new->z.v=add_tmp_var(clone_typ(p->ityp)); /*FIXME??*/
+ p->q1=new->z;
+ /* p->ityp=0;*/
+ }else{
+ remove_IC(new);
+ }
+ p->next=p->prev=0;
+ add_IC(p);
+ if(!m) m=p;
+ }
+ if(p==lp) break;
+ p=np;
+ }
+ if(!m) ierror(0);
+ first_pushed=m;
+ }else
+ first_pushed=merk_fp;
+#endif
+ return;
+ }
+ if(p->flags>=PREINC&&p->flags<=POSTDEC){
+ struct obj o;
+#if HAVE_LIBCALLS
+ char *libname;
+ struct node tn={ADD},one={CEXPR};
+#endif
+ gen_IC(p->left,0,0);
+ if(p->flags==POSTINC||p->flags==POSTDEC){
+ /*new=new_IC();*/
+ new->code=ASSIGN;
+ new->typf=p->ntyp->flags;
+ new->q2.val.vmax=sizetab[p->ntyp->flags&NQ];
+ new->q1=p->left->o;
+ new->q1.flags&=~SCRATCH;
+ get_scratch(&new->z,p->left->ntyp->flags,0,p->left->ntyp);
+ new->q2.flags=0;
+ o=new->z;
+ add_IC(new);
+ new=new_IC();
+ }else
+ o=p->left->o;
+#if HAVE_LIBCALLS
+ if(p->flags==PREDEC||p->flags==POSTDEC)
+ tn.flags=SUB;
+ tn.left=p->left;
+ tn.right=&one;
+ tn.ntyp=p->ntyp;
+ one.flags=CEXPR;
+ one.ntyp=p->ntyp;
+ gval.vmax=l2zm(1L);
+ eval_const(&gval,MAXINT);
+ insert_const(&one.val,p->ntyp->flags&NU);
+ if(libname=use_libcall(&tn)){
+ np lc;
+ lc=gen_libcall(libname,p->left,0,&one,0);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=p->ntyp->flags;
+ new->q2.val.vmax=sizetab[p->ntyp->flags&NQ];
+ new->q1=lc->o;
+ new->q1.flags&=~SCRATCH;
+ new->z=p->left->o;
+ add_IC(new);
+ new=new_IC();
+ free(lc);
+ }else
+#endif
+ if(ISPOINTER(p->left->ntyp->flags)){
+ if(p->flags==PREINC||p->flags==POSTINC)
+ new->code=ADDI2P;
+ else
+ new->code=SUBIFP;
+ vmax=szof(p->left->ntyp->next);
+ new->q2.val.vint=zm2zi(vmax);
+ new->typf=INT;
+ new->typf2=p->left->ntyp->flags;
+ new->q1=p->left->o;
+ new->z=p->left->o;
+ new->q2.flags=KONST;
+ add_IC(new);
+ }else{
+ if(p->flags==PREINC||p->flags==POSTINC)
+ new->code=ADD;
+ else
+ new->code=SUB;
+ new->typf=p->ntyp->flags;
+ new->q1=p->left->o;
+ new->z=p->left->o;
+ new->q2.flags=KONST;
+ gval.vint=zm2zi(l2zm(1L));
+ eval_const(&gval,INT);
+ insert_const(&new->q2.val,new->typf);
+ add_IC(new);
+ }
+ if(p->flags==POSTINC||p->flags==POSTDEC){
+ if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG))
+ free_reg(p->left->o.reg);
+ }
+ p->o=o;
+ return;
+ }
+ if(p->flags==COND){
+ int ltrue,lfalse,lout;
+ ltrue=++label;lfalse=++label;lout=++label;
+ gen_IC(p->left,ltrue,lfalse);
+ if(!p->left->o.flags){
+ free(new);
+ }else{
+ if(p->left->flags!=CEXPR){
+ gen_test(&p->left->o,p->left->ntyp->flags,BEQ,lfalse);
+ }else{
+ eval_constn(p->left);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){
+ gen_IC(p->right->right,0,0);
+ p->o=p->right->right->o;
+ }else{
+ gen_IC(p->right->left,0,0);
+ p->o=p->right->left->o;
+ }
+ return;
+ }
+ }
+ gen_label(ltrue);
+ gen_IC(p->right->left,0,0);
+ if((p->ntyp->flags&NQ)!=VOID){
+ convert(p->right->left,p->ntyp->flags);
+ if((p->right->left->o.flags&(SCRATCH|DREFOBJ))==SCRATCH){
+ p->o=p->right->left->o;
+ }else{
+ get_scratch(&p->o,p->ntyp->flags,0,p->ntyp);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->q1=p->right->left->o;
+ new->z=p->o;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(p->ntyp);
+ new->typf=p->ntyp->flags;
+ p->o=new->z;
+ add_IC(new);
+ }
+ }else
+ p->o.flags=0;
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lout;
+ add_IC(new);
+ gen_label(lfalse);
+ gen_IC(p->right->right,0,0);
+ if((p->ntyp->flags&NQ)!=VOID){
+ convert(p->right->right,p->ntyp->flags);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->q1=p->right->right->o;
+ new->z=p->o;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(p->ntyp);
+ new->typf=p->ntyp->flags;
+ add_IC(new);
+ }
+ gen_label(lout);
+ return;
+ }
+ printf("Operation: %d=%s\n",p->flags,ename[p->flags]);
+ ierror(0);
+ free(new);
+ p->o.flags=0;
+}
+
+static void handle_reglist(struct regargs_list *nrl,struct obj *radr)
+{
+ struct IC *new;
+ /* Letztes Argument; jetzt in Register laden. */
+#ifdef HAVE_REGPARMS
+ int didradr=0;
+#endif
+ while(nrl){
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=nrl->v->vtyp->flags/*|VOLATILE*/;
+ new->q1.flags=VAR;
+ new->q1.v=nrl->v;
+ new->q1.val.vmax=l2zm(0L);
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(nrl->v->vtyp);
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ new->z.v=add_var(empty,clone_typ(nrl->v->vtyp),AUTO,0);
+ new->z.v->reg=nrl->reg;
+ new->z.v->vtyp->flags|=VOLATILE;
+ nrl->v=new->z.v;
+ add_IC(new);
+
+#ifdef HAVE_REGPARMS
+ if(radr&&!didradr){
+ didradr=1;
+ }else{
+#endif
+ nrl->al->pushic=new;
+#ifdef HAVE_REGPARMS
+ }
+#endif
+ nrl=nrl->next;
+ }
+}
+
+#ifdef HAVE_REGPARMS
+zmax push_args(struct argument_list *al,struct struct_declaration *sd,int n,struct regargs_list **rl,struct reg_handle *reg_handle,struct obj *radr,struct Typ *rtype,int rreg,struct Typ *fkt)
+#else
+zmax push_args(struct argument_list *al,struct struct_declaration *sd,int n,struct regargs_list **rl)
+#endif
+/* Legt die Argumente eines Funktionsaufrufs in umgekehrter Reihenfolge */
+/* auf den Stack. Es wird Integer-Erweiterung vorgenommen und float wird */
+/* nach double konvertiert, falls kein Prototype da ist. */
+{
+ int t,reg,regpush,evaluated=0;struct Typ *ft;
+ struct IC *new;struct regargs_list *nrl;zmax sz,rsz,of;struct obj *arg;
+#ifdef HAVE_REGPARMS
+ int stdreg;
+ if(!al&&!radr) return(0);
+ if(radr){
+ stdreg=rreg;
+ }else{
+ if(n<sd->count){
+ stdreg=reg_parm(reg_handle,(*sd->sl)[n].styp,0,fkt);
+ }else{
+ if(sd->count)
+ stdreg=reg_parm(reg_handle,al->arg->ntyp,1,fkt);
+ else
+ stdreg=reg_parm(reg_handle,al->arg->ntyp,0,fkt);
+ }
+ }
+ reg=stdreg;
+#else
+ if(!al) return(0);
+ reg=0;
+#endif
+#ifdef HAVE_REGPARMS
+ if(!radr){
+#endif
+ if(!al->arg) ierror(0);
+ if(!sd) ierror(0);
+ if(n<sd->count){
+ ft=clone_typ((*sd->sl)[n].styp);sz=szof(ft);
+ t=ft->flags;
+ reg=(*sd->sl)[n].reg;
+ }else{
+ ft=clone_typ(al->arg->ntyp);sz=szof(ft);
+ t=ft->flags;
+ }
+ if(ISINT(t)) {t=int_erw(t);ft->flags=t;sz=sizetab[t&NQ];}
+ if((t&NQ)==FLOAT&&n>=sd->count) {t=DOUBLE;ft->flags=t;sz=sizetab[t];}
+#ifdef HAVE_REGPARMS
+ }else{
+ ft=new_typ();
+ ft->flags=t=POINTER_TYPE(rtype);
+ ft->next=clone_typ(rtype);
+ sz=sizetab[t];
+ }
+#endif
+ if(reg<0) {reg=-reg;regpush=1;} else regpush=0;
+ rsz=sz;
+ sz=zmmult(zmdiv(zmadd(sz,zmsub(stackalign,l2zm(1L))),stackalign),stackalign);
+#ifdef ORDERED_PUSH
+ if(reg==0||regpush){
+ new=new_IC();
+ if(!radr&&!evaluated){
+ gen_IC(al->arg,0,0);
+ convert(al->arg,t);
+ evaluated=1;
+ new->q1=al->arg->o;
+ al->pushic=new;
+ }else
+ new->q1=*radr;
+ /* Parameteruebergabe ueber Stack. */
+ new->code=PUSH;
+ new->typf=t;
+ new->ityp=ft;
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sz;
+ new->z.val.vmax=rsz;
+ if(regpush){
+ if(c_flags[26]&USEDFLAG){
+ new->q1.am=new->q2.am=new->z.am=0;
+ new->line=line; new->file=filename;
+ insert_IC(last_ic,new);
+ }else{
+ new->q1.flags=0;
+ add_IC(new);
+ }
+ }else{
+ add_IC(new);
+ }
+ opushed++;
+ if(!first_pushed) first_pushed=new;
+ if(al&&!al->next&&!regpush) return sz;
+ }
+#endif
+#ifdef HAVE_REGPARMS
+ if(radr){
+ if(al) of=push_args(al,sd,0,rl,reg_handle,0,0,0,fkt); else of=l2zm(0L);
+ }else{
+ if(al->next) of=push_args(al->next,sd,n+1,rl,reg_handle,0,0,0,fkt); else of=l2zm(0L);
+ }
+#else
+ if(al->next) of=push_args(al->next,sd,n+1,rl); else of=l2zm(0L);
+#endif
+#ifdef ORDERED_PUSH
+ if(reg==0) return zmadd(of,sz);
+#endif
+
+ if(regpush) of=zmadd(of,sz);
+
+#ifdef HAVE_REGPARMS
+ if(radr){
+ arg=radr;
+ }else{
+ if(!evaluated){
+ gen_IC(al->arg,0,0);
+ convert(al->arg,t);
+ evaluated=1;
+ }
+ arg=&al->arg->o;
+ }
+#else
+ if(!evaluated){
+ gen_IC(al->arg,0,0);
+ convert(al->arg,t);
+ evaluated=1;
+ }
+ arg=&al->arg->o;
+#endif
+#ifndef ORDERED_PUSH
+ if(reg==0||regpush){
+ /* Parameteruebergabe ueber Stack. */
+ new=new_IC();
+ new->code=PUSH;
+ new->typf=t;
+ new->q1=*arg;
+ if(regpush&&!(c_flags[26]&USEDFLAG)) new->q1.flags=0;
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sz;
+ new->z.val.vmax=rsz;
+ add_IC(new);
+ al->pushic=new;
+ if(!regpush) return(zmadd(of,sz));
+ }
+#endif
+ if(reg){
+ /* Parameteruebergabe in Register. */
+ struct Var *v=0; struct Typ *t2;
+ if(optflags&2){
+ /* Version fuer Optimizer. */
+ t2=new_typ();
+ t2->flags=t;
+ if(ISPOINTER(t)){
+ t2->next=new_typ();
+ t2->next->flags=VOID;
+ }
+ v=add_var(empty,t2,AUTO,0);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=t;
+ new->q1=*arg;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[t&NQ];
+ new->z.flags=VAR;
+ new->z.v=v;
+ new->z.val.vmax=l2zm(0L);
+ add_IC(new);
+ nrl=mymalloc(sizeof(*nrl));
+ nrl->next=*rl;
+ nrl->reg=reg;
+ nrl->v=v;
+ nrl->al=al;
+ *rl=nrl;
+ return of;
+ }else{
+ /* Nicht-optimierende Version. */
+ if(!regs[reg]&&(!reg_pair(reg,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){
+ new=new_IC();
+ new->code=ALLOCREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q1.reg=reg;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ regs[reg]=33;regused[reg]++;
+ if(reg_pair(reg,&rp)){
+ regs[rp.r1]=33;regused[rp.r1]++;
+ regs[rp.r2]=33;regused[rp.r2]++;
+ }
+ }else{
+ if(arg->flags!=(REG|SCRATCH)||arg->reg!=reg){
+ int r=0;
+ /* register pairs */
+ if(reg_pair(reg,&rp)){
+ if(regs[reg]||regs[rp.r1]||regs[rp.r2])
+ r=reg;
+ }else{
+ for(r=MAXR;r>=1;r--){
+ if(regs[r]&®_pair(r,&rp)&&(rp.r1==reg||rp.r2==reg))
+ break;
+ }
+ if(r<1) r=reg;
+ }
+ t2=clone_typ(regtype[r]);
+ v=add_var(empty,t2,AUTO,0);
+ v->flags|=USEDASADR;
+ new=new_IC();
+ new->code=MOVEFROMREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q1.reg=r;
+ new->q2.flags=0;
+ new->q2.val.vmax=regsize[r];
+ new->z.flags=VAR|DONTREGISTERIZE;
+ new->z.v=v;
+ new->z.val.vmax=l2zm(0L);
+ add_IC(new);
+ }else
+ regs[reg]|=32;
+ }
+ new=new_IC();
+#ifdef HAVE_REGPARMS
+ if(!radr){
+ al->pushic=new;
+ }
+#else
+ al->pushic=new;
+#endif
+ new->code=ASSIGN;
+ new->typf=t;
+ new->q1=*arg;
+ /* Testen, ob Quellregister gesichert wurde. Unschoen. */
+ if((new->q1.flags®)){
+ struct regargs_list *p;
+ for(p=*rl;p;p=p->next){
+ int r;
+ if(p->v&&(r=abs(p->reg))){
+ if(new->q1.reg==r||(reg_pair(new->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))) {new->q1.v=p->v;new->q1.val.vmax=l2zm(0L);break;}
+ /*FIXME: andersrum bei LITTLEENDIAN?? */
+ if(reg_pair(r,&rp)&&rp.r1==new->q1.reg) {new->q1.v=p->v;new->q1.val.vmax=l2zm(0L);break;}
+ if(reg_pair(r,&rp)&&rp.r2==new->q1.reg) {new->q1.v=p->v;new->q1.val.vmax=regsize[rp.r1];break;}
+
+ }
+ }
+ if(p&&new->q1.v){
+ if(must_convert(new->typf,regtype[new->q1.reg]->flags,0)){
+ new->code=CONVERT;
+ new->typf2=regtype[new->q1.reg]->flags;
+ }
+ new->q1.flags&=~REG;
+ new->q1.flags|=VAR;
+ /*new->q1.val.vmax=l2zm(0L);*/
+ }
+ }
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sizetab[t&NQ];
+ new->z.flags=REG;
+ new->z.reg=reg;
+ add_IC(new);
+ nrl=mymalloc(sizeof(*nrl));
+ nrl->next=*rl;
+ nrl->reg=reg;
+ nrl->v=v;
+ *rl=nrl;
+ return of;
+ }
+ }
+}
+
+void convert(np p,int f)
+/* konvertiert das Objekt in p->o in bestimmten Typ */
+/* wenn volatile_convert gesetzt ist, wird immer IC erzeugt */
+{
+ struct IC *new;
+ int o=p->ntyp->flags;
+ if((f&NQ)==VOID) return;
+ if(p->flags==CEXPR||p->flags==PCEXPR){
+#ifdef HAVE_MISRA
+ if((o&NU)<(f&NU))
+ misra_neu(18,0,0,-1);
+#endif
+ eval_constn(p);
+ p->ntyp->flags=f;
+ insert_constn(p);
+ p->o.val=p->val;
+ return;
+ }
+ if(!volatile_convert&&((o&NU)==(f&NU)||(!must_convert(o,f,const_expr)&&(const_expr||!(optflags&2))))){
+ p->ntyp->flags=f;
+ if(!ISPOINTER(f)&&!ISARRAY(f)){freetyp(p->ntyp->next);p->ntyp->next=0;}
+ return;
+ }
+ new=new_IC();
+ new->q1=p->o;
+ new->q2.flags=0;
+ new->code=CONVERT;
+ new->typf2=o;
+ new->typf=f;
+ if((p->o.flags&(SCRATCH|REG))!=(SCRATCH|REG)||!regok(p->o.reg,f,0)){
+ get_scratch(&new->z,f,0,0);
+ p->o=new->z;
+ add_IC(new);
+ }else{
+ new->z=p->o;new->z.flags&=~DREFOBJ;
+ p->o=new->z;
+ add_IC(new);
+ }
+}
+
+void alloc_hardreg(int r)
+/* Belegt Register r. */
+{
+ struct IC *new;
+ if(nocode) return;
+ if(DEBUG&16) printf("allocated %s\n",regnames[r]);
+ regs[r]=1;regused[r]++;
+ new=new_IC();
+ new->code=ALLOCREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q1.reg=r;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ if(reg_pair(r,&rp)){
+ regs[rp.r1]=1;regused[rp.r1]++;
+ regs[rp.r2]=1;regused[rp.r2]++;
+ }
+}
+
+int allocreg(int f,int mode)
+/* Fordert Register fuer Typ f an. */
+{
+ int i,r=0,prio=-1;
+ if(nocode) return(1);
+ for(i=1;i<=MAXR;i++){
+ if(!regs[i]&®_prio[i]>prio&®ok(i,f,mode)&&(!reg_pair(i,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){
+ r=i;
+ prio=reg_prio[i];
+ }
+ }
+ if(r){
+ if(DEBUG&16) printf("alloc %s\n",regnames[r]);
+ alloc_hardreg(r);
+ return r;
+ }
+ if(DEBUG&1) printf("Couldn't allocate register for type %d\n",f);
+ return 0;
+}
+void free_reg(int r)
+/* Gibt Register r frei */
+/* Eintrag eines IC fehlt noch */
+{
+ struct IC *new;
+ if(!r||nocode) return;
+ if(regs[r]==0)
+ {printf("Register %d(%s):\n",r,regnames[r]);ierror(0);}
+ if(DEBUG&16) printf("freed %s\n",regnames[r]);
+ new=new_IC();
+ new->code=FREEREG;
+ new->typf=0;
+ new->q1.flags=REG;
+ new->q1.reg=r;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ regs[r]=0;
+ if(reg_pair(r,&rp)){
+ regs[rp.r1]=0;
+ regs[rp.r2]=0;
+ }
+}
+void gen_label(int l)
+/* Erzeugt ein Label */
+{
+ struct IC *new;
+ new=new_IC();
+ new->code=LABEL;
+ new->typf=l;
+ new->q1.flags=new->q2.flags=new->z.flags=0;
+ add_IC(new);
+}
+void gen_cond(struct obj *p,int m,int l1,int l2)
+/* Generiert code, der 0 oder 1 in Register schreibt. Schreibt obj nach p. */
+{
+ struct IC *new;
+ struct obj omerk;
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=INT;
+ new->q1.flags=KONST;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[INT];
+ if(!m) vmax=l2zm(1L); else vmax=l2zm(0L);
+ new->q1.val.vint=zm2zi(vmax);
+ get_scratch(&new->z,INT,0,0);
+ omerk=new->z;
+ add_IC(new);
+ new=new_IC();
+ new->code=BRA;
+ new->typf=l2;
+ add_IC(new);
+ gen_label(l1);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=INT;
+ new->q1.flags=KONST;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[INT];
+ if(!m) vmax=l2zm(0L); else vmax=l2zm(1L);
+ new->q1.val.vint=zm2zi(vmax);
+ new->z=omerk;
+/* new->z.reg=r;
+ new->z.flags=SCRATCH|REG;*/
+ add_IC(new);
+ gen_label(l2);
+ *p=omerk;
+}
+void scratch_var(struct obj *o,int t,struct Typ *typ)
+/* liefert eine temporaere Variable */
+/* nicht effizient, aber wer hat schon so wenig Register... */
+{
+ struct Typ *nt;
+ if(!ISSCALAR(t)){
+ if(!typ) ierror(0);
+ nt=clone_typ(typ);
+ }else{
+ nt=new_typ();
+ nt->flags=t;
+ if(ISPOINTER(t)){
+ nt->next=new_typ();
+ nt->next->flags=VOID;
+ }
+ }
+ o->flags=SCRATCH|VAR;o->reg=0;
+ o->v=add_var(empty,nt,AUTO,0);
+ o->val.vmax=l2zm(0L);
+}
+void get_scratch(struct obj *o,int t1,int t2,struct Typ *typ)
+/* liefert ein Scratchregister oder eine Scratchvariable */
+{
+ if(!(optflags&2)&&(o->reg=allocreg(t1,t2))){
+ o->flags=SCRATCH|REG;
+ }else{
+ scratch_var(o,t1,typ);
+ }
+}
+int do_arith(np p,struct IC *new,np dest,struct obj *o)
+/* erzeugt IC new fuer einen arithmetischen Knoten und speichert das */
+/* Resultat vom Unterknoten dest in o (fuer a op= b) */
+/* liefert 0, wenn dest nicht gefunden */
+{
+ int f=0,mflags;
+ new->code=p->flags;
+ if(new->code==PMULT) new->code=MULT;
+ gen_IC(p->left,0,0);
+ if(dest&&p->left==dest) {*o=p->left->o;f++;}
+ gen_IC(p->right,0,0);
+ if(dest&&p->right==dest) {*o=p->right->o;f++;}
+ if(dest){mflags=dest->o.flags;dest->o.flags&=(~SCRATCH);}
+
+ if(ISPOINTER(p->left->ntyp->flags)&&ISPOINTER(p->right->ntyp->flags)){
+ /* Subtrahieren zweier Pointer */
+ int dt=PTRDIFF_T(p->left->ntyp->flags);
+ if(p->flags!=SUB) ierror(0);
+ new->typf=dt;
+ new->typf2=p->left->ntyp->flags;
+ new->code=SUBPFP;
+ new->q1=p->left->o;
+ new->q2=p->right->o;
+ if(!dest&&(p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->left->o.reg,dt,0)){
+ new->z=p->left->o;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ if(USEQ2ASZ&&(p->right->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->right->o.reg,dt,0)){
+ new->z=p->right->o;
+ new->z.flags&=(~DREFOBJ);
+ }else{
+ get_scratch(&new->z,dt,0,0);
+ }
+ }
+ p->o=new->z;
+ add_IC(new);
+ if(!zmleq(szof(p->left->ntyp->next),l2zm(1L))){
+ new=new_IC();
+ new->code=DIV;
+ new->q1=p->o;
+ new->q2.flags=KONST;
+ gval.vmax=szof(p->left->ntyp->next);
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q2.val,dt);
+ new->z=p->o;
+ new->typf=dt;
+ add_IC(new);
+ }
+ if(dest) dest->o.flags=mflags;
+ return f;
+ }
+ if((p->flags==ADD||p->flags==SUB)&&ISPOINTER(p->ntyp->flags)){
+ /* Addieren und Subtrahieren eines Integers zu einem Pointer */
+ if(p->flags==ADD){
+ new->code=ADDI2P;
+ if(!ISPOINTER(p->left->ntyp->flags)){
+ np tmp=p->left;
+ p->left=p->right;
+ p->right=tmp;
+ }
+ }else
+ new->code=SUBIFP;
+ new->typf=p->right->ntyp->flags;
+ new->typf2=p->ntyp->flags;
+ new->q1=p->left->o;
+ /* kleinere Typen als MINADDI2P erst in diesen wandeln */
+ if((new->typf&NQ)<MINADDI2P){convert(p->right,MINADDI2P);new->typf=MINADDI2P;}
+ /* groessere Typen als MAXADDI2P erst in diesen wandeln */
+ if((new->typf&NQ)>MAXADDI2P){convert(p->right,MAXADDI2P);new->typf=MAXADDI2P;}
+ if((p->left->o.flags&VARADR)&&(p->right->o.flags&KONST)){
+ eval_const(&p->right->o.val,p->right->ntyp->flags);
+ p->o=p->left->o;
+ p->o.val.vmax=zmadd(vmax,p->left->o.val.vmax);
+ free(new);
+ return f;
+ }
+ new->q2=p->right->o;
+ if(!dest&&(p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(new->q1.reg,POINTER_TYPE(p->left->ntyp->next),p->left->ntyp->next->flags)){
+ new->z=p->left->o;
+ new->z.flags&=(~DREFOBJ);
+ }else{
+ get_scratch(&new->z,POINTER_TYPE(p->left->ntyp->next),p->left->ntyp->next->flags,0);
+ }
+ p->o=new->z;
+ add_IC(new);
+ if(dest) dest->o.flags=mflags;
+ return f;
+ }
+ convert(p->left,p->ntyp->flags);
+ if(p->flags==LSHIFT||p->flags==RSHIFT){
+ struct Typ *st=clone_typ(p->right->ntyp);
+ /*st->flags=int_erw(st->flags);*/
+ st->flags=INT;
+ convert(p->right,st->flags);
+ new->typf2=st->flags;
+ freetyp(st);
+ }else
+ convert(p->right,p->ntyp->flags);
+ new->q1=p->left->o;
+ new->q2=p->right->o;
+ new->typf=p->ntyp->flags;
+ /* Bei dest!=0, d.h. ASSIGNOP, darf q1 nicht als Ziel benuzt werden! */
+ if(!dest&&(new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(new->q1.reg,p->ntyp->flags,0)){
+ new->z=new->q1;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ if((new->q2.flags&SCRATCH)&®ok(new->q2.reg,p->ntyp->flags,0)){
+ if((p->flags>=OR&&p->flags<=AND)||p->flags==ADD||p->flags==MULT||p->flags==PMULT){
+ /* bei kommutativen Operatoren vertauschen */
+ new->z=new->q2;
+ new->q2=new->q1;
+ new->q1=new->z;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ if(USEQ2ASZ){
+ new->z=new->q2;
+ new->z.flags&=~DREFOBJ;
+ }else{
+ get_scratch(&new->z,new->typf,0,0);
+ }
+ }
+ }else{
+ get_scratch(&new->z,new->typf,0,0);
+ }
+ }
+ p->o=new->z;
+ add_IC(new);
+ if(dest) dest->o.flags=mflags;
+ return f;
+}
+void savescratch(int code,struct IC *p,int dontsave,struct obj *o)
+/* speichert Scratchregister bzw. stellt sie wieder her (je nach code */
+/* entweder MOVEFROMREG oder MOVETOREG) */
+{
+ int i,s,e,b,ds1,ds2;struct IC *new;
+ if(code==MOVETOREG){ s=1;e=MAXR+1;b=1;} else {s=MAXR;e=0;b=-1;}
+ if(reg_pair(dontsave,&rp)){
+ ds1=rp.r1;
+ ds2=rp.r2;
+ }else
+ ds1=ds2=0;
+ for(i=s;i!=e;i+=b){
+ int mustsave=0;
+ if((o->flags&(VAR|DREFOBJ))==VAR&&o->v->fi&&(o->v->fi->flags&ALL_REGS))
+ mustsave=BTST(o->v->fi->regs_modified,i);
+ else
+ mustsave=regscratch[i];
+ if(regsa[i]) mustsave=0;
+ if(mustsave) simple_scratch[i]=1;
+ if(regs[i]&&!(regs[i]&32)&&mustsave&&i!=dontsave&&i!=ds1&&i!=ds2&&!reg_pair(i,&rp)){
+ if(!regsbuf[i]){
+ struct Typ *t;
+ if(code!=MOVEFROMREG) continue;
+ t=clone_typ(regtype[i]);
+ regsbuf[i]=add_var(empty,t,AUTO,0);
+ regsbuf[i]->flags|=USEDASADR;
+ regbnesting[i]=nesting;
+ }
+ new=new_IC();
+ new->typf=new->q2.flags=0;
+ new->line=0;new->file=0;
+ new->code=code;
+ if(code==MOVEFROMREG){
+ new->q1.flags=REG;new->q1.reg=i;
+ new->z.flags=VAR|DONTREGISTERIZE;new->z.v=regsbuf[i];
+ new->z.val.vmax=l2zm(0L);
+ }else{
+ new->z.flags=REG;new->z.reg=i;
+ new->q1.flags=VAR|DONTREGISTERIZE;new->q1.v=regsbuf[i];
+ new->q1.val.vmax=l2zm(0L);
+ }
+ new->use_cnt=new->change_cnt=0;
+ new->use_list=new->change_list=0;
+ insert_IC(p,new);
+ }
+ }
+}
+
diff --git a/loop.c b/loop.c
new file mode 100644
index 0000000..b0190c6
--- /dev/null
+++ b/loop.c
@@ -0,0 +1,2077 @@
+/* $VER: vbcc (loop.c) $Revision: 1.19 $ */
+/* schleifenorientierte Optimierungen */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+#define MOVE_IC 1
+#define MOVE_COMP 2
+
+/* Liste, in die ICs eingetragen werden, die aus Schleifen */
+/* gezogen werden sollen. */
+typedef struct movlist{
+ struct movlist *next;
+ IC *IC;
+ flowgraph *target_fg;
+ int flags;
+} movlist;
+
+movlist *first_mov,*last_mov;
+
+int report_weird_code,report_suspicious_loops;
+
+static int only_shorten;
+
+/* Bitvektoren fuer schleifeninvariante ICs */
+bvtype *invariant,*inloop,*moved,*moved_completely;
+bvtype *fg_tmp;
+bvtype *not_movable;
+size_t bsize;
+
+
+/* Liste, in die ICs fuer strength-reduction eingetragen */
+/* werden. */
+typedef struct srlist{
+ struct srlist *next;
+ IC *ind_var;
+ IC *IC;
+ flowgraph *target_fg;
+ /* Hilfsvariable, falls eine aequivalente Operation schon reduziert */
+ /* wurde. */
+ Var *hv;
+} srlist ;
+
+srlist *first_sr,*last_sr;
+
+/* Liste, in die Daten fuer loop-unrolling eingetragen werden. */
+typedef struct urlist{
+ int flags;
+ long total,unroll;
+ IC *cmp,*branch,*ind;
+ flowgraph *start,*head;
+ struct urlist *next;
+} urlist;
+
+urlist *first_ur;
+
+#define UNROLL_COMPLETELY 1
+#define UNROLL_MODULO 2
+#define UNROLL_INVARIANT 4
+#define UNROLL_REVERSE 8
+#define UNROLL_SHORTEN 16
+#define IND_ONLY_COUNTS 32
+#define MULTIPLE_EXITS 64
+
+/* Hier werden Induktionsvariablen vermerkt */
+IC **ind_vars;
+
+static flowgraph *first_fg;
+
+#ifdef ALEX_REG
+void IncrementLoopDepth(flowgraph* fg,int start,int end)
+ /* erhoeht loop_depth in den Bloecken [start,end] */
+{
+ if ( (fg->index >= start) && (fg->index <= end) )
+ {
+ fg->loop_depth++;
+ }
+ if (fg->normalout)
+ IncrementLoopDepth(fg->normalout,start,end);
+}
+#endif
+
+#if !HAVE_DECIDE_REVERSE
+int decide_reverse(zmax v)
+{
+ if(optspeed||zmeqto(v,l2zm(1L)))
+ return 1;
+ return 0;
+}
+#endif
+
+int loops(flowgraph *fg,int footers)
+/* kennzeichnet Schleifen im Flussgraph; wenn footers!=0 werden darf eine */
+/* Schleife nur einen gemeinsamen Austrittspunkt haben */
+{
+ int i,start,end,c=0;flowlist *lp;flowgraph *g,*loopend;
+ if(DEBUG&1024) printf("searching loops\n");
+ g=fg;
+ while(g){
+ start=g->index;
+ end=-1;
+ for(lp=g->in;lp;lp=lp->next){
+ if(!lp->graph) continue;
+ if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA){
+ i=lp->graph->index;
+ if(i>=start&&i>end){ end=i;loopend=lp->graph; }
+ }
+ }
+ if(end>=0){
+ /* Schleife oder etwas aehnliches */
+ flowgraph *p=g;
+ if(DEBUG&1024) printf("found possible loop from blocks %d to %d\n",start,end);
+ if(1/*goto_used*/){
+ if(DEBUG&1024) printf("have to check...\n");
+ do{
+ if(!p||p->index>end) break;
+
+ /* testen, ob aus der Schleife gesprungen wird */
+ if(p->branchout&&footers){
+ i=p->branchout->index;
+ if(i<start){
+ end=-1;
+ break;
+ }
+ if(i>end&&(DEBUG&1024)){
+ puts("jump out of loop");
+ if(p->branchout!=loopend->normalout){
+ puts("no break");
+ if(p->branchout->start->typf!=return_label) puts("no return");
+ }
+ }
+ if(i>end&&p->branchout!=loopend->normalout&&p->branchout->start->typf!=return_label){
+ /* Sprung zu anderem als dem normalen Austritt oder return */
+ end=-1;
+ break;
+ }
+ }
+ /* testen, ob in die Schleife gesprungen wird */
+ if(p!=g){
+ for(lp=p->in;lp;lp=lp->next){
+ if(!lp->graph) continue;
+ if(lp->graph->branchout==p){
+ i=lp->graph->index;
+ if(i<start){
+ if(report_weird_code){error(175);report_weird_code=0;}
+ end=-1;
+ break;
+ }
+ if(i>end){
+ end=-1;
+ break;
+ }
+ }
+ }
+ }
+ if(p->index==end) break;
+ p=p->normalout;
+ }while(end>=0);
+ }else{
+ if(DEBUG&1024) printf("must be a loop, because there was no goto\n");
+ }
+ }
+ if(end>=0){
+ if(DEBUG&1024) printf("confirmed that it is a loop\n");
+ g->loopend=loopend;
+ c++;
+#ifdef ALEX_REG
+ IncrementLoopDepth(fg,start,end);
+#endif
+ }
+ g=g->normalout;
+ }
+ return c;
+}
+
+flowgraph *create_loop_headers(flowgraph *fg,int av)
+/* Fuegt vor jede Schleife einen Kopf-Block ein, wenn noetig. */
+/* Wenn av!=0 werden aktive Variablen korrekt uebertragen und */
+/* diverse Registerlisten uebernommen und index=-1 gesetzt. */
+/* Kann einen Block mehrmals in der ->in Liste eintragen */
+{
+ flowgraph *g,*last,*new,*rg=fg;
+ IC *lic,*lastic;
+ if(DEBUG&1024) printf("creating loop-headers\n");
+ g=fg;last=0;lastic=0;
+ while(g){
+ new=0;
+ if(g->loopend){
+ if(!last){
+ flowlist *lp;
+ new=new_flowgraph();
+ rg=new;
+ new->in=0;
+ lic=new_IC();
+ lic->code=LABEL;
+ lic->typf=++label;
+ lic->q1.flags=lic->q2.flags=lic->z.flags=0;
+ lic->q1.am=lic->q2.am=lic->z.am=0;
+ new->start=new->end=lic;
+ lic->next=first_ic;
+ lic->prev=0;
+ first_ic->prev=lic;
+ first_ic=lic;
+ lp=mymalloc(sizeof(flowlist));
+ lp->graph=new;
+ lp->next=g->in;
+ g->in=lp;
+ }else{
+ flowlist *lp,*nl,**ls;
+ new=new_flowgraph();
+ last->normalout=new;
+ lic=new_IC();
+ new->start=new->end=lic;
+ lic->code=LABEL;
+ lic->typf=++label;
+ lic->q1.flags=lic->q2.flags=lic->z.flags=0;
+ lic->q1.am=lic->q2.am=lic->z.am=0;
+ if(lastic) lastic->next=lic;
+ else first_ic=lic;
+ lic->prev=lastic;
+ g->start->prev=lic;
+ lic->next=g->start;
+ lp=g->in;ls=&new->in;
+ while(lp){
+ if(lp->graph&&lp->graph->index<g->index){
+ /* Eintritt von oben soll in den Kopf */
+ nl=mymalloc(sizeof(flowlist));
+ nl->graph=lp->graph;
+ nl->next=0;
+ (*ls)=nl;
+ ls=&nl->next;
+ if(lp->graph->branchout==g){
+ IC *p=lp->graph->end;
+ if(DEBUG&1024) printf("changing branch\n");
+ while(p&&p->code==FREEREG) p=p->prev;
+ if(!p||p->code<BEQ||p->code>BRA) ierror(0);
+ p->typf=lic->typf;
+ lp->graph->branchout=new;
+ }
+ lp->graph=new;
+ }
+ lp=lp->next;
+ }
+ if(!new->in) ierror(0);
+ }
+ if(new){
+ if(DEBUG&1024) printf("must insert loop-header before block %d\n",g->index);
+ basic_blocks++;
+ new->branchout=0;
+ new->loopend=0;
+ if(av)
+ new->index=-1;
+ else
+ new->index=basic_blocks;
+ new->normalout=g;
+ new->calls=0;
+ new->loop_calls=0;
+ new->rd_in=new->rd_out=new->rd_kill=new->rd_gen=0;
+ new->ae_in=new->ae_out=new->ae_kill=new->ae_gen=0;
+ new->cp_in=new->cp_out=new->cp_kill=new->cp_gen=0;
+ if(!av){
+ new->av_in=new->av_out=new->av_kill=new->av_gen=0;
+ }else{
+ new->av_in=mymalloc(vsize);
+ new->av_out=mymalloc(vsize);
+ new->av_gen=mymalloc(vsize);
+ new->av_kill=mymalloc(vsize);
+ memset(new->av_gen,0,vsize);
+ memset(new->av_kill,0,vsize);
+ memcpy(new->av_out,g->av_in,vsize);
+ memcpy(new->av_in,g->av_in,vsize);
+ memcpy(&new->regv,&g->regv,sizeof(new->regv));
+ memcpy(&new->regused,&g->regused,sizeof(new->regused));
+ }
+ }
+ }
+ last=g;if(last->end) lastic=last->end;
+ g=g->normalout;
+ }
+ return rg;
+}
+flowgraph *create_loop_footers(flowgraph *fg,int av)
+/* Fuegt hinter jede Schleife einen Fuss-Block ein, wenn noetig. */
+/* Wenn av!=0 werden aktive Variablen korrekt uebertragen und */
+/* diverse Registerlisten uebernommen und index auf -2 gesetzt. */
+{
+ flowgraph *g,*loopend,*out,*new;
+ IC *lic;
+ if(DEBUG&1024) printf("creating loop-footers\n");
+ g=fg;
+ while(g){
+ new=0;
+ loopend=g->loopend;
+ if(loopend){
+ flowlist *lp,*nl,**ls;
+ out=loopend->normalout;
+ new=new_flowgraph();
+ new->normalout=out;
+ loopend->normalout=new;
+ lic=new_IC();
+ lic->line=0;
+ lic->file=0;
+ new->start=new->end=lic;
+ lic->code=LABEL;
+ lic->typf=++label;
+ lic->q1.flags=lic->q2.flags=lic->z.flags=0;
+ lic->q1.am=lic->q2.am=lic->z.am=0;
+ lic->use_cnt=lic->change_cnt=0;
+ lic->use_list=lic->change_list=0;
+ if(out) lp=out->in; else {lp=0;new->in=0;}
+ ls=&new->in;
+ while(lp){
+ if(lp->graph&&lp->graph->index<=loopend->index&&lp->graph->index>=g->index){
+ /* Austritt aus Schleife soll in den Fuss */
+ nl=mymalloc(sizeof(flowlist));
+ nl->graph=lp->graph;
+ nl->next=0;
+ (*ls)=nl;
+ ls=&nl->next;
+ if(lp->graph->branchout==out){
+ IC *p=lp->graph->end;
+ if(DEBUG&1024) printf("changing branch\n");
+ while(p&&p->code==FREEREG) p=p->prev;
+ if(!p||p->code<BEQ||p->code>BRA) ierror(0);
+ p->typf=lic->typf;
+ lp->graph->branchout=new;
+ }
+ lp->graph=new;
+ }
+ lp=lp->next;
+ }
+ if(out&&!new->in) ierror(0);
+ if(DEBUG&1024) printf("must insert loop-footer after block %d\n",loopend->index);
+ basic_blocks++;
+ new->branchout=0;
+ new->loopend=0;
+ if(av)
+ new->index=-2;
+ else
+ new->index=basic_blocks;
+ new->normalout=out;
+ new->calls=0;
+ new->loop_calls=0;
+ new->rd_in=new->rd_out=new->rd_kill=new->rd_gen=0;
+ new->ae_in=new->ae_out=new->ae_kill=new->ae_gen=0;
+ new->cp_in=new->cp_out=new->cp_kill=new->cp_gen=0;
+ if(!av){
+ new->av_in=new->av_out=new->av_kill=new->av_gen=0;
+ }else{
+ new->av_in=mymalloc(vsize);
+ new->av_out=mymalloc(vsize);
+ new->av_kill=mymalloc(vsize);
+ new->av_gen=mymalloc(vsize);
+ memset(new->av_gen,0,vsize);
+ memset(new->av_kill,0,vsize);
+ if(out){
+ memcpy(new->av_out,out->av_in,vsize);
+ memcpy(new->av_in,out->av_in,vsize);
+ }else{
+ memcpy(new->av_out,av_globals,vsize);
+ bvunite(new->av_out,av_statics,vsize);
+ memcpy(new->av_in,new->av_out,vsize);
+ }
+ memcpy(&new->regv,&g->regv,sizeof(new->regv));
+ memcpy(&new->regused,&g->regused,sizeof(new->regused));
+ }
+ insert_IC_fg(new,loopend->end,lic);
+ }
+ g=g->normalout;
+ }
+ return fg;
+}
+void add_movable(IC *p,flowgraph *fg,int flags)
+/* Fuegt IC p, das aus der Schleife in Block fg mit Flags flags */
+/* verschoben werden darf in eine Liste. */
+{
+ movlist *new=mymalloc(sizeof(*new));
+ new->IC=p;
+ new->target_fg=fg;
+ new->flags=flags;
+ new->next=0;
+ if(last_mov){
+ last_mov->next=new;
+ last_mov=new;
+ }else{
+ first_mov=last_mov=new;
+ }
+ BSET(moved,p->defindex);
+ if(flags==MOVE_IC) BSET(moved_completely,p->defindex);
+}
+int move_to_head(void)
+/* Geht die Liste mit verschiebbaren ICs durch und schiebt die ICs */
+/* in den Vorkopf der Schleife. Ausserdem wird die Liste */
+/* freigegeben. */
+/* Der Rueckgabewert hat Bit 1 gesetzt, wenn ICs ganz verschoben */
+/* wurden und Bit 2, falls eine Berechnung mit Hilfsvariable vor */
+/* die Schleife gezogen wurde. */
+{
+ IC **fglist; /* Letztes IC vor jedem Block */
+ flowgraph *g;IC *p;movlist *m;
+ int changed=0;
+
+ if(!first_mov) return 0;
+
+ if(DEBUG&1024) printf("moving the ICs out of the loop\n");
+
+ fglist=mymalloc((basic_blocks+1)*sizeof(*fglist));
+ p=0;
+ for(g=first_fg;g;g=g->normalout){
+ if(g->index>basic_blocks) ierror(0);
+ if(g->end) p=g->end;
+ fglist[g->index]=p;
+ }
+ while(first_mov){
+ p=first_mov->IC;
+ g=first_mov->target_fg;
+ if(first_mov->flags==MOVE_IC){
+ if(DEBUG&1024) {printf("moving IC out of loop:\n");pric2(stdout,p);}
+ if(!p->prev||!p->next) ierror(0);
+ p->next->prev=p->prev;
+ p->prev->next=p->next;
+ insert_IC_fg(g,fglist[g->index],p);
+ fglist[g->index]=p;
+ changed|=1;
+ }else if(1){
+ type *t=new_typ();
+ IC *new=new_IC();
+ Var *v;
+ if(DEBUG&1024) {printf("moving computation out of loop:\n");pric2(stdout,p);}
+ t->flags=ztyp(p);
+ if(p->code==COMPARE||p->code==TEST) t->flags=0;
+ if(ISPOINTER(t->flags)){
+ t->next=new_typ();
+ t->next->flags=VOID;
+ }
+ v=add_tmp_var(t);
+ *new=*p;
+ new->z.flags=VAR;
+ new->z.v=v;
+ new->z.val.vmax=l2zm(0L);
+
+ /* Die neue Operation benutzt maximal, was die andere benutzte */
+ /* und aendert nur die Hilfsvariable. */
+ if(have_alias){
+ new->use_cnt=p->use_cnt;
+ new->use_list=mymalloc(new->use_cnt*VLS);
+ memcpy(new->use_list,p->use_list,new->use_cnt*VLS);
+ new->change_cnt=1;
+ new->change_list=mymalloc(VLS);
+ new->change_list[0].v=v;
+ new->change_list[0].flags=0;
+ }
+ insert_IC_fg(g,fglist[g->index],new);
+ fglist[g->index]=new;
+ p->code=ASSIGN;
+ p->typf=t->flags;
+ p->q1.flags=VAR;
+ p->q1.v=v;
+ p->q1.val.vmax=l2zm(0L);
+ p->q2.flags=0;
+ p->q2.val.vmax=szof(t);
+ /* Die Operation in der Schleife benutzt nun zusaetzlich */
+ /* noch die Hilfsvariable. */
+ if(have_alias){
+ void *m=p->use_list;
+ p->use_cnt++;
+ p->use_list=mymalloc(p->use_cnt*VLS);
+ memcpy(&p->use_list[1],m,(p->use_cnt-1)*VLS);
+ free(m);
+ p->use_list[0].v=v;
+ p->use_list[0].flags=0;
+ }
+ changed|=2;
+ }
+ m=first_mov->next;
+ free(first_mov);
+ first_mov=m;
+ }
+ if(DEBUG&1024) print_flowgraph(first_fg);
+ free(fglist);
+ return changed;
+}
+void calc_movable(flowgraph *start,flowgraph *end)
+/* Berechnet, welche Definitionen nicht aus der Schleife start-end */
+/* verschoben werden duerfen. Eine Def. p von z darf nur verschoben */
+/* werden, wenn keine andere Def. von p existiert und alle */
+/* Verwendungen von z nur von p erreicht werden. */
+/* Benutzt rd_defs. */
+{
+ flowgraph *g;IC *p;
+ int i,j,k,d;
+ bvtype *changed_vars;
+ if(DEBUG&1024) printf("calculating not_movable for blocks %d to %d\n",start->index,end->index);
+ if(0/*!(optflags&1024)*/){
+ memset(not_movable,UCHAR_MAX,dsize);
+ return;
+ }
+ memset(not_movable,0,dsize);
+ changed_vars=mymalloc(vsize);
+ memset(changed_vars,0,vsize);
+ for(i=0;i<vcount-rcount;i++){
+ if(vilist[i]->vtyp->flags&VOLATILE) BSET(changed_vars,i);
+ if(i<rcount){
+ if(!vilist[i]->vtyp->next||(vilist[i]->vtyp->next->flags&VOLATILE)) BSET(changed_vars,i+vcount-rcount);
+ }
+ }
+ for(g=start;g;g=g->normalout){
+ if(!g->rd_in) ierror(0);
+ memcpy(rd_defs,g->rd_in,dsize);
+ for(p=g->start;p;p=p->next){
+ for(j=0;j<p->change_cnt;j++){
+ i=p->change_list[j].v->index;
+ if(p->change_list[j].flags&DREFOBJ) i+=vcount-rcount;
+ if(i>=vcount) continue;
+ if(BTST(changed_vars,i)||is_volatile_ic(p)){
+ bvunite(not_movable,var_defs[i],dsize);
+ }else{
+ BSET(changed_vars,i);
+ }
+ }
+ for(k=0;k<p->use_cnt;k++){
+ i=p->use_list[k].v->index;
+ if(p->use_list[k].flags&DREFOBJ) i+=vcount-rcount;
+ if(i>=vcount) continue;
+ for(d=-1,j=1;j<=dcount;j++){
+ if(BTST(rd_defs,j)&&BTST(var_defs[i],j)){
+ if(d>=0){ /* mehr als eine Def. */
+ bvunite(not_movable,var_defs[i],dsize);
+ d=-1;break;
+ }else d=j;
+ }
+ if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],UNDEF(j))){
+ bvunite(not_movable,var_defs[i],dsize);
+ d=-1;break;
+ }
+ }
+ }
+ /* Das hier, um rd_defs zu aktualisieren. */
+ rd_change(p);
+ if(p==g->end) break;
+ }
+ if(g==end) break;
+ }
+ free(changed_vars);
+}
+/* Testet, ob Variable nur in der Schleife benutzt wird. */
+/* could be improved */
+int used_in_loop_only(flowgraph *start,flowgraph *end,obj *o)
+{
+ Var *v;flowgraph *g;IC *p;
+ if((o->flags&(VAR|DREFOBJ))!=VAR) return 0;
+ v=o->v;
+ if((v->flags&USEDASADR)||v->nesting==0||v->storage_class==EXTERN||v->storage_class==STATIC)
+ return 0;
+ for(g=first_fg;g;g=g->normalout){
+ if(g==start) g=end->normalout;
+ if(!g) break;
+ for(p=g->start;p;p=p->next){
+ if((p->q1.flags&VAR)&&p->q1.v==v) return 0;
+ if((p->q2.flags&VAR)&&p->q2.v==v) return 0;
+ if((p->z.flags&VAR)&&p->z.v==v) return 0;
+ if(p==g->end) break;
+ }
+ if(g==end) break;
+ }
+ return 1;
+}
+
+/* Testet, ob z immer ausgefuehrt wird, falls start in fg ausgefuehrt */
+/* wird. fg_tmp ist ein Bitvektor, um zu merken, welche Bloecke sicher */
+/* zu z fuehren. Das ganze fuer die Schleife start-end. */
+/* Wenn ignorecall!=0 ist, wird angenommen, dass jeder CALL */
+/* zurueckkehrt (das ist nuetzlich fuer loop-unrolling). */
+int always_reached(flowgraph *start,flowgraph *end,flowgraph *fg,IC *z,int ignorecall)
+{
+ bvtype *bmk=fg_tmp;
+ IC *p;flowgraph *g;
+ int changed;
+
+ for(p=z;p;p=p->prev){
+ if(!ignorecall&&p->code==CALL) return 0;
+ if(p==fg->start) break;
+ }
+
+ if(fg==start) return 1;
+
+ memset(bmk,0,bsize);
+ BSET(bmk,fg->index);
+
+ do{
+ changed=0;
+ for(g=start;g;g=g->normalout){
+ if(!BTST(bmk,g->index)){
+ flowgraph *n=g->normalout;
+ flowgraph *b=g->branchout;
+ if(n||b){
+ if((!b||BTST(bmk,b->index))&&
+ (!n||(g->end&&g->end->code==BRA)||BTST(bmk,n->index))){
+ for(p=g->end;p;p=p->prev){
+ if(!ignorecall&&p->code==CALL) break;
+ if(p==g->start){
+ if(g==start) return 1;
+ changed=1; BSET(bmk,g->index);
+ break;
+ }
+ }
+ }
+ }
+ }
+ if(g==end) break;
+ }
+ }while(changed);
+ return 0;
+}
+
+/* Ermittelt, ob Variable vindex schleifeninvariant unter den Bedingungen */
+/* rd_defs, inloop und invariant ist. */
+/* Definition ignore wird nicht beachtet. Wenn ignore auf eine gueltige */
+/* Definition gesetzt wird, kann man somit auf Induktionsvariablen testen */
+/* (das Ergebnis sagt dann, ob das die einzige Definition in der Schleife */
+/* ist). */
+int def_invariant(int vindex,int ignore)
+{
+ int i,k,j,d=0;
+ /*printf("def_inv(%d)=%s(%ld)\n",vindex,vilist[vindex]->identifier,zm2l(vilist[vindex]->offset));*/
+ for(j=1;j<=dcount;j++){
+ if(j!=ignore&&BTST(rd_defs,j)){
+ if(BTST(var_defs[vindex],j)&&BTST(inloop,j)){
+ /* Mehr als eine moegliche Def. innerhalb der Schleife oder */
+ /* eine invariante Def. in der Schleife => nicht invariant. */
+ if(d) return 0;
+ if(!BTST(moved_completely,j)) return 0;
+ d=1;
+ }
+ }
+ if(BTST(rd_defs,UNDEF(j))){
+ if(BTST(var_defs[vindex],UNDEF(j))&&BTST(inloop,UNDEF(j))){
+ /* Mehr als eine moegliche Def. innerhalb der Schleife oder */
+ /* eine invariante Def. in der Schleife => nicht invariant. */
+ if(d) return 0;
+ if(!BTST(moved_completely,UNDEF(j))) return 0;
+ d=1;
+ }
+ }
+ }
+ return 1;
+#if 0
+ if(!BTST(rd_defs,vindex+dcount+1)){
+ memcpy(rd_tmp,rd_defs,dsize);
+ bvintersect(rd_tmp,var_defs[vindex],dsize);
+ for(j=1;j<=dcount;j++){
+ if(j!=ignore&&BTST(rd_tmp,j)&&BTST(inloop,j)){
+ /* Mehr als eine moegliche Def. innerhalb der Schleife oder */
+ /* eine invariante Def. in der Schleife => nicht invariant. */
+ if(d) return 0;
+ if(!BTST(moved_completely,j)) return 0;
+ d=1;
+ }
+ }
+ }else{
+ for(j=1;j<=dcount;j++){
+ if(j!=ignore&&BTST(rd_defs,j)&&BTST(inloop,j)){
+ IC *p=dlist[j];
+ for(k=0;k<p->change_cnt;k++){
+ i=p->change_list[k].v->index;
+ if(p->change_list[k].flags&DREFOBJ) i+=vcount-rcount;
+ if(i==vindex) break;
+ }
+ if(k>=p->change_cnt) continue;
+ /* Mehr als eine moegliche Def. innerhalb der Schleife oder */
+ /* eine invariante Def. in der Schleife => nicht invariant. */
+ if(d) return 0;
+ if(!BTST(moved_completely,j)) return 0;
+ d=1;
+ }
+ }
+ }
+ return 1;
+#endif
+}
+
+void frequency_reduction(flowgraph *start,flowgraph *end,flowgraph *head)
+/* Schleifeninvariante ICs finden und in eine Liste eintragen, falls */
+/* sie vor die Schleife gezogen werden koennen. */
+{
+ IC *p;flowgraph *g;
+ int i,changed;
+
+ if(head&&start->loopend){
+ end=start->loopend;
+
+ if(DEBUG&1024){
+ printf("searching for loop-invariant code in loop from block %d to %d\n",start->index,end->index);
+ printf("head_fg=%d\n",head->index);
+ }
+ calc_movable(start,end);
+ /* erstmal kein IC invariant */
+ memset(invariant,0,dsize);
+
+ /* kennzeichnen, welche ICs in der Schleife liegen */
+ memset(inloop,0,dsize);
+ for(g=start;g;g=g->normalout){
+ for(p=g->start;p;p=p->next){
+ if(p->defindex) BSET(inloop,p->defindex);
+ if(p==g->end) break;
+ }
+ if(g==end) break;
+ }
+
+ do{
+ changed=0;
+ if(DEBUG&1024) printf("loop-invariant pass\n");
+
+ /* Schleifeninvariante ICs suchen */
+
+ for(g=start;g;g=g->normalout){
+ memcpy(rd_defs,g->rd_in,dsize);
+ for(p=g->start;p;p=p->next){
+ int k1,k2;
+ /* testen, ob IC neu als invariant markiert werden kann */
+ if(p->defindex&&p->code!=CALL&&p->code!=GETRETURN&&!BTST(invariant,p->defindex)){
+ if(!BTST(inloop,p->defindex)) ierror(0);
+ if(p->code==ADDRESS||!p->q1.flags||(p->q1.flags&(KONST|DREFOBJ))==KONST||(p->q1.flags&VARADR)){
+ k1=1;
+ }else{
+ if(!(p->q1.flags&VAR)){
+ k1=0;
+ }else{
+ i=p->q1.v->index;
+ if(p->q1.flags&DREFOBJ){
+ i+=vcount-rcount;
+ if(p->q1.dtyp&(VOLATILE|PVOLATILE))
+ k1=0;
+ else
+ k1=def_invariant(i,-1);
+ }else
+ k1=def_invariant(i,-1);
+ }
+ }
+ if(k1){
+ if(!p->q2.flags||(p->q2.flags&(KONST|DREFOBJ))==KONST||(p->q2.flags&VARADR)){
+ k2=1;
+ }else{
+ if(!(p->q2.flags&VAR)){
+ k2=0;
+ }else{
+ i=p->q2.v->index;
+ if(p->q2.flags&DREFOBJ){
+ i+=vcount-rcount;
+ if(p->q2.dtyp&(VOLATILE|PVOLATILE))
+ k2=0;
+ else
+ k2=def_invariant(i,-1);
+ }else
+ k2=def_invariant(i,-1);
+ }
+ }
+ }
+ if(k1&&k2&&!(ztyp(p)&VOLATILE)&&!(q1typ(p)&VOLATILE)){
+ if(DEBUG&1024){ printf("found loop-invariant IC:\n");pric2(stdout,p);}
+ if(!BTST(moved,p->defindex)&&(always_reached(start,end,g,p,0)||(!dangerous_IC(p)&&used_in_loop_only(start,end,&p->z)))){
+ if(p->z.flags&DREFOBJ){
+ if(p->z.flags&KONST)
+ k1=0;
+ else
+ k1=def_invariant(p->z.v->index,-1);
+ }else
+ k1=1;
+ /*if(DEBUG&1024) printf("always reached or used only in loop\n");*/
+ if(k1&&!BTST(not_movable,p->defindex)&&!(ztyp(p)&VOLATILE)&&(!(p->z.flags&VAR)||!p->z.v->reg)){
+ /*if(DEBUG&1024) printf("movable\n");*/
+ add_movable(p,head,MOVE_IC);
+ }else{
+ if(p->code==ADDRESS||(ISSCALAR(p->typf)&&(p->q2.flags||(p->q1.flags&DREFOBJ)))){
+ /*if(DEBUG&1024) printf("move computation out of loop\n");*/
+ if(!(disable&256))
+ add_movable(p,head,MOVE_COMP);
+ }
+ }
+ }else{
+ /* Wenn IC immer erreicht wird oder ungefaehrlich */
+ /* ist, kann man zumindest die Operation */
+ /* rausziehen, falls das lohnt. */
+ if(!BTST(moved,p->defindex)&&(!dangerous_IC(p)&&ISSCALAR(p->typf)&&(p->q2.flags||(p->q1.flags&DREFOBJ)||p->code==ADDRESS))){
+ /*if(DEBUG&1024) printf("move computation out of loop\n");*/
+ if(!(disable&256))
+ add_movable(p,head,MOVE_COMP);
+ }
+ }
+ BSET(invariant,p->defindex);
+ changed=1;
+ }
+ }
+
+ /* Das hier, um rd_defs zu aktualisieren. */
+ rd_change(p);
+
+ if(p==g->end) break;
+ }
+ if(g==end) break;
+ }
+ }while(changed);
+
+ }
+ return;
+}
+void add_sr(IC *p,flowgraph *fg,int i_var)
+/* Fuegt IC p, das aus der Schleife in Block fg lineare Fkt. der */
+/* Induktionsvariable i_var ist, in Liste ein. */
+/* Funktioniert als Stack. Da mit aeusseren Schleifen angefangen */
+/* wird, werden ICs zuerst in inneren Schleifen reduziert. Da ein */
+/* IC nur einmal reduziert wird, sollte dadurch das Problem eines */
+/* ICs, das potentiell in mehreren Schleifen reduziert werden */
+/* koennte, geloest werden. */
+{
+ srlist *new=mymalloc(sizeof(*new));
+ if(DEBUG&1024) printf("all:%p\n",(void*)new);
+ new->IC=p;
+ new->target_fg=fg;
+ new->ind_var=ind_vars[i_var];
+ new->next=first_sr;
+ new->hv=0;
+ first_sr=new;
+#if 0
+ if(last_sr){
+ last_sr->next=new;
+ last_sr=new;
+ }else{
+ first_sr=last_sr=new;
+ }
+#endif
+}
+int do_sr(int donothing)
+/* Durchlaufe die Liste aller strength-reduction-Kandidaten und */
+/* ersetze sie durch neue Induktionsvariablen. Dabei aufpassen, */
+/* falls ein IC schon von frequency-reduction bearbeitet wurde. */
+/* Ausserdem wird die Liste freigegeben. */
+{
+ IC **fglist; /* Letztes IC vor jedem Block */
+ IC *p;
+ flowgraph *g;
+ srlist *mf;
+ int changed=0;
+
+ if(!first_sr) return 0;
+
+ if(DEBUG&1024) printf("performing strength-reductions\n");
+
+ fglist=mymalloc((basic_blocks+1)*sizeof(*fglist));
+ p=0;
+ for(g=first_fg;g;g=g->normalout){
+ if(g->index>basic_blocks) ierror(0);
+ if(g->end) p=g->end;
+ fglist[g->index]=p;
+ }
+
+ while(first_sr){
+ Var *niv,*nstep;
+ type *t1,*t2;
+ IC *iv_ic,*new,*m;
+ int i,c;
+ p=first_sr->IC;
+ i=p->defindex;
+ /* Falls IC noch nicht verschoben und noch nicht reduziert wurde. */
+ if(!donothing&&!BTST(moved,i)&&p->code!=ASSIGN){
+ if(first_sr->hv){
+ /* Es wurde schon eine aequivalente Operation reduziert, wir */
+ /* koennen also dieselbe Hilfsvariable benutzen. */
+ p->code=ASSIGN;
+ p->q1.flags=VAR;
+ p->q1.v=first_sr->hv;
+ p->q1.val.vmax=l2zm(0L);
+ p->q2.flags=0;
+ p->q2.val.vmax=szof(p->z.v->vtyp);
+ p->typf=p->z.v->vtyp->flags;
+ /* Hilfsvariable wird jetzt auch benutzt. */
+ if(have_alias){
+ void *m=p->use_list;
+ p->use_cnt++;
+ p->use_list=mymalloc(p->use_cnt*VLS);
+ memcpy(&p->use_list[1],m,(p->use_cnt-1)*VLS);
+ free(m);
+ p->use_list[0].v=first_sr->hv;
+ p->use_list[0].flags=0;
+ }
+ }else{
+ int minus=0,q1t,q2t;
+ if(DEBUG&1024){ printf("performing strength-reduction on IC:\n");pric2(stdout,p);}
+ c=p->code;
+ g=first_sr->target_fg;
+ iv_ic=first_sr->ind_var;
+ /* Merken, wenn IC von der Form SUB x,ind_var->z */
+ if((c==SUB||c==SUBIFP)&&!compare_objs(&p->q2,&iv_ic->z,iv_ic->typf))
+ minus=1;
+ t1=new_typ();
+ t1->flags=p->typf;
+ if(c==ADDI2P||c==SUBIFP){
+ t1->flags=p->typf2;
+ t1->next=new_typ();
+ t1->next->flags=VOID;
+ }
+ niv=add_tmp_var(t1);
+ /* Suchen, ob es noch aequivalente Operationen gibt. */
+ /* Noch sehr ineffizient... */
+ q1t=q1typ(p);q2t=q2typ(p);
+ for(mf=first_sr->next;mf;mf=mf->next){
+ if(mf->target_fg==g&&mf->ind_var==iv_ic){
+ m=mf->IC;
+ if(c==m->code&&p->typf==m->typf&&
+ !compare_objs(&p->q1,&m->q1,q1t)&&
+ !compare_objs(&p->q2,&m->q2,q2t)){
+ if(mf->hv) ierror(0);
+ mf->hv=niv;
+ if(DEBUG&1024){ printf("equivalent operation\n");pric2(stdout,m);}
+ }
+ }
+ }
+ /* Initialisierung der Hilfsinduktionsvariablen */
+ new=new_IC();
+ *new=*p;
+ new->z.flags=VAR;
+ new->z.v=niv;
+ new->z.val.vmax=l2zm(0L);
+ /* IC benutzt dasselbe wie p und aendert nur niv. */
+ if(have_alias){
+ new->change_cnt=1;
+ new->change_list=mymalloc(VLS);
+ new->change_list[0].v=niv;
+ new->change_list[0].flags=0;
+ new->use_cnt=p->use_cnt;
+ new->use_list=mymalloc(new->use_cnt*VLS);
+ memcpy(new->use_list,p->use_list,new->use_cnt*VLS);
+ }
+ insert_IC_fg(g,fglist[g->index],new);
+ fglist[g->index]=m=new;
+ /* Ersetzen der Operation durch die Hilfsvariable */
+ p->code=ASSIGN;
+ p->typf=t1->flags;
+ p->q1=m->z;
+ p->q2.flags=0;
+ p->q2.val.vmax=szof(t1);
+ /* Benutzt jetzt auch Hilfsvariable. */
+ if(have_alias){
+ void *mr=p->use_list;
+ p->use_cnt++;
+ p->use_list=mymalloc(p->use_cnt*VLS);
+ memcpy(&p->use_list[1],mr,(p->use_cnt-1)*VLS);
+ free(mr);
+ p->use_list[0].v=niv;
+ p->use_list[0].flags=0;
+ }
+ /* Berechnen der Schrittweite fuer Hilfsvariable */
+ if(c==MULT||c==LSHIFT){
+ int styp;
+ t2=new_typ();
+ t2->flags=iv_ic->typf;
+ nstep=add_tmp_var(t2);
+ new=new_IC();
+ new->line=iv_ic->line;
+ new->file=iv_ic->file;
+ new->code=MULT;
+ new->typf=p->typf;
+ new->z.flags=VAR;
+ new->z.v=nstep;
+ new->z.val.vmax=l2zm(0L);
+ if(!compare_objs(&m->q1,&iv_ic->z,iv_ic->typf)){
+ new->q1=m->q2;
+ styp=q2typ(m);
+ }else{
+ new->q1=m->q1;
+ styp=m->typf;
+ }
+ if(!compare_objs(&iv_ic->q1,&iv_ic->z,iv_ic->typf)) new->q2=iv_ic->q2;
+ else new->q2=iv_ic->q1;
+ if(c==LSHIFT){
+ if((new->q1.flags&(KONST|DREFOBJ))!=KONST) ierror(0);
+ eval_const(&new->q1.val,styp);
+ gval.vmax=zmlshift(Z1,vmax);
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q1.val,new->typf);
+ }
+ /* Benutzt dasselbe wie iv_ic und m. */
+ if(have_alias){
+ new->use_cnt=iv_ic->use_cnt+m->use_cnt;
+ new->use_list=mymalloc(new->use_cnt*VLS);
+ memcpy(new->use_list,iv_ic->use_list,iv_ic->use_cnt*VLS);
+ memcpy(&new->use_list[iv_ic->use_cnt],m->use_list,m->use_cnt*VLS);
+ new->change_cnt=1;
+ new->change_list=mymalloc(VLS);
+ new->change_list[0].v=nstep;
+ new->change_list[0].flags=0;
+ }
+ insert_IC_fg(g,fglist[g->index],new);
+ fglist[g->index]=m=new;
+ }
+ /* Erhoehen der Hilfsvariable um Schrittweite */
+ new=new_IC();
+ new->line=iv_ic->line;
+ new->file=iv_ic->file;
+
+ new->code=iv_ic->code;
+ if(minus){
+ switch(new->code){
+ case ADD: new->code=SUB; break;
+ case SUB: new->code=ADD; break;
+ case ADDI2P: new->code=SUBIFP; break;
+ case SUBIFP: new->code=ADDI2P; break;
+ }
+ }
+ if(ISPOINTER(t1->flags)){
+ if(new->code==ADD) new->code=ADDI2P;
+ if(new->code==SUB) new->code=SUBIFP;
+ new->typf=t1->flags;
+ }
+ new->typf=iv_ic->typf;
+ new->q1.flags=VAR;
+ new->q1.v=niv;
+ new->typf2=niv->vtyp->flags;
+ new->q1.val.vmax=l2zm(0L);
+ new->z=new->q1;
+ if(c==MULT||c==LSHIFT){
+ new->q2=m->z;
+ }else{
+ if(!compare_objs(&iv_ic->q1,&iv_ic->z,iv_ic->typf)) new->q2=iv_ic->q2;
+ else new->q2=iv_ic->q1;
+ }
+ if(have_alias){
+ new->use_cnt=iv_ic->use_cnt+m->use_cnt;
+ new->use_list=mymalloc(new->use_cnt*VLS);
+ memcpy(new->use_list,iv_ic->use_list,iv_ic->use_cnt*VLS);
+ memcpy(&new->use_list[iv_ic->use_cnt],m->use_list,m->use_cnt*VLS);
+ new->change_cnt=1;
+ new->change_list=mymalloc(VLS);
+ new->change_list[0].v=niv;
+ new->change_list[0].flags=0;
+ }
+ /* Flussgraph muss nur bei den Schleifenkoepfen ok sein. */
+ insert_IC(iv_ic,new);
+ changed|=2;
+ }
+ }
+
+ mf=first_sr->next;
+ free(first_sr);
+ first_sr=mf;
+ }
+ free(fglist);
+ return changed;
+}
+void strength_reduction(flowgraph *start,flowgraph *end,flowgraph *head)
+/* Ersetzen von Operationen mit einer Induktionsvariablen und einem */
+/* schleifeninvarianten Operanden durch eine zusaetzliche */
+/* Hilfsinduktionsvariable. */
+{
+ flowgraph *g;IC *p;
+ int i;
+ if(DEBUG&1024) printf("performing strength_reduction on blocks %d to %d\n",start->index,end->index);
+ for(i=0;i<vcount;i++) ind_vars[i]=0;
+ /* Nach Induktionsvariablen suchen. */
+ for(g=start;g;g=g->normalout){
+ memcpy(rd_defs,g->rd_in,dsize);
+ for(p=g->start;p;p=p->next){
+ int c=p->code;
+ if(c==ADD||c==ADDI2P||c==SUB||c==SUBIFP){
+ /* TODO: what is possible/useful with floating point induction variables? */
+ if(!compare_objs(&p->q1,&p->z,p->typf)&&!ISFLOAT(p->typf)){
+ if(DEBUG&1024){printf("possible induction:\n");pric2(stdout,p);}
+ if(p->q2.flags&VAR){
+ i=p->q2.v->index;
+ if(p->q2.flags&DREFOBJ) i+=vcount-rcount;
+ }
+ if((p->z.flags&VAR)&&((p->q2.flags&(VAR|VARADR))!=VAR||def_invariant(i,-1))){
+ i=p->z.v->index;
+ if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+ if(def_invariant(i,p->defindex)){
+ if(DEBUG&1024) {printf("found basic induction var:\n");pric2(stdout,p);}
+ ind_vars[i]=p;
+ }
+ }
+ }
+ if(USEQ2ASZ&&c!=SUB&&c!=SUBIFP&&!compare_objs(&p->q2,&p->z,p->typf)){
+ if(DEBUG&1024){printf("possible induction:\n");pric2(stdout,p);}
+ if(p->q1.flags&VAR){
+ i=p->q1.v->index;
+ if(p->q1.flags&DREFOBJ) i+=vcount-rcount;
+ }
+ if((p->q1.flags&(VAR|VARADR))!=VAR||def_invariant(i,-1)){
+ i=p->z.v->index;
+ if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+ if(def_invariant(i,p->defindex)){
+ if(DEBUG&1024) {printf("found basic induction var:\n");pric2(stdout,p);}
+ ind_vars[i]=p;
+ }
+ }
+ }
+ }
+
+ /* Das hier, um rd_defs zu aktualisieren. */
+ rd_change(p);
+
+ if(p==g->end) break;
+ }
+ if(g==end) break;
+ }
+
+ if(disable&1024) return;
+
+ /* Nach reduzierbaren Operationen suchen */
+ for(g=start;g;g=g->normalout){
+ memcpy(rd_defs,g->rd_in,dsize);
+ for(p=g->start;p;p=p->next){
+ if(((p->code==MULT||p->code==LSHIFT)||((p->code==ADD||p->code==SUB||p->code==ADDI2P||p->code==SUBIFP)&&!(disable&512)))&&
+ ((!ISFLOAT(p->typf))||fp_assoc)&&!(p->flags&EFF_IC) ){
+ int k1,k2,iv;
+ if((p->q1.flags&(VAR|VARADR))==VAR){
+ i=p->q1.v->index;
+ if(p->q1.flags&DREFOBJ) i+=vcount-rcount;
+ if(ind_vars[i]){
+ k1=1;iv=i;
+ }else if(def_invariant(i,-1))
+ k1=2;
+ else
+ k1=0;
+ }else
+ k1=2;
+ if((p->q2.flags&(VAR|VARADR))==VAR){
+ i=p->q2.v->index;
+ if(p->q2.flags&DREFOBJ) i+=vcount-rcount;
+ if(ind_vars[i]){
+ k2=1;iv=i;
+ }else if(def_invariant(i,-1))
+ k2=2;
+ else
+ k2=0;
+ }else
+ k2=2;
+ if(p->code==LSHIFT&&(p->q2.flags&(KONST|DREFOBJ))!=KONST)
+ k2=0;
+ if(p->z.flags&VAR){
+ /* Aufpassen, dass eine Induktion nicht selbst reduziert */
+ /* wird. */
+ i=p->z.v->index;
+ if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+ if(ind_vars[i]) k1=0;
+ }
+ if(k1+k2==3){
+ /* if(DEBUG&1024) {printf("could perform strength-reduction on:\n");pric2(stdout,p);}*/
+ add_sr(p,head,iv);
+ }
+ }
+ /* Das hier, um rd_defs zu aktualisieren. */
+ rd_change(p);
+
+ if(p==g->end) break;
+ }
+ if(g==end) break;
+ }
+}
+void copy_code(IC *start,IC *end,IC *dest,int n,IC *ignore)
+/* Kopiert Code von start bis end n-mal hinter dest. Generiert */
+/* entsprechend neue Labels. Allerdings wird der Flussgraph und */
+/* aliasing-info nicht angepasst und muss danach neu generiert werden. */
+/* IC ignore wird nicht kopiert. */
+{
+ int firstl=0,lastl=0,*larray,i,j;
+ IC *p,*new,*current;
+ if(DEBUG&1024) printf("copy_code %d times\n",n);
+ /* Feststellen, welche Labels in der Schleife definiert werden. */
+ for(p=start;p;p=p->next){
+ if(p->code==LABEL){
+ if(firstl==0||firstl>p->typf) firstl=p->typf;
+ if(lastl ==0|| lastl<p->typf) lastl =p->typf;
+ }
+ if(p==end) break;
+ }
+ if(DEBUG&1024) printf("firstl=%d, lastl=%d\n",firstl,lastl);
+ larray=mymalloc((lastl-firstl+1)*sizeof(*larray));
+ for(i=0;i<=lastl-firstl;i++) larray[i]=0;
+ for(p=start;p;p=p->next){
+ if(p->code==LABEL) larray[p->typf-firstl]=1;
+ if(p==end) break;
+ }
+ current=dest;
+ /* Hauptschleife. */
+ for(i=0;i<n;i++){
+ /* Neue Labels erzeugen. */
+ for(j=0;j<=lastl-firstl;j++)
+ if(larray[j]) larray[j]=++label;
+ /* Code kopieren (rueckwaerts). */
+ for(p=start;p;p=p->next){
+ if(p!=ignore){
+ new=new_IC();
+ *new=*p;
+ p->copy=new;
+ /* Fuer free_alias. */
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ /* Evtl. Label anpassen. */
+ if(p->code>=LABEL&&p->code<=BRA){
+ if(p->typf>=firstl&&p->typf<=lastl&&larray[p->typf-firstl])
+ new->typf=larray[p->typf-firstl];
+ }
+ if(p->code==CALL){
+ int i;
+ new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+ for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=p->arg_list[i]->copy;
+ new->call_list=mymalloc(new->call_cnt*sizeof(*new->call_list));
+ memcpy(new->call_list,p->call_list,new->call_cnt*sizeof(*new->call_list));
+ }
+ insert_IC(current,new);
+ current=new;
+ }
+ if(p==end) break;
+ }
+ }
+ free(larray);
+}
+void add_ur(int flags,long total,long unroll,flowgraph *start,flowgraph *head,IC *cmp,IC *branch,IC *ind)
+/* Fuegt Daten fuer loop-unrolling in Stack ein. */
+{
+ urlist *new=mymalloc(sizeof(urlist));
+ if(DEBUG&1024) printf("add_ur, flags=%d\n",flags);
+ new->flags=flags;
+ new->total=total;
+ new->unroll=unroll;
+ new->start=start;
+ new->head=head;
+ new->cmp=cmp;
+ new->branch=branch;
+ new->ind=ind;
+ new->next=first_ur;
+ first_ur=new;
+}
+
+static int decide_shorten(int t,flowgraph *start,IC *ind,IC *cmp)
+{
+ IC *p;
+ Var *oiv=ind->z.v;
+ int cnt=0;
+ for(p=start->start;p;p=p->next){
+ if(p==ind) continue;
+ if(p==cmp) break;
+ if((p->q1.flags&VAR)&&p->q1.v==oiv){
+ if(!(p->code==CONVERT&&!compare_objs(&p->q1,&ind->q1,p->typf)&&(p->typf&NQ)==(t&NQ)))
+ cnt++;
+ }
+ if((p->q2.flags&VAR)&&p->q2.v==oiv){
+ if(!((p->code==ADDI2P||p->code==SUBIFP)&&!compare_objs(&p->q2,&ind->q1,p->typf)&&(p->typf&NQ)>=MINADDI2P))
+ cnt++;
+ }
+ if((p->z.flags&VAR)&&p->z.v==oiv) cnt++;
+ }
+ return cnt==0;
+}
+
+static int do_shorten()
+{
+ int changed=0; urlist *m;
+ for(m=first_ur;m;m=m->next){
+ if(m->flags&UNROLL_SHORTEN){
+ /* use shorter induction variable */
+ type st={CHAR};
+ int cnt=0;
+ Var *niv,*oiv;IC *new,*p,*cmp=m->cmp,*ind=m->ind;
+ if(DEBUG&1024) printf("shorten induction variable to %s %s\n",(m->total&UNSIGNED)?"unsigned":"signed",typname[m->total&NQ]);
+ st.flags=m->total;
+ niv=add_tmp_var(clone_typ(&st));
+ new=new_IC();
+ new->code=CONVERT;
+ new->q1=ind->z;
+ new->z.flags=VAR;
+ new->z.val.vmax=Z0;
+ new->z.v=niv;
+ new->typf2=ind->typf;
+ new->typf=st.flags;
+ insert_IC(m->head->end,new);
+ ind->q1=new->z;
+ ind->z=new->z;
+ ind->typf=st.flags;
+ cmp->q1=new->z;
+ eval_const(&cmp->q2.val,cmp->typf);
+ cmp->typf=st.flags;
+ insert_const(&cmp->q2.val,cmp->typf);
+ oiv=new->q1.v;
+ /* replace uses of the old induction variable that do not need conversions */
+ for(p=m->start->start;p;p=p->next){
+ if(p==cmp) break;
+ if((p->code==ADDI2P||p->code==SUBIFP)&&!compare_objs(&p->q2,&new->q1,p->typf)&&(p->typf&NQ)>=MINADDI2P){
+ if(DEBUG&1024){
+ printf("replace use of large induction variable (ADDI2P):\n");
+ pric2(stdout,p);
+ }
+ p->q2=new->z;
+ p->typf=new->typf;
+ }
+ if(p->code==CONVERT&&!compare_objs(&p->q1,&new->q1,p->typf)&&(p->typf&NQ)==(new->typf&NQ)){
+ if(DEBUG&1024){
+ printf("replace use of large induction variable (CONVERT):\n");
+ pric2(stdout,p);
+ }
+ p->q1=new->z;
+ p->code=ASSIGN;
+ p->q2.val.vmax=sizetab[p->typf&NQ];
+ }
+ if((p->q1.flags&VAR)&&p->q1.v==oiv) cnt++;
+ if((p->q2.flags&VAR)&&p->q2.v==oiv) cnt++;
+ if((p->z.flags&VAR)&&p->z.v==oiv) cnt++;
+ }
+ p=new_IC();
+ p->code=CONVERT;
+ p->q1=new->z;
+ p->z=new->q1;
+ p->typf=new->typf2;
+ p->typf2=new->typf;
+ if(cnt||(m->flags&MULTIPLE_EXITS))
+ insert_IC(ind,p);
+ else
+ insert_IC(m->branch,p);
+
+ m->flags=0;
+ changed|=2;
+ }
+ }
+ return changed;
+}
+
+int do_unroll(int donothing)
+/* Fuehrt loop-unrolling durch. Wenn donothing!=0, wird die Liste nur */
+/* freigegeben. */
+{
+ int changed=0; urlist *m;
+ IC *div;
+ while(m=first_ur){
+ int flags=m->flags;
+ long total=m->total,unroll=m->unroll;
+ flowgraph *start=m->start,*head=m->head;
+ IC *cmp=m->cmp,*branch=m->branch,*ind=m->ind;
+ if(donothing) flags=0;
+ if(flags&UNROLL_COMPLETELY){
+ /* Schleife komplett ausrollen. */
+ if(DEBUG&1024) printf("unroll loop completely\n");
+ copy_code(start->start->next,cmp->prev,start->start,total-1,0);
+ if(DEBUG&1024) printf("removing loop branch\n");
+ remove_IC(branch);
+ if(!cmp->z.flags){
+ remove_IC(cmp);
+ if(DEBUG&1024) printf("removing loop compare\n");
+ }
+ changed|=1;
+ }
+
+ if(flags&UNROLL_MODULO){
+ /* Schleife teilweise ausrollen. */
+ if(DEBUG&1024) printf("unroll loop partially, n=%ld,r=%ld\n",unroll,total%unroll);
+ if(unroll>1){
+ if((flags&(IND_ONLY_COUNTS|MULTIPLE_EXITS))==IND_ONLY_COUNTS){
+ IC *new=new_IC();
+ copy_code(start->start->next,cmp->prev,head->start,total%unroll,ind);
+ *new=*ind;
+ new->use_cnt=new->change_cnt=0;
+ new->use_list=new->change_list=0;
+ if(!(ind->q2.flags&KONST)) ierror(0);
+ eval_const(&ind->q2.val,ind->typf);
+ if(ind->typf&UNSIGNED){
+ gval.vumax=zummult(vumax,ul2zum((unsigned long)(total%unroll)));
+ eval_const(&gval,(UNSIGNED|MAXINT));
+ }else{
+ gval.vumax=zummult(vumax,ul2zum((unsigned long)(total%unroll)));
+ eval_const(&gval,MAXINT);
+ }
+ insert_const(&new->q2.val,ind->typf);
+ insert_IC(head->end,new);
+ copy_code(start->start->next,cmp->prev,start->start,unroll-1,ind);
+ eval_const(&ind->q2.val,ind->typf);
+ if(ind->typf&UNSIGNED){
+ gval.vumax=zummult(vumax,ul2zum((unsigned long)(unroll)));
+ eval_const(&gval,(UNSIGNED|MAXINT));
+ }else{
+ gval.vumax=zummult(vumax,ul2zum((unsigned long)(unroll)));
+ eval_const(&gval,MAXINT);
+ }
+ insert_const(&ind->q2.val,ind->typf);
+ changed|=1;
+ }else{
+ copy_code(start->start->next,cmp->prev,head->start,total%unroll,0);
+ copy_code(start->start->next,cmp->prev,start->start,unroll-1,0);
+ changed|=1;
+ }
+ }
+ }
+ if(flags&UNROLL_INVARIANT){
+ IC *new,*mc,*mn; Var *v; int out=++label,code;
+ long i; type *t;static type tptrdiff={0};
+ IC tmp;
+ if(DEBUG&1024) printf("unrolling non-constant loop\n");
+ if(ISPOINTER(cmp->typf)){
+ tptrdiff.flags=PTRDIFF_T(cmp->typf);
+ t=&tptrdiff;
+ }else{
+ if(cmp->q1.flags&VAR)
+ t=cmp->q1.v->vtyp;
+ else
+ t=cmp->q2.v->vtyp;
+ }
+ v=add_tmp_var(clone_typ(t));
+ /* branch dient hier teilweise als leere Schablone. */
+ /* Label an Schleifenausgang setzen. */
+ new=new_IC();
+ *new=*branch;
+ new->q1.flags=0;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=LABEL;
+ new->typf=out;
+ insert_IC(branch,new);
+ /* Test vor die unroll-Variante. */
+ new=new_IC(); *new=*branch;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ if(branch->code==BLT) new->code=BGE;
+ if(branch->code==BLE) new->code=BGT;
+ if(branch->code==BGT) new->code=BLE;
+ if(branch->code==BGE) new->code=BLT;
+ if(branch->code==BEQ) ierror(0);
+ if(branch->code==BNE) ierror(0);
+ code=branch->code;
+ mc=new;
+ new->typf=out;
+ insert_IC(head->start,new);
+ new=new_IC(); *new=*cmp;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ insert_IC(head->start,new);
+ /* Einsprungpunkte fuer die Modulos. */
+ label+=unroll;
+ for(i=1;i<unroll;i++){
+ copy_code(start->start->next,cmp->prev,head->start,1,0);
+ new=new_IC(); *new=*branch;
+ new->q1.flags=0;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=LABEL;
+ new->typf=out+i;
+ insert_IC(head->start,new);
+ }
+ /* Testen, welches Modulo. */
+ for(i=unroll-2;i>=0;i--){
+ new=new_IC(); *new=*branch;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=BEQ;
+ if(i>0) new->typf=out+i;
+ else new->typf=start->start->typf;
+ insert_IC(head->start,new);
+ new=new_IC(); *new=*branch;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ if(SWITCHSUBS) gval.vint=zm2zi(l2zm(1L));
+ else gval.vint=zm2zi(l2zm(i));
+ eval_const(&gval,INT);
+ new->q1.flags=VAR;
+ new->q1.v=v;
+ new->q1.val.vmax=l2zm(0L);
+ new->typf=t->flags;
+ if(SWITCHSUBS||i==0){
+ new->code=TEST;
+ insert_IC(head->start,new);
+ if(i>0){
+ new=new_IC();
+ *new=*head->start->next;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=SUB;
+ new->z=new->q1;
+ new->q2.flags=KONST;
+ insert_const(&new->q2.val,new->typf&NU);
+ insert_IC(head->start,new);
+ }
+ }else{
+ new->code=COMPARE;
+ new->q2.flags=KONST;
+ insert_const(&new->q2.val,new->typf&NU);
+ insert_IC(head->start,new);
+ }
+ }
+ /* Durchlaeufe modulo unroll berechnen. */
+ new=new_IC(); *new=*branch;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=AND;
+ new->typf=t->flags;
+ new->q1.flags=VAR;
+ new->q1.v=v;
+ new->q1.val.vmax=l2zm(0L);
+ new->z=new->q1;
+ new->q2.flags=KONST;
+ gval.vmax=l2zm(unroll-1);
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q2.val,new->typf);
+ insert_IC(head->start,new);
+ new=new_IC();
+ *new=*ind;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=DIV;
+ div=new;
+ new->q1=head->start->next->z;
+ new->z=new->q1;
+ insert_IC(head->start,new);
+ tmp=*new;
+ fix_shortop(head,new);
+ new=new_IC();
+ *new=tmp;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=ADD;
+ insert_IC(head->start,new);
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ if(code==BLT||code==BGT){
+ new=new_IC();
+ *new=*head->start->next;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=SUB;
+ gval.vmax=l2zm(1L);
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q2.val,new->typf);
+ insert_IC(head->start,new);
+ }
+ new=new_IC();
+ *new=tmp;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=SUB;
+ if(t==&tptrdiff)
+ new->code=SUBPFP;
+
+ if(!compare_objs(&ind->z,&cmp->q1,new->typf)){
+ if(code==BLT||code==BLE){
+ new->q1=cmp->q2;new->q2=ind->z;
+ }else{
+ new->q2=cmp->q2;new->q1=ind->z;
+ }
+ }else{
+ if(code==BLT||code==BLE){
+ new->q1=cmp->q1;new->q2=ind->z;
+ }else{
+ new->q2=cmp->q1;new->q1=ind->z;
+ }
+ }
+#if 0
+ if(ind->code==SUB){
+ obj o;
+ o=new->q1;new->q1=new->q2;new->q2=o;
+ }
+#endif
+ if(!new->q1.flags){
+ if(!new->q2.flags) ierror(0);
+ new->q1.flags=KONST;
+ gval.vmax=l2zm(0L);
+ eval_const(&gval,new->typf);
+ insert_const(&new->q1.val,new->typf);
+ }
+ if(!new->q2.flags){
+ if(!new->q1.flags) ierror(0);
+ new->q2.flags=KONST;
+ gval.vmax=l2zm(0L);
+ eval_const(&gval,new->typf);
+
+ insert_const(&new->q2.val,new->typf);
+ }
+ insert_IC(head->start,new);
+ new=new_IC();
+ *new=*mc;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->typf=out+1;
+ insert_IC(head->start,new);
+ new=new_IC();
+ *new=*cmp; new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ insert_IC(head->start,new);
+ if((flags&(IND_ONLY_COUNTS|MULTIPLE_EXITS))==IND_ONLY_COUNTS){
+ if(!(ind->q2.flags&KONST)) ierror(0);
+ copy_code(start->start->next,cmp->prev,start->start,unroll-1,ind);
+ eval_const(&ind->q2.val,ind->typf);
+ if(ind->typf&UNSIGNED){
+ gval.vumax=zummult(vumax,ul2zum((unsigned long)(unroll)));
+ eval_const(&gval,(UNSIGNED|MAXINT));
+ }else{
+ gval.vumax=zummult(vumax,ul2zum((unsigned long)(unroll)));
+ eval_const(&gval,MAXINT);
+ }
+ insert_const(&ind->q2.val,ind->typf);
+ changed|=2;
+ }else{
+ copy_code(start->start->next,cmp->prev,start->start,unroll-1,0);
+ changed|=2;
+ }
+ div->typf|=UNSIGNED;
+ }
+ if(flags&UNROLL_REVERSE){
+ IC *new,*mc; Var *v; int out=++label,code;
+ long i; type *t;static type tptrdiff={0};
+ IC tmp;
+ if(DEBUG&1024) printf("reversing loop\n");
+ if(ISPOINTER(cmp->typf)){
+ tptrdiff.flags=PTRDIFF_T(cmp->typf);
+ t=&tptrdiff;
+ }else{
+ if(cmp->q1.flags&VAR)
+ t=cmp->q1.v->vtyp;
+ else
+ t=cmp->q2.v->vtyp;
+ }
+ v=add_tmp_var(clone_typ(t));
+ new=new_IC();
+ *new=*ind;
+ new->code=SUB;
+ new->typf=t->flags;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->q1.flags=VAR;
+ new->q1.v=v;
+ new->q1.val.vmax=l2zm(0L);
+ new->z=new->q1;
+ new->q2.flags=KONST;
+ gval.vmax=l2zm(1L);
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q2.val,new->typf);
+ insert_IC(cmp->prev,new);
+ code=branch->code;
+#if HAVE_WANTBNE
+ branch->code=BNE;
+#else
+ branch->code=BGT;
+#endif
+ /* Durchlaeufe berechnen. */
+ new=new_IC();
+ *new=*ind;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=DIV;
+ div=new;
+ new->q1.flags=VAR;
+ new->q1.v=v;
+ new->q1.val.vmax=l2zm(0L);
+ new->z=new->q1;
+ insert_IC(head->start,new);
+ tmp=*new;
+ fix_shortop(head,new);
+ new=new_IC();
+ *new=tmp;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=ADD;
+ insert_IC(head->start,new);
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ if(code==BLT||code==BGT||code==BNE){
+ IC *a=head->start->next;
+ gval.vmax=l2zm(1L);
+ eval_const(&gval,MAXINT);
+ insert_const(&gval,a->typf);
+ calc(SUB,a->typf,&a->q2.val,&gval,&a->q2.val,0);
+ }
+ new=new_IC();
+ *new=tmp;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->code=SUB;
+ if(t==&tptrdiff)
+ new->code=SUBPFP;
+
+ if(!compare_objs(&ind->z,&cmp->q1,new->typf)){
+ if(code==BLT||code==BLE||(code==BNE&&(ind->code==ADD||ind->code==ADDI2P))){
+ new->q1=cmp->q2;new->q2=ind->z;
+ }else{
+ new->q2=cmp->q2;new->q1=ind->z;
+ }
+ }else{
+ if(code==BLT||code==BLE||(code==BNE&&(ind->code==ADD||ind->code==ADDI2P))){
+ new->q1=cmp->q1;new->q2=ind->z;
+ }else{
+ new->q2=cmp->q1;new->q1=ind->z;
+ }
+ }
+#if 0
+ if(ind->code==SUB){
+ obj o;
+ o=new->q1;new->q1=new->q2;new->q2=o;
+ }
+#endif
+ if(!new->q1.flags||!new->q2.flags) ierror(0);
+ insert_IC(head->start,new);
+ cmp->code=TEST;
+ cmp->q1.flags=VAR;
+ cmp->q1.v=v;
+ cmp->q1.val.vmax=l2zm(0L);
+ cmp->q2.flags=0;
+ div->typf|=UNSIGNED;
+ changed|=2;
+ }
+ first_ur=m->next;
+ free(m);
+ }
+ return changed;
+}
+
+void unroll(flowgraph *start,flowgraph *head)
+/* Versucht loop-unrolling. */
+{
+ flowlist *lp;flowgraph *end,*g;IC *p,*m,*branch,*cmp;
+ obj *o,*e,*cc; union atyps init_val,end_val,step_val;
+ bvtype *tmp;
+ long dist,step,ic_cnt,n,small_type;
+ int bflag=0,t=0,i,flags=0; /* 1: sub, 2: init_val gefunden */
+ int ind_only_counts,multiple_exits,cfl;
+ end=start->loopend;
+ if(DEBUG&1024) printf("checking for possible unrolling from %d to %d\n",start->index,end->index);
+ if(end->end->code==BRA){
+ if(DEBUG&1024) printf("loop ends with BRA\n");
+ return;
+ }
+ for(lp=start->in;lp;lp=lp->next)
+ if(lp->graph->index>start->index&&lp->graph->index<=end->index&&lp->graph!=end) return;
+ if(DEBUG&1024) printf("only one backward-branch\n");
+ e=0; p=end->end; cfl=0;
+ do{
+ if(p->code>=BEQ&&p->code<BRA){ branch=p;bflag=p->code;cc=&p->q1; cfl=1;}
+ if(p->code==TEST){
+ if(!cfl) return;
+ if(compare_objs(cc,&p->z,p->typf)) return;
+ o=&p->q1;t=p->typf;cmp=p;
+ end_val.vmax=l2zm(0L); eval_const(&end_val,MAXINT);
+ insert_const(&end_val,t);
+ break;
+ }
+ if(p->code==COMPARE){
+ if(!cfl) return;
+ if(compare_objs(cc,&p->z,p->typf)) return;
+ cmp=p;
+ if(p->q1.flags&VAR){
+ if(ind_vars[p->q1.v->index]){
+ o=&p->q1;t=p->typf;
+ e=&p->q2;
+ break;
+ }
+ }
+ if(p->q2.flags&VAR){
+ if(ind_vars[p->q2.v->index]){
+ o=&p->q2;t=p->typf;
+ e=&p->q1;
+ if(bflag==BLT) bflag=BGT;
+ if(bflag==BLE) bflag=BGE;
+ if(bflag==BGT) bflag=BLT;
+ if(bflag==BGE) bflag=BLE;
+ break;
+ }
+ }
+ return;
+ }
+ if(p==end->start) return;
+ p=p->prev;
+ }while(p);
+ if(!e||(e->flags&KONST)){
+ if(e) end_val=e->val;
+ if(DEBUG&1024) printf("end condition is constant\n");
+ }else{
+ if(!(e->flags&VAR)) return;
+ i=e->v->index;
+ if(e->flags&DREFOBJ) i+=vcount-rcount;
+ if(DEBUG&1024) printf("testing end-condition\n");
+ memcpy(rd_defs,end->rd_in,dsize);
+ for(m=end->start;m;m=m->next){
+ if(m==cmp){
+ if(DEBUG&1024) pric2(stdout,m);
+ if(!def_invariant(i,-1)) return;
+ if(DEBUG&1024) printf("end condition loop-invariant\n");
+ break;
+ }
+ rd_change(m);
+ if(m==end->end) ierror(0);
+ }
+ }
+ if((o->flags&(VAR|DREFOBJ))!=VAR) return;
+ p=ind_vars[o->v->index];
+ if(!p) return;
+ if(compare_objs(o,&p->z,t)) return;
+ if(DEBUG&1024) printf("loop condition only dependant on induction var\n");
+ if(!(p->q2.flags&KONST)) return;
+ if(DEBUG&1024) printf("induction is constant\n");
+ ind_only_counts=IND_ONLY_COUNTS;
+ multiple_exits=0;
+ for(ic_cnt=0,g=start;g;g=g->normalout){
+ for(m=g->start;m;m=m->next){
+ if(m!=p&&m!=cmp&&ind_only_counts){
+ int i;
+ for(i=0;i<m->use_cnt;i++){
+ if(m->use_list[i].v==p->q1.v){
+ if(DEBUG&1024){printf("use of ind_var:");pric2(stdout,m);}
+ ind_only_counts=0;break;
+ }
+ }
+ }
+ if(m==p&&!always_reached(start,end,g,p,1)) return;
+ ic_cnt++;
+ if(m==g->end) break;
+ }
+ if(g==end) break;
+ if(!multiple_exits&&g->branchout&&(g->branchout->index<start->index||g->branchout->index>end->index))
+ multiple_exits=MULTIPLE_EXITS;
+ }
+ ic_cnt-=2; /* Branch und Test */
+ if(DEBUG&1024) printf("induction always reached\n");
+ if(ind_only_counts&&(DEBUG&1024)) printf("induction variable only used as counter\n");
+ if(multiple_exits&&(DEBUG&1024)) printf("loop has multiple exits\n");
+ if(DEBUG&1024) printf("ICs in loop: %ld\n",ic_cnt);
+ step_val=p->q2.val;
+ if(p->code==SUB) flags|=1;
+ if(start->start->code==LABEL&&(start->start->flags&LOOP_COND_TRUE)&&e&&ind_only_counts){
+ if(e->flags&KONST)
+ eval_const(&e->val,t);
+ if(!(e->flags&KONST)||!zmeqto(vmax,l2zm(0L))||!zumeqto(vumax,ul2zum(0UL))||!zldeqto(vldouble,d2zld(0.0))){
+ int bc=branch->code;
+ eval_const(&step_val,t);
+ if((!(flags&1)&&(bc==BLT||bc==BLE))
+ ||((flags&1)&&(bc==BGT||bc==BGE))
+ ||(bc==BNE&&zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL)))){
+ if((t&UNSIGNED)||zmleq(l2zm(0L),vmax)){
+ if(decide_reverse(vmax)){
+ add_ur(UNROLL_REVERSE|ind_only_counts|multiple_exits,0,1,start,head,cmp,branch,p);
+ return;
+ }
+ }
+ }
+ }
+ }
+ if(!e||(e->flags&KONST)){
+ IC tmpic;
+ i=p->z.v->index;
+ if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+ memcpy(rd_defs,head->rd_out,dsize);
+ tmpic=*p;
+ if(propagate(&tmpic,&tmpic.z,1,1)){
+ init_val=tmpic.z.val;
+ }else{
+ goto inv;
+ }
+ if(DEBUG&1024){
+ printf("loop number determinable\n");
+ printf("init_val: ");printval(stdout,&init_val,t);
+ printf("\nend_val: ");printval(stdout,&end_val,t);
+ printf("\nstep_val: ");printval(stdout,&step_val,t);
+ printf("\nflags=%d bflag=%d\n",flags,bflag);
+ }
+ /* Nur integers als Induktionsvariablen. */
+ if(!ISINT(t)) goto inv;
+ /* Distanz und Step werden als long behandelt, deshalb pruefen, ob */
+ /* alles im Bereich des garantierten Mindestwerte fuer long. */
+ /* Wenn man hier die Arithmetik der Zielmaschine benutzen wuerde, */
+ /* koennte man theoretisch mehr Faelle erkennen, aber das waere */
+ /* recht popelig und man muss sehr aufpassen. */
+ if(t&UNSIGNED){
+ eval_const(&step_val,t);
+ if(!zumleq(vumax,l2zm(2147483647))) return;
+ step=zum2ul(vumax);
+ if(flags&1) step=-step;
+ eval_const(&end_val,t);
+ if(!zumleq(vumax,l2zm(2147483647))) goto inv;
+ dist=zum2ul(vumax);
+ eval_const(&init_val,t);
+ if(!zumleq(vumax,l2zm(2147483647))) goto inv;
+ dist-=zum2ul(vumax);
+ }else{
+ eval_const(&step_val,t);
+ if(!zmleq(vmax,l2zm(2147483647))) return;
+ if(zmleq(vmax,l2zm(-2147483647))) return; /* eins weniger als moeglich waere */
+ step=zm2l(vmax);
+ if(flags&1) step=-step;
+ eval_const(&end_val,t);
+ if(!zmleq(vmax,l2zm(2147483647/2))) goto inv;
+ if(zmleq(vmax,l2zm(-2147483647/2))) goto inv; /* eins weniger als moeglich waere */
+ dist=zm2l(vmax);
+ eval_const(&init_val,t);
+ if(!zmleq(vmax,l2zm(2147483647/2))) goto inv;
+ if(zmleq(vmax,l2zm(-2147483647/2))) goto inv; /* eins weniger als moeglich waere */
+ dist-=zm2l(vmax);
+ }
+ if(DEBUG&1024) printf("dist=%ld, step=%ld\n",dist,step);
+ if(step==0) ierror(0);
+ /* Die Faelle kann man noch genauer untersuchen, ob die Schleife */
+ /* evtl. nur einmal durchlaufen wird o.ae. */
+ if(step<0&&dist>=0){
+ if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+ return;
+ }
+ if(step>0&&dist<=0){
+ if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+ return;
+ }
+ if(bflag==BEQ){
+ if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+ return;
+ }
+ /* Aufpassen, ob das Schleifenende bei BNE auch getroffen wird. */
+ if(bflag==BNE){
+ if(dist%step){
+ if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+ return;
+ }
+ }
+ if(bflag==BLT||bflag==BGT||bflag==BNE){
+ if(step>0) dist--; else dist++;
+ }
+ if(dist/step<0) ierror(0);
+ if(DEBUG&1024) printf("loop is executed %ld times\n",dist/step+1);
+ if(start->start->code!=LABEL) ierror(0);
+
+ /* determine smallest type for induction variable */
+ small_type=(UNSIGNED|CHAR);
+ eval_const(&init_val,t);
+ if(!(t&UNSIGNED)&&!zmleq(Z0,vmax)){
+ small_type&=~UNSIGNED;
+ while((small_type&NQ)<(t&NQ)&&(!zmleq(t_min(small_type),vmax)||!shortcut(ADD,small_type)||!shortcut(COMPARE,small_type)))
+ small_type++;
+ }else{
+ while((small_type&NQ)<(t&NQ)&&(!zumleq(vumax,t_max(small_type))||!shortcut(ADD,small_type)||!shortcut(COMPARE,small_type)))
+ small_type++;
+ }
+ eval_const(&end_val,t);
+ if(!(t&UNSIGNED)&&!zmleq(Z0,vmax)){
+ small_type&=~UNSIGNED;
+ while((small_type&NQ)<(t&NQ)&&(!zmleq(t_min(small_type),vmax)||!shortcut(ADD,small_type)||!shortcut(COMPARE,small_type)))
+ small_type++;
+ }else{
+ while((small_type&NQ)<(t&NQ)&&(!zumleq(vumax,t_max(small_type))||!shortcut(ADD,small_type)||!shortcut(COMPARE,small_type)))
+ small_type++;
+ }
+ if(zmleq(sizetab[t&NQ],sizetab[small_type&NQ]))
+ small_type=0;
+ if(small_type&&(DEBUG&1024)) printf("induction variable can be done in %s %s\n",(small_type&UNSIGNED)?"unsigned":"signed",typname[small_type&NQ]);
+ if(range_opt&&small_type&&decide_shorten(small_type,start,p,cmp)){
+ add_ur(UNROLL_SHORTEN|ind_only_counts|multiple_exits,small_type,small_type,start,head,cmp,branch,p);
+ }else if(dist/step+1==1||ic_cnt*(dist/step+1)<=unroll_size){
+ /* Schleife komplett ausrollen. */
+ add_ur(UNROLL_COMPLETELY|ind_only_counts|multiple_exits,dist/step+1,dist/step+1,start,head,cmp,branch,p);
+ }else{
+ /* Schleife teilweise ausrollen. */
+ n=(unroll_size-ic_cnt-2)/(2*ic_cnt);
+ if(n>0)
+ add_ur(UNROLL_MODULO|ind_only_counts|multiple_exits,dist/step+1,n,start,head,cmp,branch,p);
+ }
+ return;
+ }
+ inv:
+ /* Anzahl der Schleifendurchlaeufe kann beim Eintritt in die */
+ /* Schleife zur Laufzeit berechnet werden. */
+ if(!(p->q2.flags&KONST)) return;
+ if(t&UNSIGNED){
+ eval_const(&step_val,t);
+ if(!zumleq(vumax,l2zm(2147483647))) return;
+ step=zum2ul(vumax);
+ if(flags&1) step=-step;
+ }else{
+ eval_const(&step_val,t);
+ if(!zmleq(vmax,l2zm(2147483647))) return;
+ if(zmleq(vmax,l2zm(0))) return; /* gibt Probleme */
+ step=zm2l(vmax);
+ if(flags&1) step=-step;
+ }
+ if(!compare_objs(&cmp->q1,&p->z,t)){
+ if(step>0&&(branch->code==BGT||branch->code==BGE)){
+ if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+ return;
+ }
+ if(step<0&&(branch->code==BLT||branch->code==BLE)){
+ if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+ return;
+ }
+ }else{
+ if(step<0&&(branch->code==BGT||branch->code==BGE)){
+ if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+ return;
+ }
+ if(step>0&&(branch->code==BLT||branch->code==BLE)){
+ if(report_suspicious_loops){ error(208);report_suspicious_loops=0;}
+ return;
+ }
+ }
+ if(!unroll_all) return;
+ if(bflag!=BEQ&&bflag!=BNE){
+ if(unroll_size>=8*ic_cnt+8)
+ add_ur(UNROLL_INVARIANT|ind_only_counts|multiple_exits,0,8,start,head,cmp,branch,p);
+ else if(unroll_size>=4*ic_cnt+4)
+ add_ur(UNROLL_INVARIANT|ind_only_counts|multiple_exits,0,4,start,head,cmp,branch,p);
+ else if(unroll_size>=4*ic_cnt+2)
+ add_ur(UNROLL_INVARIANT|ind_only_counts|multiple_exits,0,2,start,head,cmp,branch,p);
+ return;
+ }
+}
+
+int loop_optimizations(flowgraph *fg)
+/* steuert Optimierungen in Schleifen */
+{
+ int changed=0,i;
+ flowgraph *g,*last;
+ if(DEBUG&1024) print_flowgraph(fg);
+ if(loops(fg,0)==0) return 0;
+ if(DEBUG&1024) print_flowgraph(fg);
+ first_fg=fg=create_loop_headers(fg,0);
+ if(DEBUG&1024) print_flowgraph(fg);
+ num_defs();
+
+ /*bsize=(basic_blocks+CHAR_BIT)/CHAR_BIT;*/
+ bsize=BVSIZE(basic_blocks+1);
+ fg_tmp=mymalloc(bsize);
+ ind_vars=mymalloc(vcount*sizeof(*ind_vars));
+ invariant=mymalloc(dsize);
+ inloop=mymalloc(dsize);
+ rd_defs=mymalloc(dsize);
+ reaching_definitions(fg);
+ if(DEBUG&1024) print_flowgraph(fg);
+ moved=mymalloc(dsize);
+ memset(moved,0,dsize);
+ moved_completely=mymalloc(dsize);
+ memset(moved_completely,0,dsize);
+ not_movable=mymalloc(dsize);
+
+ first_mov=last_mov=0;
+ first_sr=last_sr=0;
+
+ for(last=0,g=fg;g;g=g->normalout){
+ if(g->loopend){
+ frequency_reduction(g,g->loopend,last);
+ strength_reduction(g,g->loopend,last);
+ if(optflags&2048) unroll(g,last);
+ }
+ last=g;
+ }
+
+ free(rd_matrix);
+ free(var_defs);
+ free(defs_kill);
+ free(defs_gen);
+ free(dlist);
+ free(rd_defs);
+ free(invariant);
+ free(inloop);
+ changed|=move_to_head();
+ if(DEBUG&1024) puts("done");
+ if(range_opt)
+ changed|=do_shorten();
+ changed|=do_sr(changed);
+ if(DEBUG&1024) puts("done");
+ changed|=do_unroll(changed);
+ if(DEBUG&1024) puts("done");
+ free(moved);
+ free(not_movable);
+ free(moved_completely);
+ if(DEBUG&1024) puts("4");
+ if(changed&2){
+ if(DEBUG&1024) printf("must repeat num_vars\n");
+ free(vilist);
+ free(av_globals);free(av_statics);
+ free(av_drefs);free(av_address);
+ num_vars();
+ }
+
+ free(ind_vars);
+ free(fg_tmp);
+
+ return changed;
+}
+
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
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..5e102f4
--- /dev/null
+++ b/main.c
@@ -0,0 +1,2010 @@
+/* $VER: vbcc (main.c) $Revision: 1.67 $ */
+#include "vbcc_cpp.h"
+#include "vbc.h"
+#include "opt.h"
+static char FILE_[]=__FILE__;
+void do_function(Var *);
+static function_info *current_fi;
+token *ctok;
+lexer_state ls;
+int endok=1;
+int line,errors;
+bvtype task_preempt_regs[RSIZE/sizeof(bvtype)];
+bvtype task_schedule_regs[RSIZE/sizeof(bvtype)];
+char *multname[]={"","s"};
+
+typedef struct deplist {char *name; struct deplist *next;} deplist;
+deplist *deps;
+FILE *depout;
+void handle_deps(char *name,int string)
+{
+ deplist *p=deps;
+ if(!depout||!name||!*name) return;
+ /* by default omit <...> includes */
+ if(!string&&!(c_flags[51]&USEDFLAG)) return;
+ while(p){
+ if(!strcmp(p->name,name)) return;
+ p=p->next;
+ }
+ p=mymalloc(sizeof(*p));
+ p->name=mymalloc(strlen(name)+1);
+ strcpy(p->name,name);
+ p->next=deps;
+ deps=p;
+ fprintf(depout," %s",name);
+}
+
+void raus(void)
+/* Beendet das Programm */
+{
+ static int inraus;
+ if(inraus) return;
+ inraus = 1;
+ if(DEBUG) printf("raus()\n");
+ if(!endok) fprintf(stderr,"unexpected end of file\n");
+ if(errors) fprintf(stderr,"%d error%s found!\n",errors,multname[errors>1]);
+ if(debug_info&&out)
+ cleanup_db(out);
+ while(nesting>=0) leave_block();
+ /*FIXME: do I have to close input-file? */
+ if(!wpo)
+ cleanup_cg(out);
+ emit_flush(out);
+ if(cmdfile) fclose(cmdfile);
+ if(out) fclose(out);
+ if(ic1) fclose(ic1);
+ if(ic2) fclose(ic2);
+ /*FIXME: need to cleanup something for ucpp?*/;
+ if(endok&&!errors) exit(EXIT_SUCCESS); else exit(EXIT_FAILURE);
+}
+int eof;
+void translation_unit(void)
+/* bearbeitet translation_unit */
+/* hier z.Z. nur provisorisch */
+{
+ Var *p;
+ if(cross_module){
+ for(p=first_ext;p;p=p->next)
+ if(!(p->flags&BUILTIN))
+ p->flags|=NOTINTU;
+ }
+ while(1){
+ killsp();
+ if(eof||ctok->type!=NAME){
+ if(!eof){
+ error(369);
+ next_token();
+ continue;
+ }else{
+ if(cross_module){
+ int n=0;
+ if(last_tunit){
+ last_tunit->next=mymalloc(sizeof(*first_tunit));
+ last_tunit=last_tunit->next;
+ }else{
+ first_tunit=last_tunit=mymalloc(sizeof(*first_tunit));
+ }
+ last_tunit->next=0;
+ for(p=first_var[0];p;p=p->next){
+ if(p->storage_class==STATIC) n++;
+ }
+ last_tunit->statics=first_var[0];
+ return;
+ }else{
+ raus();
+ }
+ }
+ }
+ endok=0;
+ var_declaration();
+ endok=1;
+ }
+}
+void reserve_reg(char *p)
+ /* reserviert ein Register */
+{
+ int i;
+ if(*p!='=') error(4,"-reserve-reg");
+ for(i=1;i<=MAXR;i++){
+ if(!strcmp(p+1,regnames[i]))
+ break;
+ }
+ if(i>MAXR){
+ error(331,p+1);
+ }else{
+ regsa[i]=1;
+ }
+}
+
+void dontwarn(char *p)
+/* schaltet flags fuer Meldung auf DONTWARN */
+{
+ if(*p!='=') error(4,"-dontwarn");
+ do{
+ int i=atoi(p+1);
+ if(i>=err_num) error(159,i);
+ if(i<0){
+ for(i=0;i<err_num;i++)
+ if(!(err_out[i].flags&(ANSIV|FATAL)))
+ err_out[i].flags|=DONTWARN;
+ return;
+ }
+ if(err_out[i].flags&(ANSIV|FATAL)) error(160,i);
+ err_out[i].flags|=DONTWARN;
+ p=strchr(p+1,',');
+ } while(p);
+}
+
+
+
+#define MISRA_98_RULE_NUMBER 127
+#define MISRA_04_CHAPTER 21
+#define MISRA_04_MAX_RULE_IN_CHAPTER 17
+
+static int misra_98_warn_flag[MISRA_98_RULE_NUMBER] = { 0 };
+static int misra_04_warn_flag[MISRA_04_CHAPTER][MISRA_04_MAX_RULE_IN_CHAPTER] = { 0 };
+
+void misrawarn(char *p) {
+ int rule,subrule,misraoldrule;
+ char* last;
+ int not_found;
+ tmisra_err_out* misr_err;
+ rule = 0;
+ subrule = 0;
+ misraoldrule = 0;
+ if(*p!='=') error(4,"-misrawarn");
+ p++;
+ if (!(strncmp("chapter",p,6))) {
+ if (sscanf((p+7),"%d",&rule) != 1) {
+ error(327,"-misrawarn");
+ }
+ } else if ( !(strncmp("misra98rule",p,11))) {
+ if (sscanf((p+12),"%d",&misraoldrule) != 1) {
+ error(327,"-misrawarn");
+ }
+ } else {
+ if (last = strchr(p,'.')) {
+ *last = 0;
+ last++;
+ if (sscanf(last,"%d",&subrule) != 1) error(327,"-misrawarn");
+ if (sscanf(p,"%d",&rule) != 1) error(327,"-misrawarn");
+ last--;
+ *last='.';
+ } else error(327,"-misrawarn");
+ }
+
+ p--;
+ if (!misracheck) misracheck = 1;
+ if (misraoldrule) {
+ if (misraversion==2004) error(328,misraversion,"-misrawarn",p);
+ if (!misraversion) misraversion=1998;
+ if ((misraoldrule < 1) || (misraoldrule>MISRA_98_RULE_NUMBER)) error(329,misraoldrule,"-misrawarn",p);
+ misra_98_warn_flag[misraoldrule-1] = 1;
+ } else {
+ if (misraversion==1998) error(328,misraversion,"-misrawarn",p);
+ if (!misraversion) misraversion=2004;
+ if (subrule) {
+ misr_err = misra_err_out;
+ not_found = 1;
+ while ( misr_err->text ) {
+ if ((misr_err->chapter == rule) && (misr_err->rule == subrule)) {
+ not_found = 0;
+ break;
+ }
+ misr_err++;
+ }
+ if (not_found) error(330,rule,subrule,"-misrawarn",p);
+ misra_04_warn_flag[rule-1][subrule-1] = 1;
+ } else {
+ misr_err = misra_err_out;
+ not_found = 1;
+ while ( misr_err->text ) {
+ if (misr_err->chapter == rule) {
+ not_found = 0;
+ misra_04_warn_flag[misr_err->chapter-1][misr_err->rule-1] = 1;
+ }
+ misr_err++;
+ }
+ if (not_found) error(330,rule,subrule,"-misrawarn",p);
+ }
+ }
+
+}
+
+
+void misradontwarn(char *p) {
+ int rule,subrule,misraoldrule;
+ char* last;
+ int not_found;
+ tmisra_err_out* misr_err;
+ rule = 0;
+ subrule = 0;
+ misraoldrule = 0;
+ if(*p!='=') error(4,"-misradontwarn");
+ p++;
+ if (!(strncmp("chapter",p,6))) {
+ if (sscanf((p+7),"%d",&rule) != 1) {
+ error(327,"-misradontwarn");
+ }
+ } else if ( !(strncmp("misra98rule",p,11))) {
+ if (sscanf((p+12),"%d",&misraoldrule) != 1) {
+ error(327,"-misradontwarn");
+ }
+ } else {
+ if (last = strchr(p,'.')) {
+ *last = 0;
+ last++;
+ if (sscanf(last,"%d",&subrule) != 1) error(327,"-misradontwarn");
+ if (sscanf(p,"%d",&rule) != 1) error(327,"-misradontwarn");
+ last--;
+ *last='.';
+ } else error(327,"-misradontwarn");
+ }
+
+ p--;
+ if (misraoldrule) {
+ if (misraversion==2004) error(328,misraversion,"-misradontwarn",p);
+ if ((misraoldrule < 1) || (misraoldrule>MISRA_98_RULE_NUMBER)) error(329,misraoldrule,"-misradontwarn",p);
+ misra_98_warn_flag[misraoldrule-1] = -1;
+ } else {
+ if (misraversion==1998) error(328,misraversion,"-misradontwarn",p);
+ if (subrule) {
+ misr_err = misra_err_out;
+ not_found = 1;
+ while ( misr_err->text ) {
+ if ((misr_err->chapter == rule) && (misr_err->rule == subrule)) {
+ not_found = 0;
+ break;
+ }
+ misr_err++;
+ }
+ if (not_found) error(330,rule,subrule,"-misradontwarn",p);
+ misra_04_warn_flag[rule-1][subrule-1] = -1;
+ } else {
+ misr_err = misra_err_out;
+ not_found = 1;
+ while ( misr_err->text ) {
+ if (misr_err->chapter == rule) {
+ not_found = 0;
+ misra_04_warn_flag[misr_err->chapter-1][misr_err->rule-1] = -1;
+ }
+ misr_err++;
+ }
+ if (not_found) error(330,rule,subrule,"-misradontwarn",p);
+ }
+ }
+
+}
+
+
+
+void warn(char *p)
+/* schaltet Warnung fuer Meldung ein */
+/* wenn Nummer<0 sind alle Warnungen ein */
+{
+ int i;
+ if(*p!='=') error(4,"-warn");
+ i=atoi(p+1);
+ if(i>=err_num) error(159,i);
+ if(i<0){
+ for(i=0;i<err_num;i++) err_out[i].flags&=~DONTWARN;
+ return;
+ }else err_out[i].flags&=~DONTWARN;
+}
+void gen_function(FILE *f,Var *v,int real_gen)
+{
+ IC *p,*new;int i,had_regs;
+ if(DEBUG&1) printf("gen_function <%s>,f=%p,real_gen=%d\n",v->identifier,(void*)f,real_gen);
+ if(!v->fi) ierror(0);
+ if(errors!=0) return;
+ first_ic=last_ic=0;
+ for(i=1;i<=MAXR;i++) {regs[i]=regused[i]=regsa[i];regsbuf[i]=0;}
+ function_calls=0;vlas=0;
+ if(!real_gen){
+ for(p=v->fi->first_ic;p;p=p->next){
+ new=new_IC();
+ *new=*p;
+ p->copy=new;
+ add_IC(new);
+ new->file=p->file;
+ new->line=p->line;
+ if(p->code==CALL){
+ int i;
+ function_calls++;
+ if((p->q1.flags&VAR)&&!strcmp(p->q1.v->identifier,"__allocvla")){
+ vlas=1;
+ v->fi->flags|=USES_VLA;
+ }
+ new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+ for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=p->arg_list[i]->copy;
+ }
+ }
+ }else{
+ for(i=1;i<=MAXR;i++) regused[i]=0;
+ for(p=v->fi->opt_ic;p;p=p->next){
+ if(p->code==ALLOCREG){
+ regused[p->q1.reg]=1;
+ if(reg_pair(p->q1.reg,&rp)){
+ regused[rp.r1]=1;
+ regused[rp.r2]=1;
+ }
+ }
+ if(p->code==CALL){
+ if((p->q1.flags&VAR)&&!strcmp(p->q1.v->identifier,"__allocvla")) vlas=1;
+ function_calls++;
+ }
+ }
+ }
+ if(vlas&&FPVLA_REG) regs[FPVLA_REG]=regused[FPVLA_REG]=regsa[FPVLA_REG]=regscratch[FPVLA_REG]=1;
+
+ if(!real_gen&&(c_flags[2]&USEDFLAG)&&ic1){
+ fprintf(ic1,"function %s\n",v->identifier);
+ pric(ic1,first_ic);
+ }
+ vl0=first_ext;
+ vl1=v->fi->statics;
+ vl2=0;
+ vl3=v->fi->vars;
+ nesting=1;
+ first_var[nesting]=last_var[nesting]=0;
+ cur_func=v->identifier;
+ if(!real_gen){
+ optimize(optflags,v);
+ if((force_statics||prefer_statics)&&first_var[nesting]){
+
+ last_var[nesting]->next=v->fi->vars;
+ v->fi->vars=first_var[nesting];
+ }
+ memset(regs_modified,0,RSIZE);
+ /* pseudeo generator pass to get regs_modified */
+ v->fi->opt_ic=clone_ic(first_ic);
+ v->fi->max_offset=max_offset;
+ if(v->fi&&(v->fi->flags&ALL_REGS))
+ had_regs=1;
+ else
+ had_regs=0;
+ gen_code(0,first_ic,v,max_offset);
+#ifdef HAVE_REGS_MODIFIED
+ if(!v->fi) v->fi=new_fi();
+ {
+ int i;IC *p;
+ for(i=1;i<=MAXR;i++){
+ if(BTST(regs_modified,i)&®_pair(i,&rp)){
+ BSET(regs_modified,rp.r1);
+ BSET(regs_modified,rp.r2);
+ }
+ }
+#if 1
+ for(i=1;i<=MAXR;i++){
+ if(reg_pair(i,&rp)){
+ if(BTST(regs_modified,rp.r1)||BTST(regs_modified,rp.r2))
+ BSET(regs_modified,i);
+ }
+ }
+#endif
+ if(had_regs){
+ if(memcmp(regs_modified,v->fi->regs_modified,RSIZE))
+ error(321,v->identifier);
+ }else
+ memcpy(v->fi->regs_modified,regs_modified,RSIZE);
+#if 0
+ printf("regs for %s (ALL_REGS=%d):\n",v->identifier,v->fi->flags&ALL_REGS);
+ for(i=1;i<MAXR;i++) if(BTST(regs_modified,i)) printf("%s ",regnames[i]);
+ printf("\n");
+#endif
+ }
+#endif
+ v->flags|=GENERATED;
+ free_IC(first_ic);
+ first_ic=last_ic=0;
+ /*free_var(first_var[nesting]);*/
+ nesting=0;
+ }else{
+ if((c_flags[3]&USEDFLAG)&&ic2){
+ fprintf(ic2,"function %s\n",v->identifier);
+ pric(ic2,v->fi->opt_ic);
+ }
+ gen_code(f,v->fi->opt_ic,v,v->fi->max_offset);
+ static_stack_check(v);
+ }
+}
+/* handle functions in a const list before caller */
+static void do_clist_calls(const_list *cl)
+{
+ while(cl){
+ if(cl->tree&&(cl->tree->o.flags&VARADR)){
+ Var *v=cl->tree->o.v;
+ if(ISFUNC(v->vtyp->flags)){
+ if(DEBUG&1)
+ printf(":: %s\n",v->identifier);
+ do_function(v);
+ }
+ }
+ if(cl->other)
+ do_clist_calls(cl->other);
+ cl=cl->next;
+ }
+}
+void do_function(Var *v)
+{
+ int i;IC *p;
+ if((v->flags&(GENERATED|DEFINED))!=DEFINED) return;
+ v->flags|=GENERATED;
+ if(!v->fi) v->fi=new_fi();
+#if 0
+ for(i=0;i<v->fi->call_cnt;i++){
+ if(v->fi->call_list[i].v->flags&DEFINED)
+ do_function(v->fi->call_list[i].v);
+ }
+#endif
+ /* handle callees before caller */
+ for(p=v->fi->first_ic;p;p=p->next){
+ /* direct call */
+ if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR)
+ do_function(p->q1.v);
+ /* function address is also a candidate */
+ if((p->q1.flags&(VAR|VARADR))&&ISFUNC(p->q1.v->vtyp->flags))
+ do_function(p->q1.v);
+ if((p->q2.flags&(VAR|VARADR))&&ISFUNC(p->q2.v->vtyp->flags))
+ do_function(p->q2.v);
+ if((p->z.flags&(VAR|VARADR))&&ISFUNC(p->z.v->vtyp->flags))
+ do_function(p->z.v);
+ /* indirect call, handle special case */
+ if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+ Var *v=p->q1.v;
+ if(v->storage_class==AUTO||v->storage_class==REGISTER){
+ IC *m=p->prev;Var *tmp=0;
+ while(m&&(m->code<LABEL||m->code>=BRA)){
+ if(!tmp&&(m->z.flags&(VAR|DREFOBJ))==VAR&&m->z.v==v&&
+ (m->q1.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ))
+ tmp=m->q1.v;
+ if(tmp&&(m->z.flags&(VAR|DREFOBJ))==VAR&&m->z.v==tmp&&
+ (m->q1.flags&(VAR|VARADR))==(VAR|VARADR)&&
+ m->q1.v->clist&&is_const(m->q1.v->vtyp)){
+ do_clist_calls(m->q1.v->clist);
+ }
+ m=m->prev;
+ }
+ }
+ }
+ }
+ gen_function(0,v,0);
+}
+
+
+
+extern char *copyright;
+int main(int argc,char *argv[])
+{
+ int i,j,*fname=malloc(argc*sizeof(int)),files=0;
+ unsigned long ucpp_flags=LEXER|WARN_TRIGRAPHS|WARN_STANDARD|WARN_ANNOYING/*|CCHARSET*/|HANDLE_PRAGMA|COPY_LINE|WARN_TRIGRAPHS_MORE|HANDLE_TRIGRAPHS;
+ if(!fname) ierror(0);
+ memset(fname,0,argc*sizeof(int));
+ c_flags_val[9].f=dontwarn;
+ c_flags_val[10].f=warn;
+ c_flags_val[42].f=misrawarn;
+ c_flags_val[43].f=misradontwarn;
+ c_flags_val[44].f=reserve_reg;
+ for(i=1;i<argc;i++){
+ if(*argv[i]!='-'){ /* kein Flag */
+ fname[i]=1;
+ files++;
+ if(!inname) inname=argv[i];
+ }else{
+ int flag=0;
+ if(argv[i][1]=='D'||argv[i][1]=='I') flag=1;
+ for(j=0;j<MAXCF&&flag==0;j++){
+ size_t l;
+ if(!c_flags_name[j]) continue;
+ l=strlen(c_flags_name[j]);
+ if(l>0&&!strncmp(argv[i]+1,c_flags_name[j],l)&&(argv[i][1+l]==0||argv[i][1+l]=='=')){
+ flag=1;
+ if((c_flags[j]&(USEDFLAG|FUNCFLAG))==USEDFLAG){error(2,argv[i]);break;}
+ c_flags[j]|=USEDFLAG;
+ if(c_flags[j]&STRINGFLAG){
+ if(argv[i][l+1]!='='){error(3,argv[i]);}
+ if(argv[i][l+2]||i>=argc-1)
+ c_flags_val[j].p=&argv[i][l+2];
+ else
+ c_flags_val[j].p=&argv[++i][0];
+ }
+ if(c_flags[j]&VALFLAG){
+ if(argv[i][l+1]!='='){error(4,argv[i]);}
+ if(argv[i][l+2]||i>=argc-1)
+ c_flags_val[j].l=atol(&argv[i][l+2]);
+ else
+ c_flags_val[j].l=atol(&argv[++i][0]);
+ }
+ if(c_flags[j]&FUNCFLAG) c_flags_val[j].f(&argv[i][l+1]);
+ }
+ }
+ for(j=0;j<MAXGF&&flag==0;j++){
+ size_t l;
+ if(!g_flags_name[j]) continue;
+ l=strlen(g_flags_name[j]);
+ if(l>0&&!strncmp(argv[i]+1,g_flags_name[j],l)){
+ flag=1;
+ if((g_flags[j]&(USEDFLAG|FUNCFLAG))==USEDFLAG){error(2,argv[i]);break;}
+ g_flags[j]|=USEDFLAG;
+ if(g_flags[j]&STRINGFLAG){
+ if(argv[i][l+1]!='='){error(3,argv[i]);}
+ if(argv[i][l+2]||i>=argc-1)
+ g_flags_val[j].p=&argv[i][l+2];
+ else
+ g_flags_val[j].p=&argv[++i][0];
+ }
+ if(g_flags[j]&VALFLAG){
+ if(argv[i][l+1]!='='){error(4,argv[i]);}
+ if(argv[i][l+2]||i>=argc-1)
+ g_flags_val[j].l=atol(&argv[i][l+2]);
+ else
+ g_flags_val[j].l=atol(&argv[++i][0]);
+ }
+ if(g_flags[j]&FUNCFLAG) g_flags_val[j].f(&argv[i][l+1]);
+ }
+ }
+ if(!flag){error(5,argv[i]);}
+ }
+ }
+ if(!(c_flags[6]&USEDFLAG)){
+#ifdef SPECIAL_COPYRIGHT
+ printf("%s\n",SPECIAL_COPYRIGHT);
+#else
+ printf("%s\n",copyright);
+ printf("%s\n",cg_copyright);
+#endif
+ }
+ if(c_flags[4]&USEDFLAG) DEBUG=c_flags_val[4].l; else DEBUG=0;
+ if(c_flags[13]&USEDFLAG) ucpp_flags|=CPLUSPLUS_COMMENTS;
+ if(c_flags[14]&USEDFLAG) ucpp_flags|=CPLUSPLUS_COMMENTS;
+ if(c_flags[15]&USEDFLAG) ucpp_flags&=~HANDLE_TRIGRAPHS;
+ if(c_flags[52]&USEDFLAG) ucpp_flags&=~(WARN_STANDARD|WARN_ANNOYING);
+ if(c_flags[16]&USEDFLAG) no_inline_peephole=1;
+ if(c_flags[17]&USEDFLAG) final=1;
+ if(!(c_flags[8]&USEDFLAG)) c_flags_val[8].l=10; /* max. Fehlerzahl */
+ if(c_flags[22]&USEDFLAG) c_flags[7]|=USEDFLAG; /* iso=ansi */
+ if(c_flags[7]&USEDFLAG) error(209);
+ if(c_flags[0]&USEDFLAG) optflags=c_flags_val[0].l;
+ if(optflags&16384) cross_module=1;
+ if(c_flags[11]&USEDFLAG) maxoptpasses=c_flags_val[11].l;
+ if(c_flags[12]&USEDFLAG) inline_size=c_flags_val[12].l;
+ if(c_flags[21]&USEDFLAG) fp_assoc=1;
+ if(c_flags[25]&USEDFLAG) unroll_size=c_flags_val[25].l;
+ if(c_flags[23]&USEDFLAG) noaliasopt=1;
+ if(c_flags[27]&USEDFLAG) optspeed=1;
+ if(c_flags[28]&USEDFLAG) optsize=1;
+ if(c_flags[29]&USEDFLAG) unroll_all=1;
+ if(c_flags[30]&USEDFLAG) stack_check=1;
+ if(c_flags[31]&USEDFLAG) inline_depth=c_flags_val[31].l;
+ if(c_flags[32]&USEDFLAG) debug_info=1;
+ if(c_flags[33]&USEDFLAG) c99=1;
+ if(c_flags[60]&USEDFLAG) c99=0;
+ if(c_flags[34]&USEDFLAG) {wpo=1;no_emit=1;}
+ if(c_flags[36]&USEDFLAG) {noitra=1;}
+ if(c_flags[37]&USEDFLAG) {
+ misracheck=1;
+ if ((misraversion==1998) && (c_flags_val[37].l == 2004)) error(328,c_flags_val[37].l,"-misra","");
+ if ((misraversion==2004) && (c_flags_val[37].l == 1998)) error(328,c_flags_val[37].l,"-misra","");
+ misraversion=c_flags_val[37].l;
+
+ if (!((misraversion==2004) || (misraversion==1998))) error(328,misraversion,"-misra","");
+ if (misraversion==1998) {
+ int misra_set_iterator;
+ for (misra_set_iterator = 0; misra_set_iterator < MISRA_98_RULE_NUMBER; misra_set_iterator++ ) {
+ if (misra_98_warn_flag[misra_set_iterator] != -1) misra_98_warn_flag[misra_set_iterator] = 1;
+ }
+ } else {
+ int m1, m2;
+ for (m1 = 0; m1 < MISRA_04_CHAPTER; m1++) {
+ for (m2 = 0; m2 < MISRA_04_MAX_RULE_IN_CHAPTER; m2++) {
+ if (misra_04_warn_flag[m1][m2] != -1) misra_04_warn_flag[m1][m2] = 1;
+ }
+ }
+ }
+ }
+ if(c_flags[38]&USEDFLAG) {coloring=c_flags_val[38].l;}
+ if(c_flags[39]&USEDFLAG) {dmalloc=1;}
+ if(c_flags[40]&USEDFLAG) {disable=c_flags_val[40].l;}
+ if(c_flags[41]&USEDFLAG) {softfloat=1;}
+ if(c_flags[45]&USEDFLAG) {ecpp=1;}
+ if(c_flags[46]&USEDFLAG) {short_push=1;}
+ if(c_flags[47]&USEDFLAG) {default_unsigned=1;}
+ if(c_flags[48]&USEDFLAG) {opencl=1;}
+ {
+ size_t hs=1000;
+ if(c_flags[53]&USEDFLAG) hs=c_flags_val[53].l;
+ if(hs!=0) hash_ext=new_hashtable(hs);
+ }
+
+
+ if(wpo){
+ cross_module=1;
+ optflags=-1;
+ }
+ if(optsize){
+ if(!(c_flags[25]&USEDFLAG)) unroll_size=0;
+ clist_copy_pointer=clist_copy_stack;
+ }
+
+ if(optspeed){
+ clist_copy_pointer=256;
+ }
+
+ if(ecpp&&c99){
+ error(333, "c99", "ecpp");
+ }
+ if(c99){
+ ucpp_flags|=CPLUSPLUS_COMMENTS|MACRO_VAARG;
+ err_out[67].flags|=ANSIV;
+ err_out[67].flags&=~DONTWARN;
+ err_out[161].flags|=ANSIV;
+ err_out[161].flags&=~DONTWARN;
+ err_out[155].flags|=ANSIV;
+ err_out[155].flags&=~DONTWARN;
+ err_out[156].flags|=ANSIV;
+ err_out[156].flags&=~DONTWARN;
+ }
+ if(ecpp){
+#ifndef HAVE_ECPP
+ error(334, "EC++");
+#endif
+ ucpp_flags|=CPLUSPLUS_COMMENTS|MACRO_VAARG;
+ }
+ if(!cross_module&&files>1) error(1);
+ if(files<=0&&!(c_flags[35]&USEDFLAG)) error(6);
+ stackalign=l2zm(0L);
+ if(!init_cg()) exit(EXIT_FAILURE);
+
+ if(c_flags[55]&USEDFLAG) {clist_copy_stack=c_flags_val[55].l;}
+ if(c_flags[56]&USEDFLAG) {clist_copy_static=c_flags_val[56].l;}
+ if(c_flags[57]&USEDFLAG) {clist_copy_pointer=c_flags_val[57].l;}
+ if(c_flags[58]&USEDFLAG) {inline_memcpy_sz=c_flags_val[58].l;}
+ if(c_flags[61]&USEDFLAG) {force_statics=1;}
+ if(c_flags[62]&USEDFLAG) {prefer_statics=1;}
+ if(c_flags[63]&USEDFLAG) {range_opt=1;}
+ if(c_flags[64]&USEDFLAG) {merge_strings=1;}
+ if(c_flags[65]&USEDFLAG) {sec_per_obj=1;}
+ if(c_flags[66]&USEDFLAG) {no_eff_ics=1;}
+ if(c_flags[67]&USEDFLAG) {early_eff_ics=1;}
+ if(c_flags[68]&USEDFLAG) {mask_opt=1;}
+
+
+ if(!(optflags&2)){
+ for(i=1;i<=MAXR;i++){
+ sregsa[i]=regsa[i];
+ if(regsa[i]==REGSA_TEMPS) regsa[i]=0;
+ }
+ }
+ if(zmeqto(stackalign,l2zm(0L)))
+ stackalign=maxalign;
+ for(i=0;i<=MAX_TYPE;i++)
+ if(zmeqto(align[i],l2zm(0L)))
+ align[i]=l2zm(1L);
+ for(i=0;i<EMIT_BUF_DEPTH;i++)
+ emit_buffer[i]=mymalloc(EMIT_BUF_LEN);
+ emit_p=emit_buffer[0];
+ /*FIXME: multiple-ccs don't work */
+ if(c_flags[24]&USEDFLAG) multiple_ccs=0;
+ if(!(c_flags[5]&USEDFLAG)){
+ if(c_flags[1]&USEDFLAG){
+ out=open_out(c_flags_val[1].p,0);
+ }else{
+ if(wpo)
+ out=open_out(inname,"o");
+ else
+ out=open_out(inname,"asm");
+ }
+ if(!out){
+ exit(EXIT_FAILURE);
+ }
+ }
+ if(wpo){
+ wpo_key=MAGIC_WPO;
+ fprintf(out,"%cVBCC",0);
+ }
+ if(debug_info) init_db(out);
+ if(c_flags[2]&USEDFLAG) ic1=open_out(inname,"ic1");
+ if(c_flags[3]&USEDFLAG) ic2=open_out(inname,"ic2");
+ c99_compliant=0;
+ init_cpp();
+ if(c_flags[35]&USEDFLAG){
+ /* we have a command file */
+ cmdfile=fopen(c_flags_val[35].p,"r");
+ if(!cmdfile) error(7,c_flags_val[35].p);
+ }
+ for(i=1;cmdfile||i<argc;i++){
+ FILE *in;
+ int first_byte;
+ if(i<argc){
+ if(!fname[i]) continue;
+ inname=argv[i];
+ }else{
+ static char nbuf[1024];
+ if(!fgets(nbuf,1023,cmdfile)) break;
+ inname=nbuf;
+ while(isspace((unsigned char)*inname)) inname++;
+ if(*inname=='\"') inname++;
+ if(inname[strlen(inname)-1]=='\n') inname[strlen(inname)-1]=0;
+ if(inname[strlen(inname)-1]=='\"') inname[strlen(inname)-1]=0;
+ if(!*inname) break;
+ }
+ if(DEBUG&1) printf("starting translation-unit <%s>\n",inname);
+ in=fopen(inname,"r");
+ if(!in) {error(7,inname);}
+ misratok=0;
+ first_byte=fgetc(in);
+ if(first_byte==0){
+ input_wpo=in;
+ if(fgetc(in)!='V') error(300);
+ if(fgetc(in)!='B') error(300);
+ if(fgetc(in)!='C') error(300);
+ if(fgetc(in)!='C') error(300);
+ wpo_key=MAGIC_WPO;
+ }else{
+ ungetc(first_byte,in);
+ input_wpo=0;
+ }
+ if(c_flags[50]&USEDFLAG){
+ char *p;
+ depout=open_out(inname,"dep");
+ /* nicht super schoen (besser letzten Punkt statt ersten), aber kurz.. */
+ if(c_flags[59]&USEDFLAG){
+ fprintf(depout,"%s: %s",c_flags_val[59].p,inname);
+ }else{
+ for(p=inname;*p&&*p!='.';p++) fprintf(depout,"%c",*p);
+ fprintf(depout,".o: %s",inname);
+ }
+ }
+ if(c_flags[18]&USEDFLAG) ppout=open_out(inname,"i");
+ if(!input_wpo){
+ int mcmerk=misracheck;
+ misracheck=0;
+ init_tables(0);
+ init_include_path(0);
+ set_init_filename(inname,1);
+ init_lexer_state(&ls);
+ init_lexer_mode(&ls);
+ ls.flags=ucpp_flags;
+ ls.input=in;
+ for(j=1;j<argc;j++){
+ if(argv[j][0]=='-'&&argv[j][1]=='I')
+ add_incpath(&argv[j][2]);
+ if(argv[j][0]=='-'&&argv[j][1]=='D')
+ define_macro(&ls,&argv[j][2]);
+ }
+ if(target_macros){
+ char **m=target_macros;
+ while(*m)
+ define_macro(&ls,*m++);
+ }
+ define_macro(&ls,"__VBCC__");
+ define_macro(&ls,"__entry=__vattr(\"entry\")");
+ define_macro(&ls,"__str(x)=#x");
+ define_macro(&ls,"__asm(x)=do{static void inline_assembly()=x;inline_assembly();}while(0)");
+ define_macro(&ls,"__regsused(x)=__vattr(\"regused(\"x\")\")");
+ define_macro(&ls,"__varsused(x)=__vattr(\"varused(\"x\")\")");
+ define_macro(&ls,"__varsmodified(x)=__vattr(\"varchanged(\"x\")\")");
+ define_macro(&ls,"__noreturn=__vattr(\"noreturn()\")");
+ define_macro(&ls,"__alwaysreturn=__vattr(\"alwaysreturn()\")");
+ define_macro(&ls,"__nosidefx=__vattr(\"nosidefx()\")");
+ define_macro(&ls,"__stack(x)=__vattr(__str(stack1(x)))");
+ define_macro(&ls,"__stack2(x)=__vattr(__str(stack2(x)))");
+ define_macro(&ls,"__noinline=__vattr(\"noinline()\")");
+ if(c99)
+ define_macro(&ls,"__STDC_VERSION__=199901L");
+ if(optspeed)
+ define_macro(&ls,"__OPTSPEED__");
+ if(optsize)
+ define_macro(&ls,"__OPTSIZE__");
+ misracheck=mcmerk;
+ enter_file(&ls,ls.flags);
+ }
+ filename=current_filename;
+ switch_count=0;break_label=0;
+ line=0;eof=0;
+ next_token();
+ killsp();
+ nesting=-1;enter_block();
+ translation_unit();
+ fclose(in); /*FIXME: do I have to close??*/
+ if((c_flags[18]&USEDFLAG)&&ppout) fclose(ppout);
+ if((c_flags[50]&USEDFLAG)&&depout){fprintf(depout,"\n");fclose(depout);}
+ if(!input_wpo)
+ free_lexer_state(&ls);
+ }
+ if(wpo)
+ raus();
+ if(!cross_module){
+ ierror(0);
+ }else{
+ tunit *t;
+ Var *v,*sf;
+#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 */
+#endif
+ if(DEBUG&1) printf("first optimizing\n");
+ for(v=first_ext;v;v=v->next){
+ if(ISFUNC(v->vtyp->flags)&&(v->flags&DEFINED)&&(!v->vattr||!strstr(v->vattr,"taskprio("))){
+ do_function(v);
+ }
+ }
+ for(t=first_tunit;t;t=t->next){
+ for(v=t->statics;v;v=v->next){
+ if(ISFUNC(v->vtyp->flags)&&(v->flags&DEFINED)){
+ do_function(v);
+ }
+ }
+ }
+ if(DEBUG&1) printf("determining used objects\n");
+ for(v=first_ext;v;v=v->next){
+ if((v->flags&(DEFINED|TENTATIVE))&&(v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC){
+ if(!final||!strcmp(v->identifier,"main")||(v->vattr&&strstr(v->vattr,"entry"))){
+#ifndef NO_OPTIMIZER
+ used_objects(v);
+#endif
+ if(ISFUNC(v->vtyp->flags)) do_function(v);
+ }
+ }
+ }
+ if(!(c_flags[5]&USEDFLAG)){
+ if(DEBUG&1) printf("generating external functions:\n");
+ for(v=first_ext;v;v=v->next){
+ if(ISFUNC(v->vtyp->flags)&&(v->flags&(REFERENCED|DEFINED))==(REFERENCED|DEFINED)){
+ gen_function(out,v,1);
+ }
+ }
+ if(DEBUG&1024) printf("generating static functions\n");
+ i=0;
+ for(t=first_tunit;t;t=t->next){
+ if(DEBUG&1) printf("translation-unit %d:\n",++i);
+ if(DEBUG&1) printf("generating statics:\n");
+ for(v=t->statics;v;v=v->next){
+ if(DEBUG&1) printf(" %s\n",v->identifier);
+ if(ISFUNC(v->vtyp->flags)&&(v->flags&(REFERENCED|DEFINED))==(REFERENCED|DEFINED)){
+ gen_function(out,v,1);
+ }
+ }
+ }
+
+ if(DEBUG&1) printf("generating vars:\n");
+ gen_vars(first_ext);
+ for(t=first_tunit;t;t=t->next)
+ gen_vars(t->statics);
+ for(v=first_ext;v;v=v->next){
+ if(ISFUNC(v->vtyp->flags)&&(v->flags&DEFINED))
+ gen_vars(v->fi->vars);
+ }
+ for(t=first_tunit;t;t=t->next){
+ for(v=t->statics;v;v=v->next){
+ if(ISFUNC(v->vtyp->flags)&&(v->flags&DEFINED))
+ gen_vars(v->fi->vars);
+ }
+ }
+ }
+ }
+ raus();
+}
+int mcmp(const char *s1,const char *s2)
+/* Einfachere strcmp-Variante. */
+{
+ char c;
+ do{
+ c=*s1++;
+ if(c!=*s2++) return(1);
+ }while(c);
+ return 0;
+}
+int is_keyword(char *p)
+{
+ char *n=p+1;
+ switch(*p){
+ case 'a':
+ if(!mcmp(n,"uto")) return 1;
+ return 0;
+ case 'b':
+ if(ecpp&&!mcmp(n,"ool")) return 1;
+ if(!mcmp(n,"reak")) return 1;
+ return 0;
+ case 'c':
+ if(!mcmp(n,"ase")) return 1;
+ if(ecpp&&!mcmp(n,"atch")) return 1;
+ if(!mcmp(n,"har")) return 1;
+ if(ecpp&&!mcmp(n,"lass")) return 1;
+ if(!mcmp(n,"onst")) return 1;
+ if(ecpp&&!mcmp(n,"ons_cast")) return 1;
+ if(!mcmp(n,"ontinue")) return 1;
+ return 0;
+ case 'd':
+ if(!mcmp(n,"efault")) return 1;
+ if(ecpp&&!mcmp(n,"elete")) return 1;
+ if(!mcmp(n,"o")) return 1;
+ if(!mcmp(n,"ouble")) return 1;
+ if(ecpp&&!mcmp(n,"ynamic_cast")) return 1;
+ return 0;
+ case 'e':
+ if(!mcmp(n,"lse")) return 1;
+ if(!mcmp(n,"num")) return 1;
+ if(ecpp&&!mcmp(n,"xplicit")) return 1;
+ if(ecpp&&!mcmp(n,"xport")) return 1;
+ if(!mcmp(n,"xtern")) return 1;
+ return 0;
+ case 'f':
+ if(ecpp&&!mcmp(n,"alse")) return 1;
+ if(!mcmp(n,"loat")) return 1;
+ if(!mcmp(n,"or")) return 1;
+ if(ecpp&&!mcmp(n,"riend")) return 1;
+ return 0;
+ case 'g':
+ if(!mcmp(n,"oto")) return 1;
+ return 0;
+ case 'i':
+ if(!mcmp(n,"f")) return 1;
+ if(c99&&!mcmp(n,"nline")) return 1;
+ if(!mcmp(n,"nt")) return 1;
+ return 0;
+ case 'l':
+ if(!mcmp(n,"ong")) return 1;
+ return 0;
+ case 'm':
+ if(ecpp&&!mcmp(n,"utable")) return 1;
+ return 0;
+ case 'n':
+ if(ecpp&&!mcmp(n,"amespace")) return 1;
+ if(ecpp&&!mcmp(n,"ew")) return 1;
+ return 0;
+ case 'o':
+ if(ecpp&&!mcmp(n,"perator")) return 1;
+ return 0;
+ case 'p':
+ if(ecpp&&!mcmp(n,"rivate")) return 1;
+ if(ecpp&&!mcmp(n,"rotected")) return 1;
+ if(ecpp&&!mcmp(n,"ublic")) return 1;
+ return 0;
+ case 'r':
+ if(!mcmp(n,"egister")) return 1;
+ if(ecpp&&!mcmp(n,"einterpret_cast")) return 1;
+ if(c99&&!mcmp(n,"estrict")) return 1;
+ if(!mcmp(n,"eturn")) return 1;
+ return 0;
+ case 's':
+ if(!mcmp(n,"hort")) return 1;
+ if(!mcmp(n,"igned")) return 1;
+ if(!mcmp(n,"izeof")) return 1;
+ if(!mcmp(n,"tatic")) return 1;
+ if(ecpp&&!mcmp(n,"tatic_cast")) return 1;
+ if(!mcmp(n,"truct")) return 1;
+ if(!mcmp(n,"witch")) return 1;
+ return 0;
+ case 't':
+ if(ecpp&&!mcmp(n,"emplate")) return 1;
+ /* if(ecpp&&!mcmp(n,"his")) return 1;*/
+ if(ecpp&&!mcmp(n,"hrow")) return 1;
+ if(ecpp&&!mcmp(n,"rue")) return 1;
+ if(ecpp&&!mcmp(n,"ry")) return 1;
+ if(!mcmp(n,"ypedef")) return 1;
+ if(ecpp&&!mcmp(n,"ypeid")) return 1;
+ if(ecpp&&!mcmp(n,"ypename")) return 1;
+ return 0;
+ case 'u':
+ if(!mcmp(n,"nion")) return 1;
+ if(!mcmp(n,"nsigned")) return 1;
+ if(ecpp&&!mcmp(n,"sing")) return 1;
+ return 0;
+ case 'v':
+ if(ecpp&&!mcmp(n,"irtual")) return 1;
+ if(!mcmp(n,"oid")) return 1;
+ if(!mcmp(n,"olatile")) return 1;
+ return 0;
+ case 'w':
+ if(ecpp&&!mcmp(n,"char_t")) return 1;
+ if(!mcmp(n,"hile")) return 1;
+ return 0;
+ case '_':
+ if(c99&&!mcmp(n,"Bool")) return 1;
+ if(c99&&!mcmp(n,"Complex")) return 1;
+ if(c99&&!mcmp(n,"Imaginary")) return 1;
+ default:
+ return 0;
+ }
+}
+void cpbez(char *m,int check_keyword)
+/* Kopiert den naechsten Bezeichner von s nach m. Wenn check_keyord!=0 */
+/* wird eine Fehlermeldung ausgegeben, falls das Ergebnis ein */
+/* reserviertes Keyword von C ist. */
+{
+ if(ctok->type!=NAME){
+ *m=0;
+ return;
+ }
+ if(strlen(ctok->name)>=MAXI){
+ error(206,MAXI-1);
+ strncpy(m,ctok->name,MAXI-1);
+ m[MAXI-1]=0;
+ }else{
+ strcpy(m,ctok->name);
+ }
+ if(check_keyword&&is_keyword(m))
+ error(216,m);
+}
+void cpnum(char *m)
+/* kopiert die naechste int-Zahl von s nach m */
+/* muss noch erheblich erweiter werden */
+{
+ if(ctok->type!=NUMBER){
+ *m=0;
+ return;
+ }
+ strcpy(m,ctok->name);
+}
+void copy_token(token *d,token *s)
+{
+ size_t l;
+ *d=*s;
+ if(S_TOKEN(s->type)){
+ l=strlen(s->name)+1;
+ d->name=mymalloc(l);
+ memcpy(d->name,s->name,l);
+ }else
+ d->name=0;
+}
+static token back_token;
+static int have_back_token;
+void push_token(token *t)
+{
+ static char back_name[MAXI+1];
+ if(have_back_token) ierror(0);
+ back_token=*t;
+ if(S_TOKEN(t->type)){
+ strcpy(back_name,t->name);
+ back_token.name=back_name;
+ }else
+ back_token.name=0;
+ have_back_token=1;
+ ctok=&back_token;
+}
+void next_token(void)
+{
+ if(eof){
+ if(!endok)
+ raus();
+ else
+ return;
+ }
+ if(input_wpo){
+ int c;
+ static token wpo_tok;
+ static size_t sz;
+ char *p;size_t cs;
+
+ if(have_back_token){
+ have_back_token=0;
+ ctok=&wpo_tok;
+ return;
+ }
+ ctok=&wpo_tok;
+ c=fgetc(input_wpo);
+ if(c==EOF){
+ eof=1;
+ return;
+ }else
+ c^=wpo_key++;
+ wpo_tok.type=(unsigned char)c;
+ /*printf("wpoget: %d (%s)\n",ctok->type,operators_name[ctok->type]);*/
+ if(S_TOKEN(wpo_tok.type)){
+ p=wpo_tok.name;
+ cs=0;
+ do{
+ if(cs>=sz){
+ sz+=1000;
+ wpo_tok.name=myrealloc(wpo_tok.name,sz);
+ p=wpo_tok.name+cs;
+ }
+ c=fgetc(input_wpo);
+ if(c!=EOF){
+ c^=wpo_key++;
+ *p++=c;
+ cs++;
+ }else
+ eof=1;
+ }while(((unsigned char)c)!=0&&c!=EOF);
+ *p=0;
+ /*printf("name=%s\n",ctok->name);*/
+ }
+ return;
+ }
+ if(have_back_token){
+ have_back_token=0;
+ if(S_TOKEN(ctok->type)&&!ctok->name)
+ ierror(0);
+ }else{
+ static int last_line=1,last_token=NONE;
+ static char *last_fname;static size_t last_size;
+ eof=lex(&ls);
+ if(ctok&&S_TOKEN(ls.ctok->type)&&!ls.ctok->name)
+ ierror(0);
+ if(wpo){
+ fprintf(out,"%c",ls.ctok->type^wpo_key++);
+ if(S_TOKEN(ls.ctok->type)){
+ char *p=ls.ctok->name;
+ while(*p){
+ fprintf(out,"%c",*p^wpo_key++);
+ p++;
+ }
+ fprintf(out,"%c",0^wpo_key++);
+ }
+ }
+ if((c_flags[18]&USEDFLAG)&&ppout&&!input_wpo){
+ if(!last_fname){
+ last_fname=mymalloc(1);
+ *last_fname=0;
+ }
+ if(strcmp(last_fname,current_filename)){
+ fprintf(ppout,"\n#line %d \"%s\"\n",(int)ls.ctok->line,current_filename);
+ last_line=ls.ctok->line;
+ if(strlen(current_filename)>=last_size)
+ last_fname=myrealloc(last_fname,strlen(current_filename)+1);
+ strcpy(last_fname,current_filename);
+ }else{
+ for(;last_line<ls.ctok->line;last_line++)
+ fprintf(ppout,"\n");
+ }
+ if(S_TOKEN(ls.ctok->type)){
+ if(ls.ctok->type==PRAGMA)
+ fprintf(ppout,"#pragma");
+ fprintf(ppout," %s",ls.ctok->name);
+ }else
+ fprintf(ppout," %s",operators_name[ls.ctok->type]);
+ last_token=ls.ctok->type;
+ }
+ }
+ ctok=ls.ctok;
+ line=ctok->line;
+ if(misracheck&&ctok->type!=PRAGMA&&ctok->type!=NONE&&ctok->type!=NEWLINE&&ctok->type!=COMMENT)
+ misratok=1;
+ /*FIXME: do not store multiple */
+ if(filename!=current_filename&&strcmp(filename,current_filename)){
+ filename=mymalloc(strlen(current_filename)+1);
+ strcpy(filename,current_filename);
+ }
+ /*filename=current_filename;*/
+ if(DEBUG&2) printf("current token (type %d): %s\n",(int)ctok->type,ucpp_token_name(ctok));
+}
+char *pragma_cpbez(char *buff,char *s);
+/* calculate fi entries (regs_modifed,uses,changes,flags etc.) from
+ attributes */
+void fi_from_attr(Var *v)
+{
+ char *attr;
+ attr=v->vattr;
+ if(!attr) return;
+ while(attr=strstr(attr,"readmem(")){
+ int f;
+ attr+=8;
+ if(sscanf(attr,"%d",&f)!=1) ierror(0);
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_USES;
+ v->fi->use_cnt++;
+ v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(varlist));
+ v->fi->use_list[v->fi->use_cnt-1].v=0;
+ v->fi->use_list[v->fi->use_cnt-1].flags=f;
+ }
+ attr=v->vattr;
+ while(attr=strstr(attr,"writemem(")){
+ int f;
+ attr+=9;
+ if(sscanf(attr,"%d",&f)!=1) ierror(0);
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_MODS;
+ v->fi->change_cnt++;
+ v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(varlist));
+ v->fi->change_list[v->fi->change_cnt-1].v=0;
+ v->fi->change_list[v->fi->change_cnt-1].flags=f;
+ }
+ attr=v->vattr;
+ while(attr=strstr(attr,"varused(")){
+ Var *n;
+ attr+=8;
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_USES;
+ while(1){
+ while(isspace((unsigned char)*attr)) attr++;
+ if(*attr==')') break;
+ attr=pragma_cpbez(buff,attr);
+ if(buff[0]==0){
+ error(76);
+ break;
+ }
+ n=find_ext_var(buff);
+ if(!n){
+ error(82,buff);
+ break;
+ }
+ v->fi->use_cnt++;
+ v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(varlist));
+ v->fi->use_list[v->fi->use_cnt-1].v=n;
+ v->fi->use_list[v->fi->use_cnt-1].flags=n->vtyp->flags;
+ while(isspace((unsigned char)*attr)) attr++;
+ if(*attr==','||*attr=='/') attr++;
+ }
+ }
+ attr=v->vattr;
+ while(attr=strstr(attr,"varchanged(")){
+ Var *n;
+ attr+=11;
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_MODS;
+ while(1){
+ while(isspace((unsigned char)*attr)) attr++;
+ if(*attr==')') break;
+ attr=pragma_cpbez(buff,attr);
+ if(buff[0]==0){
+ error(76);
+ break;
+ }
+ n=find_ext_var(buff);
+ if(!n){
+ error(82,buff);
+ break;
+ }
+ v->fi->change_cnt++;
+ v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(varlist));
+ v->fi->change_list[v->fi->change_cnt-1].v=n;
+ v->fi->change_list[v->fi->change_cnt-1].flags=n->vtyp->flags;
+ while(isspace((unsigned char)*attr)) attr++;
+ if(*attr==','||*attr=='/') attr++;
+ }
+ }
+ attr=v->vattr;
+ while(attr=strstr(attr,"regused(")){
+ int r,i;
+ static char rname[MAXI];
+ attr+=8;
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_REGS;
+ while(1){
+ while(isspace((unsigned char)*attr)) attr++;
+ for(i=0;i<MAXI-1&&*attr&&!isspace((unsigned char)*attr)&&*attr!=','&&*attr!=')'&&*attr!='/';i++)
+ rname[i]=*attr++;
+ rname[i]=0;
+ for(r=1;r<=MAXR;r++){
+ if(!reg_pair(r,&rp)&&!strcmp(rname,regnames[r])){
+ BSET(v->fi->regs_modified,r);
+ while(isspace((unsigned char)*attr)) attr++;
+ if(*attr==','||*attr=='/') attr++;
+ break;
+ }
+ }
+ if(r>MAXR){
+ if(rname[0]) error(220,rname);
+ break;
+ }
+ }
+ }
+ attr=v->vattr;
+ while(attr=strstr(attr,"stack1(")){
+ unsigned long sz;
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ attr+=7;
+ if(sscanf(attr,"%lu",&sz)!=1) ierror(0); /*FIXME*/
+ v->fi->stack1=ul2zum(sz);
+ }
+ attr=v->vattr;
+ while(attr=strstr(attr,"stack2(")){
+ unsigned long sz;
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALL_STACK;
+ attr+=7;
+ if(sscanf(attr,"%lu",&sz)!=1) ierror(0); /*FIXME*/
+ v->fi->stack2=ul2zum(sz);
+ }
+ if(strstr(v->vattr,"noreturn()")){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=NEVER_RETURNS;
+ }
+ if(strstr(v->vattr,"alwaysreturn()")){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=ALWAYS_RETURNS;
+ }
+ if(strstr(v->vattr,"nosidefx()")){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=NOSIDEFX;
+ }
+ if(strstr(v->vattr,"noinline()")){
+ if(!v->fi) v->fi=new_fi();
+ v->fi->flags|=NO_INLINE;
+ }
+}
+#define pragma_killsp() while(isspace((unsigned char)*s)) s++;
+char *pragma_cpbez(char *buff,char *s)
+{
+ int cnt=0;
+ if(*s=='_'||isalpha((unsigned char)*s)){
+ *buff++=*s++;
+ cnt++;
+ while(cnt<MAXI-1&&(*s=='_'||isalnum((unsigned char)*s))){
+ *buff++=*s++;
+ cnt++;
+ }
+ }
+ *buff++=0;
+ return s;
+}
+#define WARNSTACKSIZE 128
+static int widx,warn_num[WARNSTACKSIZE],warn_flags[WARNSTACKSIZE];
+#define PACKSTACKSIZE 128
+static int pidx,pack[PACKSTACKSIZE];
+void do_pragma(char *s)
+{
+ error(163);
+ pragma_killsp();
+ if(!strncmp("opt",s,3)){
+ s+=3;pragma_killsp();
+ c_flags_val[0].l=optflags=atol(s);
+ if(DEBUG&1) printf("#pragma opt %ld\n",c_flags_val[0].l);
+ }else if(!strncmp("dontwarn",s,8)){
+ int i;
+ s+=8;pragma_killsp();
+ if(widx>=WARNSTACKSIZE) ierror(0);
+ if(sscanf(s,"%d",&i)==1){
+ if(i>=err_num) error(159,i);
+ warn_num[widx]=i;
+ warn_flags[widx]=err_out[i].flags;
+ widx++;
+ err_out[i].flags|=DONTWARN;
+ }
+ }else if(!strncmp("warn",s,4)){
+ int i;
+ s+=4;pragma_killsp();
+ if(widx>=WARNSTACKSIZE) ierror(0);
+ if(sscanf(s,"%d",&i)==1){
+ if(i>=err_num) error(159,i);
+ warn_num[widx]=i;
+ warn_flags[widx]=err_out[i].flags;
+ widx++;
+ err_out[i].flags&=~DONTWARN;
+ }
+ }else if(!strncmp("popwarn",s,7)){
+ if(widx<=0) error(303);
+ widx--;
+ err_out[warn_num[widx]].flags=warn_flags[widx];
+ }else if(!strncmp("begin_header",s,12)){
+ header_cnt++;
+ }else if(!strncmp("end_header",s,10)){
+ header_cnt--;
+ }else if(!strncmp("pfi",s,3)){
+ Var *v;
+ s+=3;pragma_killsp();
+ pragma_cpbez(buff,s);
+ if(DEBUG&1) printf("print function_info %s\n",buff);
+ v=find_var(buff,0);
+ if(v&&v->fi) print_fi(stdout,v->fi);
+ }else if(!strncmp("finfo",s,5)){
+ Var *v;
+ s+=5;pragma_killsp();
+ pragma_cpbez(buff,s);
+ if(DEBUG&1) printf("new function_info %s\n",buff);
+ v=find_var(buff,0);
+ if(v){
+ if(!v->fi) v->fi=new_fi();
+ current_fi=v->fi;
+ }
+ }else if(!strncmp("fi_flags",s,8)){
+ unsigned long flags;
+ s+=8;pragma_killsp();
+ sscanf(s,"%lu",&flags);
+ if(DEBUG&1) printf("fi_flags %lu\n",flags);
+ if(current_fi) current_fi->flags=flags;
+ }else if(!strncmp("fi_uses",s,7)){
+ int t;Var *v;
+ s+=7;pragma_killsp();
+ s=pragma_cpbez(buff,s);
+ t=nesting;nesting=0;
+ v=find_var(buff,0);
+ nesting=t;
+ sscanf(s,"%d",&t);
+ if(DEBUG&1) printf("new fi_use %s,%d\n",buff,t);
+ if(current_fi){
+ current_fi->use_cnt++;
+ current_fi->use_list=myrealloc(current_fi->use_list,current_fi->use_cnt*sizeof(varlist));
+ current_fi->use_list[current_fi->use_cnt-1].v=v;
+ current_fi->use_list[current_fi->use_cnt-1].flags=t;
+ }
+ }else if(!strncmp("fi_changes",s,10)){
+ int t;Var *v;
+ s+=10;pragma_killsp();
+ s=pragma_cpbez(buff,s);
+ t=nesting;nesting=0;
+ v=find_var(buff,0);
+ nesting=t;
+ sscanf(s,"%d",&t);
+ if(DEBUG&1) printf("new fi_change %s,%d\n",buff,t);
+ if(current_fi){
+ current_fi->change_cnt++;
+ current_fi->change_list=myrealloc(current_fi->change_list,current_fi->change_cnt*sizeof(varlist));
+ current_fi->change_list[current_fi->change_cnt-1].v=v;
+ current_fi->change_list[current_fi->change_cnt-1].flags=t;
+ }
+ }else if(!strncmp("fi_calls",s,8)){
+ int t;Var *v;
+ s+=8;pragma_killsp();
+ s=pragma_cpbez(buff,s);
+ t=nesting;nesting=0;
+ v=find_var(buff,0);
+ nesting=t;
+ sscanf(s,"%d",&t);
+ if(DEBUG&1) printf("new fi_call %s,%d\n",buff,t);
+ if(current_fi){
+ current_fi->call_cnt++;
+ current_fi->call_list=myrealloc(current_fi->call_list,current_fi->call_cnt*sizeof(varlist));
+ current_fi->call_list[current_fi->call_cnt-1].v=v;
+ current_fi->call_list[current_fi->call_cnt-1].flags=t;
+ }
+ }else if(!strncmp("fi_regs",s,7)){
+ int r;
+ s+=7;pragma_killsp();
+ pragma_cpbez(buff,s);
+ for(r=1;r<=MAXR;r++)
+ if(!strcmp(buff,regnames[r])) break;
+ if(r<=MAXR&¤t_fi)
+ BSET(current_fi->regs_modified,r);
+ }else if(!strncmp("printflike",s,10)){
+ Var *v;
+ s+=10;pragma_killsp();
+ pragma_cpbez(buff,s);
+ if(DEBUG&1) printf("printflike %s\n",buff);
+ v=find_var(buff,0);
+ if(v){
+ v->flags|=PRINTFLIKE;
+ if(DEBUG&1) printf("succeeded\n");
+ }
+ }else if(!strncmp("scanflike",s,9)){
+ Var *v;
+ s+=9;pragma_killsp();
+ pragma_cpbez(buff,s);
+ if(DEBUG&1) printf("scanflike %s\n",buff);
+ v=find_var(buff,0);
+ if(v){
+ v->flags|=SCANFLIKE;
+ if(DEBUG&1) printf("succeeded\n");
+ }
+ }else if(!strncmp("only-inline",s,11)){
+ s+=11;pragma_killsp();
+ if(!strncmp("on",s,2)){
+ if(DEBUG&1) printf("only-inline on\n");
+ only_inline=1;
+ }else{
+ if(DEBUG&1) printf("only-inline off\n");
+ only_inline=2;
+ }
+ }else if(!strncmp("pack",s,4)){
+ /* packing of structures */
+ s+=4;pragma_killsp();
+ if(*s=='(') { s++;pragma_killsp();}
+ if(!strncmp("push",s,4)){
+ if(pidx==PACKSTACKSIZE){
+ memmove(pack,pack+1,(PACKSTACKSIZE-1)*sizeof(pack[0]));
+ pidx--;
+ }
+ pack[pidx++]=pack_align;
+ s+=4;pragma_killsp();
+ if(*s==','){
+ s++;pragma_killsp();
+ sscanf(s,"%i",&pack_align);
+ }
+ }else if(!strncmp("pop",s,3)){
+ if(pidx>0) pack_align=pack[--pidx];
+ else pack_align=0;
+ }else if(*s==')')
+ pack_align=0;
+ else
+ sscanf(s,"%i",&pack_align);
+#if 0
+ }else if(!strncmp("type",s,4)){
+ /* Typ eines Ausdrucks im Klartext ausgeben */
+ np tree;
+ s+=4;strcat(s,";");
+ tree=expression();
+ if(tree&&type_expression(tree)){
+ printf("type of %s is:\n",string+7);
+ prd(stdout,tree->ntyp);printf("\n");
+ }
+ if(tree) free_expression(tree);
+ }else if(!strncmp("tree",s,4)){
+ /* gibt eine expression aus */
+ np tree;
+ s+=4;strcat(s,";");
+ tree=expression();
+ if(tree&&type_expression(tree)){
+ printf("tree of %s is:\n",string+7);
+ pre(stdout,tree);printf("\n");
+ }
+ if(tree) free_expression(tree);
+#endif
+#ifdef HAVE_ECPP
+/* 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
+ }else{
+#ifdef HAVE_TARGET_PRAGMAS
+ handle_pragma(s);
+#endif
+ }
+}
+void killsp(void)
+/* Ueberspringt Fuellzeichen */
+/* noch einige unschoene Dinge drin */
+{
+ /*FIXME: #pragma etc. */
+ while(!eof&&(ttWHI(ctok->type)||ctok->type==PRAGMA||(!input_wpo&&!ls.condcomp))){
+ if(ctok->type==PRAGMA)
+ do_pragma(ctok->name);
+ next_token();
+ }
+}
+void enter_block(void)
+/* Setzt Zeiger/Struckturen bei Eintritt in neuen Block */
+{
+ if(nesting>=MAXN){error(9,nesting);return;}
+ nesting++;
+ if(DEBUG&1) printf("enter block %d\n",nesting);
+ first_ilist[nesting]=last_ilist[nesting]=0;
+ first_sd[nesting]=last_sd[nesting]=0;
+ first_si[nesting]=last_si[nesting]=0;
+ first_var[nesting]=last_var[nesting]=0;
+ if(nesting==1){
+ first_llist=last_llist=0;
+ first_clist=last_clist=0;
+ merk_varf=merk_varl=0;
+ merk_ilistf=merk_ilistl=0;
+ merk_sif=merk_sil=0;
+/* struct-declarations erst ganz am Schluss loeschen. Um zu vermeiden, */
+/* dass struct-declarations in Prototypen frei werden und dann eine */
+/* spaetere struct, dieselbe Adresse bekommt und dadurch gleich wird. */
+/* Nicht sehr schoen - wenn moeglich noch mal aendern. */
+/* merk_sdf=merk_sdl=0;*/
+ afterlabel=0;
+ }
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+#endif
+}
+void leave_block(void)
+/* Setzt Zeiger/Struckturen bei Verlassen eines Blocks */
+{
+ static int inleave;
+ int i;
+ if(inleave) return;
+ inleave=1;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+#endif
+ for(i=1;i<=MAXR;i++)
+ if(regbnesting[i]==nesting) regsbuf[i]=0;
+ if(nesting<0){error(10);inleave=0;return;}
+ if(DEBUG&1) printf("leave block %d vla=%p\n",nesting,(void *)block_vla[nesting]);
+ if(block_vla[nesting]) clearvl();
+ if(nesting>0){
+ if(merk_varl) merk_varl->next=first_var[nesting]; else merk_varf=first_var[nesting];
+ if(last_var[nesting]) merk_varl=last_var[nesting];
+ if(merk_sil) merk_sil->next=first_si[nesting]; else merk_sif=first_si[nesting];
+ if(last_si[nesting]) merk_sil=last_si[nesting];
+ if(merk_sdl) merk_sdl->next=first_sd[nesting]; else merk_sdf=first_sd[nesting];
+ if(last_sd[nesting]) merk_sdl=last_sd[nesting];
+ if(merk_ilistl) merk_ilistl->next=first_ilist[nesting]; else merk_ilistf=first_ilist[nesting];
+ if(last_ilist[nesting]) merk_ilistl=last_ilist[nesting];
+ }
+ if(nesting==1){
+ if(cross_module){
+ /* anything to do? */
+ }else{
+ if(merk_varf) gen_vars(merk_varf);
+ if(first_llist) free_llist(first_llist);
+ first_llist=0;
+ if(first_clist) free_clist(first_clist);
+ first_clist=0;
+ if(merk_varf) free_var(merk_varf);
+ merk_varf=0;
+ if(merk_sif) free_si(merk_sif);
+ merk_sif=0;
+ /* struct-declarations erst ganz am Schluss loeschen. Um zu vermeiden, */
+ /* dass struct-declarations in Prototypen frei werden und dann eine */
+ /* spaetere struct, dieselbe Adresse bekommt und dadurch gleich wird. */
+ /* Nicht sehr schoen - wenn moeglich noch mal aendern. */
+ /* if(merk_sdf) free_sd(merk_sdf);*/
+ if(merk_ilistf) free_ilist(merk_ilistf);
+ merk_ilistf=0;
+ }
+ }
+ if(nesting==0){
+ if(/*ecpp||*/cross_module){
+ /* don't free struct_declarations in EC++ for now, since they can be */
+ /* referenced even when they are not in scope */
+ /* anything to do? */
+ }else{
+ /* struct-declarations erst ganz am Schluss loeschen. Um zu vermeiden, */
+ /* dass struct-declarations in Prototypen frei werden und dann eine */
+ /* spaetere struct, dieselbe Adresse bekommt und dadurch gleich wird. */
+ /* Nicht sehr schoen - wenn moeglich noch mal aendern. */
+ if(first_si[0]) free_si(first_si[0]);
+ if(first_ext)
+ gen_vars(first_ext);
+ if(first_var[0])
+ gen_vars(first_var[0]);
+ if(first_ext)
+ free_var(first_ext);
+ if(first_var[0])
+ free_var(first_var[0]);
+ if(merk_sdf) free_sd(merk_sdf);
+ if(first_sd[0]) free_sd(first_sd[0]);
+ if(first_ilist[0]) free_ilist(first_ilist[0]);
+ }
+ }
+ nesting--;
+ inleave=0;
+}
+void pra(FILE *f,argument_list *p)
+/* Gibt argument_list umgekehrt auf Bildschirm aus */
+{
+ if(p->next){ pra(f,p->next);fprintf(f,",");}
+ if(p->arg) pre(f,p->arg);
+}
+void pre(FILE *f,np p)
+/* Gibt expression auf Bildschirm aus */
+{
+ int c;
+ c=p->flags;
+ if(p->sidefx) fprintf(f,"/");
+ if(p->lvalue) fprintf(f,"|");
+ if(c==CALL){fprintf(f,"call-function(");pre(f,p->left);fprintf(f,")(");
+ if(p->alist) pra(f,p->alist);
+ fprintf(f,")");return;}
+ if(c==CAST){fprintf(f,"cast(");pre(f,p->left);
+ fprintf(f,"->");prd(f,p->ntyp);
+ fprintf(f,")");return;}
+ if(c==MEMBER){if(p->identifier) fprintf(f,".%s",p->identifier);return;}
+ if(c==IDENTIFIER){if(p->identifier) fprintf(f,"%s",p->identifier);
+ fprintf(f,"+");printval(f,&p->val,LONG); return;}
+ fprintf(f,"%s(",ename[c]);
+ if(p->left) pre(f,p->left);
+ if(p->right){
+ fprintf(f,",");
+ pre(f,p->right);
+ }
+ fprintf(f,")");
+ if(c==CEXPR||c==PCEXPR){fprintf(f,"(value="); printval(f,&p->val,p->ntyp->flags); fprintf(f,")");}
+}
+static int pp_line;
+void do_error(int errn,va_list vl)
+/* Behandelt Ausgaben wie Fehler und Meldungen */
+{
+ int type,have_stack=0;
+ int treat_warning_as_error=0;
+ char *errstr="",*txt=filename;
+ if(c_flags_val[8].l&&c_flags_val[8].l<=errors)
+ return;
+ if(errn==-1) errn=158;
+ type=err_out[errn].flags;
+ treat_warning_as_error=(type&WARNING)&&(c_flags[54]&USEDFLAG);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(type&DONTWARN) return;
+ if(type&WARNING) errstr="warning";
+ if(type&ERROR) errstr="error";
+ if(input_wpo){
+ fprintf(stderr,"%s %d: ",errstr,errn);
+ }else if((type&NOLINE)/*||((type&PREPROC)&&pp_line<=0)*/){
+ fprintf(stderr,"%s %d: ",errstr,errn);
+ }else if(type&(INFUNC|INIC)){
+ if((type&INIC)&&err_ic&&err_ic->line){
+ fprintf(stderr,"%s %d in line %d of \"%s\": ",errstr,errn,err_ic->line,err_ic->file);
+
+
+ }else{
+ fprintf(stderr,"%s %d in function \"%s\": ",errstr,errn,cur_func);
+ }
+ }else if(!input_wpo){
+ int n;
+ if(eof){
+ fprintf(stderr,">EOF\n");
+ }else{
+ if(ls.cli!=0) ls.copy_line[ls.cli]=0;
+ fprintf(stderr,">%s\n",ls.copy_line);
+ }
+ if(type&PREPROC){
+ txt=current_filename;
+ n=pp_line;
+ }else{
+ if(ctok)
+ n=ctok->line;
+ else
+ n=-1;
+ }
+ if(c_flags[20]&USEDFLAG){ /* strip-path from filename */
+ char *p=txt,c;
+ while(c=*p++)
+ if(c==':'||c=='/'||c=='\\') txt=p;
+ }
+ fprintf(stderr,"%s %d in line %d of \"%s\": ",errstr,errn,n,txt);
+ have_stack=1; /* we can report the include stack */
+ }
+ vfprintf(stderr,err_out[errn].text,vl);
+ fprintf(stderr,"\n");
+ if(have_stack&&(!(c_flags[49]&USEDFLAG))){
+ int i;
+ stack_context *sc = report_context();
+ for(i=0;;i++){
+ if(sc[i].line==-1) break;
+ fprintf(stderr,"\tincluded from file \"%s\":%ld\n",sc[i].long_name?sc[i].long_name:sc[i].name,sc[i].line);
+ }
+ }
+ if(treat_warning_as_error){fprintf(stderr,"warning %d treated as error [-warnings-as-errors]\n",errn);}
+ if(type&ERROR||treat_warning_as_error){
+ errors++;
+ if(c_flags_val[8].l&&c_flags_val[8].l<=errors&&!(type&NORAUS))
+ {fprintf(stderr,"Maximum number of errors reached!\n");raus();}
+ }
+ if(type&FATAL){fprintf(stderr,"aborting...\n");raus();}
+}
+void error(int errn,...)
+{
+ va_list vl;
+ va_start(vl,errn);
+ do_error(errn,vl);
+ va_end(vl);
+}
+void ucpp_ouch(char *fmt, ...)
+{
+ ierror(0);
+}
+void do_ucpp_error(char *fmt,va_list vl)
+{
+ int i;
+ for(i=0;i<err_num;i++){
+ if(!strcmp(fmt,err_out[i].text))
+ break;
+ }
+ if(*fmt=='#'){
+ /* #error/#warning-directive */
+ i=*(fmt+1)=='w'?325:292;
+ }
+ if(i>=err_num){
+ puts(fmt);
+ ierror(0);
+ }
+ do_error(i,vl);
+}
+void ucpp_error(long line, char *fmt, ...)
+{
+ va_list ap;
+ pp_line=line;
+ va_start(ap, fmt);
+ do_ucpp_error(fmt,ap);
+ va_end(ap);
+}
+void ucpp_warning(long line, char *fmt, ...)
+{
+ va_list ap;
+ pp_line=line;
+ va_start(ap, fmt);
+ do_ucpp_error(fmt,ap);
+ va_end(ap);
+}
+
+void misra(int n,...)
+{
+ va_list vl;
+ if(!misracheck) return;
+ va_start(vl,n);
+ fprintf(stderr,"MISRA error %d\n",n);
+ va_end(vl);
+}
+
+void misra_error(int n, int rule, int subrule, int line, ...) {
+ va_list vl;
+ tmisra_err_out* misr_err;
+ char* mis_vers_string;
+ char mis_numb_string[100];
+ char* rule_text;
+ int not_found;
+ if (!misracheck) return;
+ mis_vers_string = 0;
+ va_start(vl,line);
+
+ if (line == 0) line = ctok->line;
+
+ if ((n) && (misraversion==1998)) {
+ if (misra_98_warn_flag[n-1] != 1) return; /* TODO: Zhler setzen wenn nur ein paar nicht ausgegeben werden sollen */
+ mis_vers_string = mystrdup("1998");
+ sprintf(mis_numb_string,"%d",n);
+ misr_err = NULL;
+ } else if ((rule) && (misraversion==2004)) {
+ if (misra_04_warn_flag[rule-1][subrule-1] != 1) return;/* TODO: Zhler setzen wenn nur ein paar nicht ausgegeben werden sollen */
+ mis_vers_string = mystrdup("2004");
+ sprintf(mis_numb_string,"Chapter %d, Rule %d",rule,subrule);
+ if (subrule) {
+ misr_err = misra_err_out;
+ not_found = 1;
+ while ( not_found ) {
+ if ((misr_err->chapter == rule) && (misr_err->rule == subrule)) {
+ not_found = 0;
+ break;
+ }
+ misr_err++;
+ }
+ }
+ }
+ if (!mis_vers_string) return;
+ if (misr_err) fprintf(stderr,"MISRA(%s) Rule violation (%s) in line <%d>\n%s\n",mis_vers_string,mis_numb_string,line,misr_err->text);
+ else fprintf(stderr,"MISRA(%s) Rule violation (%s) in line <%d>: No description found\n",mis_vers_string,mis_numb_string,line);
+
+ if (mis_vers_string) free(mis_vers_string);
+
+ va_end(vl);
+}
+
+void misra_neu(int n,int rule,int subrule, int line, ...)
+{
+ va_list vl;
+ int mis_warn = 0;
+ misra_error(n,rule,subrule,line);
+ return;
+ va_start(vl,line);
+ va_end(vl);
+
+}
+
+FILE *open_out(char *name,char *ext)
+/* Haengt ext an name an und versucht diese File als output zu oeffnen */
+{
+ char *s,*p;FILE *f;
+ if(ext){
+ s=mymalloc(strlen(name)+strlen(ext)+2);
+ strcpy(s,name);
+ p=s+strlen(s);
+ while(p>=s){
+ if(*p=='.'){*p=0;break;}
+ p--;
+ }
+ strcat(s,".");
+ strcat(s,ext);
+ }else
+ s=name;
+ f=fopen(s,"w");
+ if(!f) fprintf(stderr,"Couldn't open <%s> for output!\n",s);
+ if(ext) free(s);
+ return(f);
+}
diff --git a/mbasic.c b/mbasic.c
new file mode 100755
index 0000000..5d7308a
--- /dev/null
+++ b/mbasic.c
@@ -0,0 +1,229 @@
+/* Test-language for vbcc. */
+
+#include "supp.h"
+
+#include <ctype.h>
+#include <stdio.h>
+
+struct Var *fv;
+
+struct Typ tint,mfunc;
+struct struct_declaration msd; /* initialized to zero */
+
+FILE *file;
+char *next;
+
+struct obj expression(),factor(),scalar();
+
+void raus(void)
+{
+ while(fv){
+ struct Var *m=fv->next;
+ free(fv);
+ fv=m;
+ }
+ while(first_ic){
+ struct IC *m=first_ic->next;
+ free(first_ic);
+ first_ic=m;
+ }
+ exit(0);
+}
+void add_IC(struct IC *new)
+{
+ new->next=0;
+ new->prev=last_ic;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->line=0;
+ new->file=0;
+ new->q1.am=new->q2.am=new->z.am=0;
+ if(!last_ic){
+ first_ic=new;
+ }else{
+ last_ic->next=new;
+ }
+ last_ic=new;
+}
+struct Var *add_var(char *name,struct Typ *t,int sc)
+{
+ struct Var *v=mymalloc(sizeof(*v));
+ v->vtyp=t;
+ v->storage_class=sc;
+ v->reg=0;
+ v->identifier=name;
+ v->offset=max_offset;
+ if(sc==AUTO) max_offset=zmadd(max_offset,sizetab[t->flags&NQ]);
+ v->priority=1;
+ v->flags=0;
+ v->next=fv;
+ v->clist=0;
+ v->fi=0;
+ v->inline_copy=0;
+ v->nesting=1;
+ fv=v;
+ return v;
+}
+struct Var *add_tmp_var(struct Typ *t)
+{
+ return add_var(empty,t,AUTO);
+}
+struct Var *get_var(char *name)
+{
+ struct Var *v;char *buf;
+ puts("getvar");
+ for(v=fv;v;v=v->next){
+ if(!strcmp(name,v->identifier)) return v;
+ }
+ buf=mymalloc(strlen(name)+1);
+ strcpy(buf,name);
+ return add_var(buf,&tint,AUTO);
+}
+
+char *identifier(void)
+{
+ static char id[1024];
+ char *s=id;
+ puts("identifier");
+ while(isalnum(*next)) *s++=*next++;
+ puts("done");
+ return id;
+}
+struct obj scalar(void)
+{
+ struct obj o;
+ zmax val;
+ puts("scalar");
+ if(isdigit(*next)){
+ o.flags=KONST;
+ val=l2zm(0L);
+ while(isdigit(*next)){
+ val=zmmult(val,l2zm(10L));
+ val=zmadd(val,l2zm((long)(*next-'0')));
+ next++;
+ }
+ o.val.vint=zm2zi(val);
+ return o;
+ }
+ if(*next=='('){
+ next++;
+ o=expression();
+ next++;
+ return o;
+ }
+ o.flags=VAR;
+ o.val.vmax=l2zm(0L);
+ o.v=get_var(identifier());
+ return o;
+}
+struct obj factor(void)
+{
+ struct obj o;
+ struct IC *new;
+ puts("factor");
+ o=scalar();
+ while(*next=='*'||*next=='/'){
+ new=new_IC();
+ if(*next=='*') new->code=MULT; else new->code=DIV;
+ next++;
+ new->typf=INT;
+ new->q1=o;
+ new->q2=scalar();
+ o.flags=VAR;
+ o.v=add_tmp_var(&tint);
+ o.val.vmax=l2zm(0L);
+ new->z=o;
+ add_IC(new);
+ }
+ return o;
+}
+struct obj expression(void)
+{
+ struct obj o;
+ struct IC *new;
+ puts("expression");
+ o=factor();
+ while(*next=='+'||*next=='-'){
+ new=new_IC();
+ if(*next=='+') new->code=ADD; else new->code=SUB;
+ next++;
+ new->typf=INT;
+ new->q1=o;
+ new->q2=factor();
+ o.flags=VAR;
+ o.v=add_tmp_var(&tint);
+ o.val.vmax=l2zm(0L);
+ new->z=o;
+ add_IC(new);
+ }
+ return o;
+}
+void compile(void)
+{
+ struct IC *new;
+ char line[1024],*s;
+ struct obj o,last;
+ puts("compile");
+ while(fgets(line,1023,file)){
+ next=line;
+ s=identifier();
+ if(*next=='='){
+ struct Var *v=get_var(s);
+ next++;
+ o=expression();
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=INT;
+ new->q1=o;
+ new->z.flags=VAR;
+ new->z.v=v;
+ new->z.val.vmax=l2zm(0L);
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[INT];
+ last=new->z;
+ add_IC(new);
+ continue;
+ }
+ }
+ new=new_IC();
+ new->code=SETRETURN;
+ new->typf=INT;
+ new->q1=last;
+ new->q2.flags=new->z.flags=0;
+ new->q2.val.vmax=sizetab[INT];
+ new->z.reg=freturn(&tint);
+ if(!new->z.reg) puts("problem!");
+ add_IC(new);
+}
+void error(int n,...)
+{
+ printf("error %d\n",n);
+ raus();
+}
+void savescratch()
+{}
+
+main(int argc,char **argv)
+{
+ struct Var *main;
+ max_offset=l2zm(0L);
+ if(!init_cg()) raus();
+ tint.flags=INT;
+ tint.next=0;
+ mfunc.flags=FUNKT;
+ mfunc.next=∭
+ mfunc.exact=&msd;
+ main=add_var("main",&mfunc,EXTERN);
+ file=fopen(argv[1],"r");
+ if(!file) {printf("Error opening file\n");raus();}
+ compile();
+ scanf("%ld",&optflags);
+ pric(stdout,first_ic);
+ vl1=vl3=0;
+ vl2=fv;
+ optimize(optflags,main);
+ pric(stdout,first_ic);
+ gen_code(stdout,first_ic,main,max_offset);
+ raus();
+}
+
diff --git a/minicomp.c b/minicomp.c
new file mode 100755
index 0000000..1bf274b
--- /dev/null
+++ b/minicomp.c
@@ -0,0 +1,913 @@
+#include "minicomp.h"
+
+#define clone_type clone_typ
+#define free_type freetyp
+#define new_icode new_IC
+#define add_icode add_IC
+#define free_all_icode() free_IC(first_ic)
+#define get_first_icode() first_ic
+typedef struct IC icode;
+
+static int errors;
+var *store_locals;
+
+struct rpair rp;
+
+char *copyright="minicomp/vbcc (c) in 2002 Volker Barthelmann";
+char *inname,*outname;
+struct struct_declaration *first_sd;
+struct Var *first_ext,*merk_varf;
+char **target_macros;
+
+FILE *out;
+
+void raus(void)
+{
+ var *v;
+ for(v=first_var[0];v;v=v->next)
+ if(v->type->flags!=FUNCTION){
+ gen_align(out,falign(v->type));
+ gen_var_head(out,v->vbccvar);
+ gen_ds(out,szof(v->type),v->type);
+ }
+
+ cleanup_cg(out);
+
+ if(errors>0)
+ exit(EXIT_FAILURE);
+ else
+ exit(EXIT_SUCCESS);
+}
+
+main(int argc,char **argv)
+{
+ int i,j,flag;
+ type *nt;
+
+ for(i=1;i<argc;i++){
+ if(*argv[i]!='-'){
+ if(inname)
+ error(18,"multiple input files");
+ inname=argv[i];
+ }else{
+ flag=0;
+ if((!strcmp("-o",argv[i]))&&i<argc-1){
+ flag=1;
+ outname=argv[++i];
+ continue;
+ }
+ if(!strncmp("-debug=",argv[i],7)){
+ flag=1;
+ sscanf(argv[i]+7,"%d",&j);
+ DEBUG=j;
+ continue;
+ }
+ if(!strncmp("-unroll-size=",argv[i],13)){
+ flag=1;
+ sscanf(argv[i]+13,"%d",&j);
+ unroll_size=j;
+ continue;
+ }
+ if(!strncmp("-inline-size=",argv[i],13)){
+ flag=1;
+ sscanf(argv[i]+13,"%d",&j);
+ inline_size=j;
+ continue;
+ }
+ if(!strncmp("-maxoptpasses=",argv[i],14)){
+ flag=1;
+ sscanf(argv[i]+14,"%d",&j);
+ maxoptpasses=j;
+ continue;
+ }
+ for(j=0;j<MAXGF&&flag==0;j++){
+ size_t l;
+ if(!g_flags_name[j]) continue;
+ l=strlen(g_flags_name[j]);
+ if(l>0&&!strncmp(argv[i]+1,g_flags_name[j],l)){
+ flag=1;
+ if((g_flags[j]&(USEDFLAG|FUNCFLAG))==USEDFLAG){error(19,"multiple option");break;}
+ g_flags[j]|=USEDFLAG;
+ if(g_flags[j]&STRINGFLAG){
+ if(argv[i][l+1]!='='){error(21,"string expected");}
+ if(argv[i][l+2]||i>=argc-1)
+ g_flags_val[j].p=&argv[i][l+2];
+ else
+ g_flags_val[j].p=&argv[++i][0];
+ }
+ if(g_flags[j]&VALFLAG){
+ if(argv[i][l+1]!='='){error(20,"value expected");}
+ if(argv[i][l+2]||i>=argc-1)
+ g_flags_val[j].l=atol(&argv[i][l+2]);
+ else
+ g_flags_val[j].l=atol(&argv[++i][0]);
+ }
+ if(g_flags[j]&FUNCFLAG) g_flags_val[j].f(&argv[i][l+1]);
+ }
+ }
+ if(!flag) error(23,"unknown option");
+ }
+ }
+
+ if(!inname)
+ error(22,"no input file");
+ infile=fopen(inname,"r");
+ if(!infile)
+ error(18,"could not open output file");
+ if(!outname)
+ error(23,"no output file");
+ out=fopen(outname,"w");
+ if(!out){
+ error(24,"could not open input file");
+ }
+ nt=new_type(FUNCTION);
+ nt->next=new_type(INT);
+ add_var("readInt",clone_type(nt));
+ add_var("writeInt",clone_type(nt));
+ add_var("writeChar",clone_type(nt));
+ add_var("readChar",clone_type(nt));
+ add_var("writeReal",nt);
+ nt=new_type(FUNCTION);
+ nt->next=new_type(REAL);
+ add_var("readReal",nt);
+
+ stackalign=l2zm(0L);
+ if(!init_cg()) exit(EXIT_FAILURE);
+ if(zmeqto(stackalign,l2zm(0L)))
+ stackalign=maxalign;
+ for(i=0;i<EMIT_BUF_DEPTH;i++)
+ emit_buffer[i]=mymalloc(EMIT_BUF_LEN);
+ emit_p=emit_buffer[0];
+
+ multiple_ccs=0;
+ optflags=-1;
+ maxoptpasses=100;
+
+ yyparse();
+
+ raus();
+}
+
+yyerror(char *s)
+{
+ error(1,s);
+}
+
+void error(int n,...)
+{
+ if(n==170||n==172) return;
+ errors++;
+ fprintf(stderr,"error %d\n",n);
+ raus();
+}
+
+void *getmem(size_t s)
+{
+ void *p=malloc(s);
+ if(!p){
+ error(2,"out of memory");
+ }
+ return p;
+}
+
+#define LABELNESTING 1024
+static int labelstack[LABELNESTING],labelidx;
+
+void push_int(int l)
+{
+ labelstack[labelidx++]=l;
+}
+
+int pop_int()
+{
+ return labelstack[--labelidx];
+}
+
+#define NAMENESTING 1024
+static char *namestack[NAMENESTING],nameidx;
+
+void push_ptr(void *ptr)
+{
+ namestack[nameidx++]=ptr;
+}
+
+void *pop_ptr()
+{
+ return namestack[--nameidx];
+}
+
+
+char *typename[]={" ","int","real","array","function"};
+
+
+type *new_type(int t)
+{
+ type *new=new_typ();
+ new->flags=t;
+ new->next=0;
+ return new;
+}
+
+type *new_array(type *t,node *p)
+{
+ type *new=new_typ();
+ simplify_tree(p);
+ if(p->flags!=NNUMBER)
+ error(3,"array size not a constant");
+ if(p->type->flags!=INT)
+ error(4,"array size not an integer");
+ new->flags=ARRAY;
+ new->next=t;
+ new->size=l2zm((long)p->ivalue);
+ free_tree(p);
+ return new;
+}
+
+int nesting;
+int local_offset,parm_offset,framesize;
+
+#define MAXNESTING 128
+var *first_var[128];
+
+void free_varlist(var *v)
+{
+ var *m;
+ while(v){
+ free_var(v->vbccvar);
+ m=v->next;
+ free(v);
+ v=m;
+ }
+}
+
+void enter_block()
+{
+ nesting++;
+ first_var[nesting]=0;
+ push_int(local_offset);
+}
+
+void leave_block()
+{
+ if(first_var[nesting]){
+ var *p=first_var[nesting];
+ while(p->next)
+ p=p->next;
+ p->next=store_locals;
+ p->vbccvar->next=merk_varf;
+ store_locals=first_var[nesting];
+ merk_varf=store_locals->vbccvar;
+ }
+ nesting--;
+ local_offset=pop_int();
+}
+
+void gen_func(var *v,icode *first,int framesize)
+{
+ pric(stdout,get_first_icode());
+ vl1=first_var[0]?first_var[0]->vbccvar:0;
+ vl2=first_var[1]?first_var[1]->vbccvar:0;
+ vl3=merk_varf;
+ optimize(optflags,v->vbccvar);
+ memset(regs_modified,0,RSIZE);
+ pric(stdout,get_first_icode());
+ gen_code(out,get_first_icode(),v->vbccvar,max_offset);
+}
+
+void enter_func(char *name,type *p)
+{
+ type *t=new_type(FUNCTION);
+ var *v;
+ t->next=p;
+ t->exact=getmem(sizeof(*t->exact));
+ t->exact->count=0;
+ v=add_var(name,t);
+ local_offset=parm_offset=framesize=0;
+ push_ptr(v);
+ enter_block();
+}
+
+void leave_func()
+{
+ icode *p,*merk;
+ leave_block();
+ gen_func(pop_ptr(),get_first_icode(),framesize);
+ free_all_icode();
+ first_ic=last_ic=0;
+ free_varlist(store_locals);
+ merk_varf=0;
+ store_locals=0;
+}
+
+var *find_var(char *p,int minnest)
+{
+ var *v;
+ int i;
+
+ for(i=nesting;i>=minnest;i--){
+ for(v=first_var[i];v;v=v->next)
+ if(!strcmp(v->name,p))
+ return v;
+ }
+ return 0;
+}
+
+var *add_var(char *name,type *t)
+{
+ var *new=getmem(sizeof(*new));
+ struct Var *vv;
+ /*FIXME: add vbccvar */
+ if(find_var(name,nesting))
+ error(5,"var %s already defined",name);
+ new->nesting=nesting;
+ new->name=add_string(name);
+ new->type=t;
+ if(*name==0){
+ new->next=store_locals;
+ }else{
+ new->next=first_var[nesting];
+ }
+ if(nesting==1){
+ /* parameter */
+ new->offset=parm_offset;
+ parm_offset+=szof(t);
+ }
+ if(nesting>1){
+ /* local variable */
+ new->offset=local_offset;
+ local_offset+=szof(t);
+ if(local_offset>framesize)
+ framesize=local_offset;
+ }
+ /* attach vbcc variable */
+ vv=new_var();
+ vv->vtyp=clone_typ(new->type);
+ vv->identifier=add_string(name);
+ vv->nesting=(*name!=0?nesting:2);
+ vv->storage_class=(vv->nesting==0?EXTERN:AUTO);
+ if(nesting==1)
+ vv->offset=zmsub(l2zm(0L),zmadd(maxalign,l2zm(new->offset)));
+ else
+ vv->offset=l2zm((long)local_offset);
+ new->vbccvar=vv;
+
+ if(*name==0){
+ store_locals=new;
+ vv->next=merk_varf;
+ merk_varf=vv;
+ }else{
+ vv->next=first_var[nesting]?first_var[nesting]->vbccvar:0;
+ first_var[nesting]=new;
+ }
+ return new;
+}
+
+var *new_temp(int tflags)
+{
+ char tname[16];
+ static int itmps,rtmps,ptmps;
+ if(tflags==INT)
+ sprintf(tname,"\0 itmp%d",++itmps);
+ else if(tflags==REAL)
+ sprintf(tname,"\0 rtmp%d",++rtmps);
+ else if(tflags==POINTER)
+ sprintf(tname,"\0 rtmp%d",++ptmps);
+ else
+ error(16,"internal");
+ return add_var(tname,new_type(tflags));
+}
+
+struct Var *add_tmp_var(struct Typ *t)
+{
+
+ return new_temp(t->flags)->vbccvar;
+}
+
+char *add_string(char *s)
+{
+ char *new=getmem(strlen(s)+1);
+ strcpy(new,s);
+ return new;
+}
+
+char *nodename[]={
+ "var","number","add","mul","sub","div","index","equals",
+ "lt","gt","leq","geq","neq","and","or",
+ "int2real","real2int","assign","call","argument"
+};
+
+node *number_node(void)
+{
+ node *new=getmem(sizeof(*new));
+ new->flags=NNUMBER;
+ if(strstr(tkname,".")){
+ double rval;
+ sscanf(tkname,"%lf",&rval);
+ new->rvalue=rval;
+ new->type=new_type(REAL);
+ new->left=new->right=0;
+ }else{
+ new->ivalue=atoi(tkname);
+ new->type=new_type(INT);
+ new->left=new->right=0;
+ }
+ return new;
+}
+
+node *var_node(void)
+{
+ var *v=find_var(tkname,0);
+ node *new;
+ if(!v){
+ error(6,"unknown identifier: %s",tkname);
+ }
+ new=getmem(sizeof(*new));
+ new->flags=NVARIABLE;
+ new->var=v;
+ new->type=clone_type(v->type);
+ new->left=new->right=0;
+ return new;
+}
+
+
+node *binary_node(enum nodeflags flags,node *left,node *right)
+{
+ node *new=getmem(sizeof(*new));
+ new->flags=flags;
+ new->left=left;
+ new->right=right;
+ new->type=0;
+ if(!left||(flags!=NCALL&&!right))
+ error(7,"internal error");
+ if(flags==NINDEX){
+ if(left->type->flags!=ARRAY)
+ error(8,"operand of [] must be array");
+ new->type=clone_type(left->type->next);
+ }else if(flags==NARG){
+ /* nothing to do? */
+ }else if(flags==NCALL){
+ if(left->type->flags!=FUNCTION)
+ error(9,"only functions can be called");
+ new->type=clone_type(left->type->next);
+ }else{
+ if(left->type->flags==ARRAY||right->type->flags==ARRAY)
+ error(10,"both operands must be real or int");
+ if(left->type->flags==REAL||right->type->flags==REAL){
+ new->type=new_type(REAL);
+ if(left->type->flags==INT){
+ new->left=conv_tree(left,REAL);
+ }
+ if(right->type->flags==INT){
+ new->right=conv_tree(right,REAL);
+ }
+ }else
+ new->type=new_type(INT);
+ }
+ return new;
+}
+
+void print_tree(node *p)
+{
+ printf("%s(",nodename[p->flags]);
+ if(p->left)
+ print_tree(p->left);
+ if(p->right){
+ printf(",");
+ print_tree(p->right);
+ }
+ if(p->flags==NNUMBER){
+ if(p->type->flags==INT)
+ printf("%d[int]",p->ivalue);
+ else
+ printf("%g[real]",p->rvalue);
+ }
+ if(p->flags==NVARIABLE)
+ printf("%s[%s]",p->var->name,typename[p->var->type->flags]);
+ printf(")");
+}
+
+node *conv_tree(node *p,int tflags)
+{
+ node *new;
+ if(p->type->flags==tflags)
+ return p;
+ new=getmem(sizeof(*new));
+ if(tflags==REAL)
+ new->flags=NI2R;
+ else
+ new->flags=NR2I;
+ new->type=new_type(p->type->flags);
+ new->left=p;
+ new->right=0;
+ return new;
+}
+
+void free_tree(node *p)
+{
+ if(p->left)
+ free_tree(p->left);
+ if(p->right)
+ free_tree(p->right);
+ if(p->type)
+ free_type(p->type);
+ free(p);
+}
+
+
+static void const_node(node *p,int val)
+{
+ p->flags=NNUMBER;
+ p->ivalue=val;
+ if(p->left)
+ free_tree(p->left);
+ if(p->right)
+ free_tree(p->right);
+ p->left=p->right=0;
+}
+
+void simplify_tree(node *p)
+{
+ if(p->left)
+ simplify_tree(p->left);
+ if(p->right)
+ simplify_tree(p->right);
+ if(p->type&&p->type->flags==INT&&p->left&&p->left->flags==NNUMBER&&p->right&&p->right->flags==NNUMBER){
+ switch(p->flags){
+ case NADD: const_node(p,p->left->ivalue+p->right->ivalue); break;
+ case NMUL: const_node(p,p->left->ivalue*p->right->ivalue); break;
+ case NSUB: const_node(p,p->left->ivalue-p->right->ivalue); break;
+ case NDIV:
+ if(p->right->ivalue!=0)
+ const_node(p,p->left->ivalue/p->right->ivalue); break;
+ }
+ }
+}
+
+void assign_statement(node *left,node *right)
+{
+ if(left->type->flags==ARRAY||right->type->flags==ARRAY)
+ error(11,"array type in assignment");
+ if(left->type->flags==FUNCTION||right->type->flags==FUNCTION)
+ error(12,"function type in assignment");
+
+ right=conv_tree(right,left->type->flags);
+ simplify_tree(left);
+ simplify_tree(right);
+ if(left->flags==NINDEX){
+ icode *n1,*n2,*n3;
+ n1=new_icode();
+ n1->code=MULT;
+ n1->typf=INT;
+ n1->q1=*gen_tree(left->right);
+ n1->q2.flags=KONST;
+ n1->q2.val.vint=zm2zi(sizetab[INT]);
+ n1->z.flags=VAR;
+ n1->z.v=new_temp(INT)->vbccvar;
+ n1->z.val.vmax=l2zm(0L);
+ n2=new_icode();
+ n2->code=ADDI2P;
+ n2->typf=INT;
+ n2->typf2=POINTER;
+ n2->q1=*gen_tree(left->left);
+ n2->q2=n1->z;
+ n2->z.flags=VAR;
+ n2->z.v=new_temp(POINTER)->vbccvar;
+ n2->z.val.vmax=l2zm(0L);
+ n3=new_icode();
+ n3->code=ASSIGN;
+ n3->typf=left->type->flags;
+ n3->q1=*gen_tree(right);
+ n3->z=n2->z;
+ n3->z.flags|=DREFOBJ;
+ n3->z.dtyp=POINTER;
+ n3->q2.val.vmax=szof(left->type);
+ add_icode(n1);
+ add_icode(n2);
+ add_icode(n3);
+#if 0
+ /* leicht anderes Format */
+ new->flags=CSTORE;
+ new->op1=*gen_tree(right);
+ new->op2=*gen_tree(left->left);
+ new->dest=*gen_tree(left->right);
+#endif
+ }else{
+ icode *new=new_icode();
+ new->code=ASSIGN;
+ new->q1=*gen_tree(right);
+ new->z=*gen_tree(left);
+ new->q2.val.vmax=szof(left->type);
+ new->typf=left->type->flags;
+ add_icode(new);
+ }
+ free_tree(left);
+ free_tree(right);
+}
+
+void return_statement(node *p)
+{
+ icode *new=new_icode();
+ p=conv_tree(p,INT); /*FIXME*/
+ simplify_tree(p);
+ new->code=SETRETURN;
+ new->typf=p->type->flags;
+ new->q1=*gen_tree(p);
+ new->z.reg=freturn(p->type);
+ add_icode(new);
+ free_tree(p);
+}
+
+void while_statement(node *p)
+{
+ int loop=++label,exit=++label;
+ simplify_tree(p);
+ gen_cond(p,loop,exit);
+ gen_label(loop);
+ last_ic->flags|=LOOP_COND_TRUE;
+ push_ptr(p);
+ push_int(loop);
+ push_int(exit);
+#if 0
+ gen_label(loop);
+ gen_cond(p,start,exit);
+ free_tree(p);
+ gen_label(start);
+ push_int(loop);
+ push_int(exit);
+#endif
+}
+
+void while_end()
+{
+ int loop,exit;
+ node *p;
+ exit=pop_int();
+ loop=pop_int();
+ p=pop_ptr();
+ gen_cond(p,loop,exit);
+ gen_label(exit);
+#if 0
+ new=new_icode();
+ new->code=BRA;
+ new->typf=loop;
+ add_icode(new);
+ gen_label(exit);
+#endif
+}
+
+void if_statement(node *p)
+{
+ int true=++label,false=++label;
+ simplify_tree(p);
+ gen_cond(p,true,false);
+ free_tree(p);
+ gen_label(true);
+ push_int(false);
+}
+
+void if_end()
+{
+ gen_label(pop_int());
+}
+
+void if_else()
+{
+ int endlabel=++label;
+ icode *new=new_icode();
+ new->code=BRA;
+ new->typf=++label;
+ add_icode(new);
+ gen_label(pop_int());
+ push_int(label);
+}
+
+int label;
+
+operand *gen_tree(node *p)
+{
+ icode *new;
+ static operand op;
+
+ if(p->flags==NVARIABLE){
+ if(p->var->type->flags==ARRAY){
+ if(p->var->nesting==0){
+ op.flags=VAR|VARADR;
+ op.v=p->var->vbccvar;
+ op.val.vmax=l2zm(0L);
+ return &op;
+ }else{
+ icode *new=new_icode();
+ new->flags=ADDRESS;
+ new->q1.flags=VAR;
+ new->q1.v=p->var->vbccvar;
+ new->q1.val.vmax=l2zm(0L);
+ new->z.flags=VAR;
+ new->z.v=new_temp(POINTER)->vbccvar;
+ new->z.val.vmax=l2zm(0L);
+ add_icode(new);
+ return &new->z;
+ }
+ }else{
+ op.flags=VAR;
+ op.v=p->var->vbccvar;
+ op.val.vmax=l2zm(0L);
+ return &op;
+ }
+ }
+
+ if(p->flags==NNUMBER){
+ op.flags=KONST;
+ if(p->type->flags==INT)
+ op.val.vint=p->ivalue;
+ else
+ op.val.vdouble=zld2zd(d2zld(p->rvalue));
+ return &op;
+ }
+
+ if(p->flags==NADD||p->flags==NMUL||p->flags==NSUB||p->flags==NDIV||p->flags==NI2R||p->flags==NR2I){
+ int ttyp=p->type->flags;
+ new=new_icode();
+ switch(p->flags){
+ case NADD: new->code=ADD;break;
+ case NMUL: new->code=MULT;break;
+ case NSUB: new->code=SUB;break;
+ case NDIV: new->code=DIV;break;
+ case NI2R: new->code=CONVERT;ttyp=REAL;new->typf2=INT;break;
+ case NR2I: new->code=CONVERT;ttyp=INT;new->typf2=REAL;break;
+ }
+ new->q1=*gen_tree(p->left);
+ if(p->right)
+ new->q2=*gen_tree(p->right);
+ new->z.flags=VAR;
+ new->z.v=new_temp(ttyp)->vbccvar;
+ new->z.val.vmax=l2zm(0L);
+ new->typf=ttyp;
+ add_icode(new);
+ return &new->z;
+ }
+
+ if(p->flags==NINDEX){
+ if(p->type->flags==ARRAY){
+ icode *merk,*new=new_icode();
+ new->flags=MULT;
+ new->typf=INT;
+ new->q1=*gen_tree(p->right);
+ new->q2.flags=KONST;
+ new->q2.val.vint=szof(p->type);
+ new->z.flags=VAR;
+ new->z.v=new_temp(INT)->vbccvar;
+ new->z.val.vmax=l2zm(0L);
+ add_icode(new);
+ merk=new;
+ new=new_icode();
+ new->flags=ADDI2P;
+ new->typf=INT;
+ new->typf2=POINTER;
+ new->q1=*gen_tree(p->left);
+ new->q2=merk->z;
+ new->z.flags=VAR;
+ new->z.v=new_temp(POINTER)->vbccvar;
+ new->z.val.vmax=l2zm(0L);
+ op=new->z;
+ add_icode(new);
+ return &new->z;
+ }else{
+ icode *merk,*new=new_icode();
+ new->code=MULT;
+ new->typf=INT;
+ new->q1=*gen_tree(p->right);
+ new->q2.flags=KONST;
+ new->q2.val.vint=zm2zi(sizetab[INT]);
+ new->z.flags=VAR;
+ new->z.v=new_temp(INT)->vbccvar;
+ new->z.val.vmax=l2zm(0L);
+ add_icode(new);
+ merk=new;
+ new=new_icode();
+ new->code=ADDI2P;
+ new->q1=*gen_tree(p->left);
+ new->q2=merk->z;
+ new->typf=INT;
+ new->typf2=POINTER;
+ new->z.flags=VAR;
+ new->z.v=new_temp(POINTER)->vbccvar;
+ new->z.val.vmax=l2zm(0L);
+ op=new->z;
+ op.flags|=DREFOBJ;
+ op.dtyp=POINTER;
+ add_icode(new);
+ return &op;
+ }
+ }
+
+ if(p->flags==NCALL){
+ icode *new=new_icode();
+ new->code=CALL;
+ new->typf=FUNKT;
+ if(p->right)
+ new->q2.val.vmax=l2zm(push_arg(p->right));
+ else
+ new->q2.val.vmax=l2zm(0L);
+ new->q1=*gen_tree(p->left);
+ add_icode(new);
+ new=new_icode();
+ new->code=GETRETURN;
+ new->z.flags=VAR;
+ new->typf=p->type->flags;
+ new->z.v=new_temp(p->type->flags)->vbccvar;
+ new->z.val.vmax=l2zm(0L);
+ new->q1.reg=freturn(p->type);
+ add_icode(new);
+ return &new->z;
+ }
+
+ error(13,"operation not yet supported");
+}
+
+void gen_label(int l)
+{
+ icode *new=new_icode();
+ new->code=LABEL;
+ new->typf=l;
+ add_icode(new);
+}
+
+void gen_cond(node *p,int true_label,int false_label)
+{
+ icode *new;
+ if(p->flags==NAND){
+ int tmp=++label;
+ gen_cond(p->left,tmp,false_label);
+ gen_label(tmp);
+ gen_cond(p->right,true_label,false_label);
+ return;
+ }
+ if(p->flags==NOR){
+ int tmp=++label;
+ gen_cond(p->left,true_label,tmp);
+ gen_label(tmp);
+ gen_cond(p->right,true_label,false_label);
+ return;
+ }
+ new=new_icode();
+ new->code=COMPARE;
+ new->typf=p->type->flags;
+ new->q1=*gen_tree(p->left);
+ new->q2=*gen_tree(p->right);
+ add_icode(new);
+ new=new_icode();
+ switch(p->flags){
+ case NEQUALS: new->code=BEQ;break;
+ case NNEQ: new->code=BNE;break;
+ case NLT: new->code=BLT;break;
+ case NGT: new->code=BGT;break;
+ case NLEQ: new->code=BLE;break;
+ case NGEQ: new->code=BGE;break;
+ default: error(14,"internal");
+ }
+ new->typf=true_label;
+ add_icode(new);
+
+ new=new_icode();
+ new->code=BRA;
+ new->typf=false_label;
+ add_icode(new);
+}
+
+int push_arg(node *p)
+{
+ if(p->flags==NARG){
+ int s;
+ s=push_arg(p->right);
+ return s+push_arg(p->left);
+ }else{
+ icode *new=new_icode();
+ if(p->type->flags==ARRAY)
+ error(15,"arrays cannot be passed");
+ new->code=PUSH;
+ new->q2.val.vmax=szof(p->type);
+ new->z.val.vmax=new->q2.val.vmax;
+ new->typf=p->type->flags;
+ new->q1=*gen_tree(p);
+ add_icode(new);
+ return szof(p->type);
+ }
+}
+
+void free_var(struct Var *v)
+{
+ free(v);
+ /*FIXME*/
+}
+
+void add_IC(icode *new)
+{
+ if(last_ic&&new->code==ASSIGN&&new->q1.flags==VAR&&last_ic->z.flags==VAR&&
+ new->q1.v==last_ic->z.v&&zmeqto(new->q1.val.vmax,last_ic->z.val.vmax)&&
+ *new->q1.v->identifier==0){
+ last_ic->z=new->z;
+ free(new);
+ return;
+ }
+ insert_IC(last_ic,new);
+}
diff --git a/minicomp.h b/minicomp.h
new file mode 100755
index 0000000..c47f0f7
--- /dev/null
+++ b/minicomp.h
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "supp.h"
+
+extern FILE *infile;
+#define MAXLEN 1024
+extern char tkname[MAXLEN];
+extern int label;
+extern int nesting;
+extern int local_offset,parm_offset,framesize;
+
+#define REAL DOUBLE
+#define FUNCTION FUNKT
+
+#define YYERROR_VERBOSE 1
+
+enum nodeflags {
+ NVARIABLE,NNUMBER,NADD,NMUL,NSUB,NDIV,NINDEX,
+ NEQUALS,NLT,NGT,NLEQ,NGEQ,NNEQ,NAND,NOR,
+ NI2R,NR2I,NASSGN,NCALL,NARG
+};
+
+extern char *nodename[];
+
+typedef struct Typ type;
+
+typedef struct obj operand;
+
+typedef struct var {
+ int nesting;
+ char *name;
+ struct Typ *type;
+ struct var *next;
+ int offset;
+ struct Var *vbccvar;
+} var;
+
+#define MAXNESTING 128
+extern var *first_var[128];
+
+typedef struct {
+ int flags;
+ char *name;
+} *stype;
+
+typedef struct mnode {
+ enum nodeflags flags;
+ struct mnode *left,*right;
+ type *type;
+ var *var;
+ int ivalue;
+ double rvalue;
+} node;
+
+void enter_block(void);
+void leave_block(void);
+void enter_func(char *,type *);
+void leave_func(void);
+var *find_var(char *,int);
+var *add_var(char *,type *);
+var *new_temp(int);
+char *add_string(char *);
+void error(int,...);
+void *getmem(size_t);
+node *number_node(void);
+node *var_node(void);
+node *conv_tree(node *,int);
+node *binary_node(enum nodeflags,node *,node *);
+void print_tree(node *);
+void simplify_tree(node *);
+void free_tree(node *);
+type *new_type(int);
+type *new_array(type *,node *);
+void return_statement(node *);
+void while_statement(node *);
+void while_end(void);
+void if_statement(node *);
+void if_end(void);
+void if_else(void);
+void assign_statement(node *,node *);
+void push_int(int);
+int pop_int(void);
+void push_name(char *);
+char *pop_name(void);
+operand *gen_tree(node *);
+void gen_cond(node *,int,int);
+void gen_label(int);
+int push_arg(node *);
+void gen_global(char *,int);
diff --git a/minicomp.tab.c b/minicomp.tab.c
new file mode 100755
index 0000000..f50de99
--- /dev/null
+++ b/minicomp.tab.c
@@ -0,0 +1,1189 @@
+
+/* A Bison parser, made from minicomp.y
+ by GNU Bison version 1.27
+ */
+
+#define YYBISON 1 /* Identify Bison output. */
+
+#define TKNUMBER 257
+#define TKIDENTIFIER 258
+#define TKREAL 259
+#define TKINT 260
+#define TKLEQ 261
+#define TKGEQ 262
+#define TKNEQ 263
+#define TKIF 264
+#define TKELSE 265
+#define TKWHILE 266
+#define TKRETURN 267
+#define TKASSIGN 268
+#define TKAND 269
+#define TKOR 270
+
+#line 18 "minicomp.y"
+
+#include "minicomp.h"
+
+typedef void *voidptr;
+#define YYSTYPE voidptr
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define YYFINAL 123
+#define YYFLAG -32768
+#define YYNTBASE 32
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 270 ? yytranslate[x] : 64)
+
+static const char yytranslate[] = { 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 23,
+ 24, 27, 25, 29, 26, 2, 28, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 19, 21,
+ 20, 22, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 17, 2, 18, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 30, 2, 31, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = { 0,
+ 0, 3, 5, 7, 9, 11, 13, 18, 21, 23,
+ 27, 29, 33, 37, 39, 43, 47, 51, 55, 59,
+ 63, 67, 71, 75, 77, 81, 85, 87, 91, 93,
+ 98, 102, 104, 109, 111, 113, 117, 119, 122, 124,
+ 126, 128, 130, 132, 134, 135, 139, 143, 146, 149,
+ 151, 152, 160, 161, 162, 166, 167, 174, 179, 183,
+ 186, 190, 194, 197, 201, 203
+};
+
+static const short yyrhs[] = { 32,
+ 33, 0, 33, 0, 59, 0, 36, 0, 5, 0,
+ 6, 0, 34, 17, 40, 18, 0, 35, 36, 0,
+ 36, 0, 34, 37, 19, 0, 4, 0, 38, 15,
+ 39, 0, 38, 16, 39, 0, 39, 0, 40, 20,
+ 40, 0, 40, 9, 40, 0, 40, 21, 40, 0,
+ 40, 22, 40, 0, 40, 7, 40, 0, 40, 8,
+ 40, 0, 23, 38, 24, 0, 40, 25, 41, 0,
+ 40, 26, 41, 0, 41, 0, 41, 27, 42, 0,
+ 41, 28, 42, 0, 42, 0, 23, 40, 24, 0,
+ 3, 0, 44, 23, 45, 24, 0, 44, 23, 24,
+ 0, 43, 0, 42, 17, 40, 18, 0, 44, 0,
+ 4, 0, 45, 29, 40, 0, 40, 0, 46, 47,
+ 0, 47, 0, 51, 0, 55, 0, 57, 0, 58,
+ 0, 48, 0, 0, 30, 49, 50, 0, 35, 46,
+ 31, 0, 46, 31, 0, 35, 31, 0, 31, 0,
+ 0, 10, 23, 38, 24, 52, 48, 53, 0, 0,
+ 0, 11, 54, 48, 0, 0, 12, 23, 38, 24,
+ 56, 48, 0, 43, 14, 40, 19, 0, 13, 40,
+ 19, 0, 60, 61, 0, 34, 37, 23, 0, 62,
+ 24, 48, 0, 24, 48, 0, 62, 29, 63, 0,
+ 63, 0, 34, 37, 0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+ 27, 29, 32, 34, 37, 39, 40, 43, 45, 48,
+ 52, 56, 58, 59, 62, 64, 65, 66, 67, 68,
+ 69, 72, 73, 74, 77, 78, 79, 82, 84, 85,
+ 86, 87, 90, 92, 95, 99, 101, 104, 106, 109,
+ 111, 112, 113, 114, 117, 119, 121, 123, 124, 125,
+ 129, 130, 133, 135, 135, 139, 140, 143, 147, 151,
+ 155, 159, 161, 164, 166, 169
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = { "$","error","$undefined.","TKNUMBER",
+"TKIDENTIFIER","TKREAL","TKINT","TKLEQ","TKGEQ","TKNEQ","TKIF","TKELSE","TKWHILE",
+"TKRETURN","TKASSIGN","TKAND","TKOR","'['","']'","';'","'='","'<'","'>'","'('",
+"')'","'+'","'-'","'*'","'/'","','","'{'","'}'","glob_decl_list","glob_decl",
+"type","decl_list","decl","decl_id","cond_expr","ao_expr","arith_expr","term",
+"factor","lvalue","variable","arg_list","stmt_list","stmt","block","@1","block_end",
+"if_stmt","@2","else_part","@3","while_stmt","@4","assgn_stmt","return_stmt",
+"func_decl","func_decl_begin","func_decl_end","par_list","par_decl", NULL
+};
+#endif
+
+static const short yyr1[] = { 0,
+ 32, 32, 33, 33, 34, 34, 34, 35, 35, 36,
+ 37, 38, 38, 38, 39, 39, 39, 39, 39, 39,
+ 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
+ 42, 42, 43, 43, 44, 45, 45, 46, 46, 47,
+ 47, 47, 47, 47, 49, 48, 50, 50, 50, 50,
+ 52, 51, 53, 54, 53, 56, 55, 57, 58, 59,
+ 60, 61, 61, 62, 62, 63
+};
+
+static const short yyr2[] = { 0,
+ 2, 1, 1, 1, 1, 1, 4, 2, 1, 3,
+ 1, 3, 3, 1, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 1, 3, 3, 1, 3, 1, 4,
+ 3, 1, 4, 1, 1, 3, 1, 2, 1, 1,
+ 1, 1, 1, 1, 0, 3, 3, 2, 2, 1,
+ 0, 7, 0, 0, 3, 0, 6, 4, 3, 2,
+ 3, 3, 2, 3, 1, 2
+};
+
+static const short yydefact[] = { 0,
+ 5, 6, 0, 2, 0, 4, 3, 0, 1, 11,
+ 0, 0, 0, 0, 60, 0, 65, 29, 35, 0,
+ 0, 24, 27, 32, 34, 10, 61, 45, 63, 66,
+ 0, 0, 0, 7, 0, 0, 0, 0, 0, 0,
+ 0, 62, 64, 28, 22, 23, 25, 26, 0, 31,
+ 37, 0, 0, 0, 0, 50, 0, 0, 9, 0,
+ 32, 0, 39, 44, 46, 40, 41, 42, 43, 33,
+ 30, 0, 0, 0, 0, 0, 49, 8, 0, 0,
+ 48, 38, 36, 0, 0, 14, 0, 0, 59, 47,
+ 0, 0, 0, 0, 0, 51, 0, 0, 0, 0,
+ 0, 0, 56, 58, 21, 12, 13, 0, 19, 20,
+ 16, 15, 17, 18, 0, 53, 57, 54, 52, 0,
+ 55, 0, 0
+};
+
+static const short yydefgoto[] = { 3,
+ 4, 5, 58, 6, 12, 85, 86, 87, 22, 23,
+ 24, 25, 52, 62, 63, 64, 41, 65, 66, 108,
+ 119, 120, 67, 115, 68, 69, 7, 8, 15, 16,
+ 17
+};
+
+static const short yypact[] = { 33,
+-32768,-32768, 148,-32768, 27,-32768,-32768, 0,-32768,-32768,
+ 50, 75, -21, 27,-32768, 128,-32768,-32768,-32768, 50,
+ 25, 102, -5,-32768, 32,-32768,-32768,-32768,-32768,-32768,
+ -21, 33, 137,-32768, 50, 50, 50, 50, 50, 44,
+ 10,-32768,-32768,-32768, 102, 102, -5, -5, 46,-32768,
+ 133, 131, 78, 81, 50,-32768, 27, 53,-32768, -5,
+ 55, 93,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768, 50, 57, 57, 56, 60,-32768,-32768, 105, 50,
+-32768,-32768, 133, 57, 62,-32768, 125, 95,-32768,-32768,
+ 74, 97, 118, 57, 57,-32768, 50, 50, 50, 50,
+ 50, 50,-32768,-32768,-32768,-32768,-32768, -21, 133, 133,
+ 133, 133, 133, 133, -21, 103,-32768,-32768,-32768, -21,
+-32768, 85,-32768
+};
+
+static const short yypgoto[] = {-32768,
+ 117, -6,-32768, -24, -11, -47, 70, -10, 132, -30,
+ -37,-32768,-32768, 64, -43, -13,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+ 99
+};
+
+
+#define YYLAST 168
+
+
+static const short yytable[] = { 29,
+ 21, 14, 30, 61, 1, 2, 47, 48, 28, 33,
+ 60, 39, 18, 19, 1, 2, 59, 42, 82, 53,
+ 61, 54, 55, 13, 61, 14, 88, 60, 49, 51,
+ 10, 60, 20, 78, 57, 82, 92, 1, 2, 28,
+ 56, 61, 34, 11, 75, 76, 18, 19, 60, 35,
+ 36, 57, 18, 19, 40, 18, 19, 1, 2, 18,
+ 19, 83, 53, 70, 54, 55, 20, 50, 80, 91,
+ 35, 36, 20, 93, 89, 20, 94, 95, 26, 84,
+ 35, 36, 28, 77, 123, 96, 109, 110, 111, 112,
+ 113, 114, 104, 26, 116, 18, 19, 27, 35, 36,
+ 73, 117, 53, 74, 54, 55, 121, 18, 19, 94,
+ 95, 94, 95, 118, 53, 20, 54, 55, 103, 9,
+ 105, 79, 28, 81, 97, 98, 99, 20, 37, 38,
+ 43, 97, 98, 99, 28, 90, 0, 100, 101, 102,
+ 0, 44, 35, 36, 100, 101, 102, 122, 0, 35,
+ 36, 31, 1, 2, 71, 0, 32, 35, 36, 72,
+ 44, 35, 36, 106, 107, 0, 45, 46
+};
+
+static const short yycheck[] = { 13,
+ 11, 8, 14, 41, 5, 6, 37, 38, 30, 20,
+ 41, 17, 3, 4, 5, 6, 41, 31, 62, 10,
+ 58, 12, 13, 24, 62, 32, 74, 58, 39, 40,
+ 4, 62, 23, 58, 41, 79, 84, 5, 6, 30,
+ 31, 79, 18, 17, 55, 57, 3, 4, 79, 25,
+ 26, 58, 3, 4, 23, 3, 4, 5, 6, 3,
+ 4, 72, 10, 18, 12, 13, 23, 24, 14, 80,
+ 25, 26, 23, 84, 19, 23, 15, 16, 19, 23,
+ 25, 26, 30, 31, 0, 24, 97, 98, 99, 100,
+ 101, 102, 19, 19, 108, 3, 4, 23, 25, 26,
+ 23, 115, 10, 23, 12, 13, 120, 3, 4, 15,
+ 16, 15, 16, 11, 10, 23, 12, 13, 24, 3,
+ 24, 58, 30, 31, 7, 8, 9, 23, 27, 28,
+ 32, 7, 8, 9, 30, 31, -1, 20, 21, 22,
+ -1, 24, 25, 26, 20, 21, 22, 0, -1, 25,
+ 26, 24, 5, 6, 24, -1, 29, 25, 26, 29,
+ 24, 25, 26, 94, 95, -1, 35, 36
+};
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+#line 3 "/usr/share/bison.simple"
+/* This file comes from bison-1.27. */
+
+/* Skeleton output parser for bison,
+ Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* This is the parser code that is written into each bison parser
+ when the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+#ifndef YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C. */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C. */
+/* This used to test MSDOS, but that is a bad idea
+ since that symbol is in the user namespace. */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+ instead, just don't use alloca. */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+ So I turned it off. rms, 2 May 1997. */
+/* #include <malloc.h> */
+ #pragma alloca
+#define YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
+ and on HPUX 10. Eventually we can turn this on. */
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#ifdef YYSTACK_USE_ALLOCA
+#define YYSTACK_ALLOC alloca
+#else
+#define YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+ It is replaced by the list of actions, each action
+ as one case of the switch. */
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+ This remains here temporarily to ease the
+ transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define YYFAIL goto yyerrlab
+#define YYRECOVERING() (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { yychar = (token), yylval = (value); \
+ yychar1 = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { yyerror ("syntax error: cannot back up"); YYERROR; } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+#ifndef YYPURE
+#define YYLEX yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int yychar; /* the lookahead symbol */
+YYSTYPE yylval; /* the semantic value of the */
+ /* lookahead symbol */
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc; /* location data for the lookahead */
+ /* symbol */
+#endif
+
+int yynerrs; /* number of parse errors so far */
+#endif /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug; /* nonzero means print parse trace */
+/* Since this is uninitialized, it does not stop multiple parsers
+ from coexisting. */
+#endif
+
+/* YYINITDEPTH indicates the initial size of the parser's stacks */
+
+#ifndef YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH is the maximum size the stacks can grow to
+ (effective only if the built-in stack extension method is used). */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Define __yy_memcpy. Note that the size argument
+ should be passed with type unsigned int, because that is what the non-GCC
+ definitions require. With GCC, __builtin_memcpy takes an arg
+ of type size_t, but it can handle unsigned int. */
+
+#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
+#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
+#else /* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (to, from, count)
+ char *to;
+ char *from;
+ unsigned int count;
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (char *to, char *from, unsigned int count)
+{
+ register char *t = to;
+ register char *f = from;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#endif
+#endif
+
+#line 216 "/usr/share/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+ into yyparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+#ifdef YYPARSE_PARAM
+int yyparse (void *);
+#else
+int yyparse (void);
+#endif
+#endif
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+ YYPARSE_PARAM_DECL
+{
+ register int yystate;
+ register int yyn;
+ register short *yyssp;
+ register YYSTYPE *yyvsp;
+ int yyerrstatus; /* number of tokens to shift before error messages enabled */
+ int yychar1 = 0; /* lookahead token as an internal (translated) token number */
+
+ short yyssa[YYINITDEPTH]; /* the state stack */
+ YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
+
+ short *yyss = yyssa; /* refer to the stacks thru separate pointers */
+ YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp;
+
+#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK (yyvsp--, yyssp--)
+#endif
+
+ int yystacksize = YYINITDEPTH;
+ int yyfree_stacks = 0;
+
+#ifdef YYPURE
+ int yychar;
+ YYSTYPE yylval;
+ int yynerrs;
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylloc;
+#endif
+#endif
+
+ YYSTYPE yyval; /* the variable used to return */
+ /* semantic values from the action */
+ /* routines */
+
+ int yylen;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Starting parse\n");
+#endif
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss - 1;
+ yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in yystate . */
+/* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks. */
+yynewstate:
+
+ *++yyssp = yystate;
+
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ /* Give user a chance to reallocate the stack */
+ /* Use copies of these so that the &'s don't force the real ones into memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+ YYLTYPE *yyls1 = yyls;
+#endif
+
+ /* Get the current used size of the three stacks, in elements. */
+ int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ /* Each stack pointer address is followed by the size of
+ the data in use in that stack, in bytes. */
+#ifdef YYLSP_NEEDED
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if yyoverflow is a macro. */
+
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yyls1, size * sizeof (*yylsp),
+ &yystacksize);
+#else
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yystacksize);
+#endif
+
+ yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+ yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+ /* Extend the stack our own way. */
+ if (yystacksize >= YYMAXDEPTH)
+ {
+ yyerror("parser stack overflow");
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 2;
+ }
+ yystacksize *= 2;
+ if (yystacksize > YYMAXDEPTH)
+ yystacksize = YYMAXDEPTH;
+#ifndef YYSTACK_USE_ALLOCA
+ yyfree_stacks = 1;
+#endif
+ yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+ __yy_memcpy ((char *)yyss, (char *)yyss1,
+ size * (unsigned int) sizeof (*yyssp));
+ yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+ __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+ size * (unsigned int) sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+ yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+ __yy_memcpy ((char *)yyls, (char *)yyls1,
+ size * (unsigned int) sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + size - 1;
+ yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+ if (yyssp >= yyss + yystacksize - 1)
+ YYABORT;
+ }
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+ goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* yychar is either YYEMPTY or YYEOF
+ or a valid token in external form. */
+
+ if (yychar == YYEMPTY)
+ {
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Reading a token: ");
+#endif
+ yychar = YYLEX;
+ }
+
+ /* Convert token to internal form (in yychar1) for indexing tables with */
+
+ if (yychar <= 0) /* This means end of input. */
+ {
+ yychar1 = 0;
+ yychar = YYEOF; /* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Now at end of input.\n");
+#endif
+ }
+ else
+ {
+ yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+ /* Give the individual parser a way to print the precise meaning
+ of a token, for further debugging info. */
+#ifdef YYPRINT
+ YYPRINT (stderr, yychar, yylval);
+#endif
+ fprintf (stderr, ")\n");
+ }
+#endif
+ }
+
+ yyn += yychar1;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ goto yydefault;
+
+ yyn = yytable[yyn];
+
+ /* yyn is what to do for this token type in this state.
+ Negative => reduce, -yyn is rule number.
+ Positive => shift, yyn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrlab;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ /* count tokens shifted since error; after three, turn off error status. */
+ if (yyerrstatus) yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+/* Do the default action for the current state. */
+yydefault:
+
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+
+/* Do a reduction. yyn is the number of a rule to reduce with. */
+yyreduce:
+ yylen = yyr2[yyn];
+ if (yylen > 0)
+ yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ int i;
+
+ fprintf (stderr, "Reducing via rule %d (line %d), ",
+ yyn, yyrline[yyn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+ fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+ fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+ }
+#endif
+
+
+ switch (yyn) {
+
+case 5:
+#line 38 "minicomp.y"
+{yyval=new_type(DOUBLE);;
+ break;}
+case 6:
+#line 39 "minicomp.y"
+{yyval=new_type(INT);;
+ break;}
+case 7:
+#line 40 "minicomp.y"
+{yyval=new_array(yyvsp[-3],yyvsp[-1]);;
+ break;}
+case 10:
+#line 49 "minicomp.y"
+{add_var(yyvsp[-1],yyvsp[-2]);;
+ break;}
+case 11:
+#line 53 "minicomp.y"
+{yyval=add_string(tkname);;
+ break;}
+case 12:
+#line 57 "minicomp.y"
+{yyval=binary_node(NAND,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 13:
+#line 58 "minicomp.y"
+{yyval=binary_node(NOR,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 15:
+#line 63 "minicomp.y"
+{yyval=binary_node(NEQUALS,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 16:
+#line 64 "minicomp.y"
+{yyval=binary_node(NNEQ,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 17:
+#line 65 "minicomp.y"
+{yyval=binary_node(NLT,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 18:
+#line 66 "minicomp.y"
+{yyval=binary_node(NGT,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 19:
+#line 67 "minicomp.y"
+{yyval=binary_node(NLEQ,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 20:
+#line 68 "minicomp.y"
+{yyval=binary_node(NGEQ,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 21:
+#line 69 "minicomp.y"
+{yyval=yyvsp[-1];
+ break;}
+case 22:
+#line 72 "minicomp.y"
+{yyval=binary_node(NADD,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 23:
+#line 73 "minicomp.y"
+{yyval=binary_node(NSUB,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 25:
+#line 77 "minicomp.y"
+{yyval=binary_node(NMUL,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 26:
+#line 78 "minicomp.y"
+{yyval=binary_node(NDIV,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 28:
+#line 83 "minicomp.y"
+{yyval=yyvsp[-1];;
+ break;}
+case 29:
+#line 84 "minicomp.y"
+{yyval=number_node();;
+ break;}
+case 30:
+#line 85 "minicomp.y"
+{yyval=binary_node(NCALL,yyvsp[-3],yyvsp[-1]);;
+ break;}
+case 31:
+#line 86 "minicomp.y"
+{yyval=binary_node(NCALL,yyvsp[-2],0);;
+ break;}
+case 33:
+#line 91 "minicomp.y"
+{yyval=binary_node(NINDEX,yyvsp[-3],yyvsp[-1]);;
+ break;}
+case 35:
+#line 96 "minicomp.y"
+{yyval=var_node();;
+ break;}
+case 36:
+#line 100 "minicomp.y"
+{yyval=binary_node(NARG,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 45:
+#line 118 "minicomp.y"
+{enter_block();;
+ break;}
+case 47:
+#line 122 "minicomp.y"
+{leave_block();;
+ break;}
+case 48:
+#line 123 "minicomp.y"
+{leave_block();;
+ break;}
+case 49:
+#line 124 "minicomp.y"
+{leave_block();;
+ break;}
+case 50:
+#line 125 "minicomp.y"
+{leave_block();;
+ break;}
+case 51:
+#line 130 "minicomp.y"
+{if_statement(yyvsp[-1]);;
+ break;}
+case 53:
+#line 134 "minicomp.y"
+{if_end();;
+ break;}
+case 54:
+#line 135 "minicomp.y"
+{if_else();;
+ break;}
+case 55:
+#line 135 "minicomp.y"
+{if_end();;
+ break;}
+case 56:
+#line 140 "minicomp.y"
+{while_statement(yyvsp[-1]);;
+ break;}
+case 57:
+#line 140 "minicomp.y"
+{while_end();;
+ break;}
+case 58:
+#line 144 "minicomp.y"
+{assign_statement(yyvsp[-3],yyvsp[-1]);;
+ break;}
+case 59:
+#line 148 "minicomp.y"
+{return_statement(yyvsp[-1]);;
+ break;}
+case 61:
+#line 156 "minicomp.y"
+{enter_func(yyvsp[-1],yyvsp[-2]);;
+ break;}
+case 62:
+#line 160 "minicomp.y"
+{leave_func();;
+ break;}
+case 63:
+#line 161 "minicomp.y"
+{leave_func();;
+ break;}
+case 66:
+#line 170 "minicomp.y"
+{add_var(yyvsp[0],yyvsp[-1]);;
+ break;}
+}
+ /* the action file gets copied in in place of this dollarsign */
+#line 542 "/usr/share/bison.simple"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+ yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "state stack now");
+ while (ssp1 != yyssp)
+
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+ yylsp++;
+ if (yylen == 0)
+ {
+ yylsp->first_line = yylloc.first_line;
+ yylsp->first_column = yylloc.first_column;
+ yylsp->last_line = (yylsp-1)->last_line;
+ yylsp->last_column = (yylsp-1)->last_column;
+ yylsp->text = 0;
+ }
+ else
+ {
+ yylsp->last_line = (yylsp+yylen-1)->last_line;
+ yylsp->last_column = (yylsp+yylen-1)->last_column;
+ }
+#endif
+
+ /* Now "shift" the result of the reduction.
+ Determine what state that goes to,
+ based on the state we popped back to
+ and the rule number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+ if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTBASE];
+
+ goto yynewstate;
+
+yyerrlab: /* here on detecting error */
+
+ if (! yyerrstatus)
+ /* If not already recovering from an error, report this error. */
+ {
+ ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (yyn > YYFLAG && yyn < YYLAST)
+ {
+ int size = 0;
+ char *msg;
+ int x, count;
+
+ count = 0;
+ /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ size += strlen(yytname[x]) + 15, count++;
+ msg = (char *) malloc(size + 15);
+ if (msg != 0)
+ {
+ strcpy(msg, "parse error");
+
+ if (count < 5)
+ {
+ count = 0;
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ {
+ strcat(msg, count == 0 ? ", expecting `" : " or `");
+ strcat(msg, yytname[x]);
+ strcat(msg, "'");
+ count++;
+ }
+ }
+ yyerror(msg);
+ free(msg);
+ }
+ else
+ yyerror ("parse error; also virtual memory exceeded");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror("parse error");
+ }
+
+ goto yyerrlab1;
+yyerrlab1: /* here on error raised explicitly by an action */
+
+ if (yyerrstatus == 3)
+ {
+ /* if just tried and failed to reuse lookahead token after an error, discard it. */
+
+ /* return failure if at end of input */
+ if (yychar == YYEOF)
+ YYABORT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+ yychar = YYEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token
+ after shifting the error token. */
+
+ yyerrstatus = 3; /* Each real token shifted decrements this */
+
+ goto yyerrhandle;
+
+yyerrdefault: /* current state does not do anything special for the error token. */
+
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+ yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
+ if (yyn) goto yydefault;
+#endif
+
+yyerrpop: /* pop the current state because it cannot handle the error token */
+
+ if (yyssp == yyss) YYABORT;
+ yyvsp--;
+ yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+ yylsp--;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "Error: state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+yyerrhandle:
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yyerrdefault;
+
+ yyn += YYTERROR;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+ goto yyerrdefault;
+
+ yyn = yytable[yyn];
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrpop;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrpop;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting error token, ");
+#endif
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ yystate = yyn;
+ goto yynewstate;
+
+ yyacceptlab:
+ /* YYACCEPT comes here. */
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 0;
+
+ yyabortlab:
+ /* YYABORT comes here. */
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 1;
+}
+#line 173 "minicomp.y"
+
+
+#include "minicomplexer.c"
+
diff --git a/minicompg.tab.c b/minicompg.tab.c
new file mode 100755
index 0000000..b27bae0
--- /dev/null
+++ b/minicompg.tab.c
@@ -0,0 +1,1187 @@
+
+/* A Bison parser, made from minicompg.y
+ by GNU Bison version 1.27
+ */
+
+#define YYBISON 1 /* Identify Bison output. */
+
+#define TKNUMBER 257
+#define TKIDENTIFIER 258
+#define TKREAL 259
+#define TKINT 260
+#define TKLEQ 261
+#define TKGEQ 262
+#define TKNEQ 263
+#define TKIF 264
+#define TKELSE 265
+#define TKWHILE 266
+#define TKRETURN 267
+#define TKASSIGN 268
+#define TKAND 269
+#define TKOR 270
+
+#line 18 "minicompg.y"
+
+#include "minicomp.h"
+
+typedef void *voidptr;
+#define YYSTYPE voidptr
+#ifndef YYSTYPE
+#define YYSTYPE int
+#endif
+#include <stdio.h>
+
+#ifndef __cplusplus
+#ifndef __STDC__
+#define const
+#endif
+#endif
+
+
+
+#define YYFINAL 123
+#define YYFLAG -32768
+#define YYNTBASE 32
+
+#define YYTRANSLATE(x) ((unsigned)(x) <= 270 ? yytranslate[x] : 64)
+
+static const char yytranslate[] = { 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 23,
+ 24, 27, 25, 29, 26, 2, 28, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 19, 21,
+ 20, 22, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 17, 2, 18, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 30, 2, 31, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
+};
+
+#if YYDEBUG != 0
+static const short yyprhs[] = { 0,
+ 0, 3, 5, 7, 9, 11, 13, 18, 21, 23,
+ 27, 29, 33, 37, 39, 43, 47, 51, 55, 59,
+ 63, 67, 71, 75, 77, 81, 85, 87, 91, 93,
+ 98, 102, 104, 109, 111, 113, 117, 119, 122, 124,
+ 126, 128, 130, 132, 134, 135, 139, 143, 146, 149,
+ 151, 152, 160, 161, 162, 166, 167, 174, 179, 183,
+ 186, 190, 194, 197, 201, 203
+};
+
+static const short yyrhs[] = { 32,
+ 33, 0, 33, 0, 59, 0, 36, 0, 5, 0,
+ 6, 0, 34, 17, 40, 18, 0, 35, 36, 0,
+ 36, 0, 34, 37, 19, 0, 4, 0, 38, 15,
+ 39, 0, 38, 16, 39, 0, 39, 0, 40, 20,
+ 40, 0, 40, 9, 40, 0, 40, 21, 40, 0,
+ 40, 22, 40, 0, 40, 7, 40, 0, 40, 8,
+ 40, 0, 23, 38, 24, 0, 40, 25, 41, 0,
+ 40, 26, 41, 0, 41, 0, 41, 27, 42, 0,
+ 41, 28, 42, 0, 42, 0, 23, 40, 24, 0,
+ 3, 0, 44, 23, 45, 24, 0, 44, 23, 24,
+ 0, 43, 0, 42, 17, 40, 18, 0, 44, 0,
+ 4, 0, 45, 29, 40, 0, 40, 0, 46, 47,
+ 0, 47, 0, 51, 0, 55, 0, 57, 0, 58,
+ 0, 48, 0, 0, 30, 49, 50, 0, 35, 46,
+ 31, 0, 46, 31, 0, 35, 31, 0, 31, 0,
+ 0, 10, 23, 38, 24, 52, 48, 53, 0, 0,
+ 0, 11, 54, 48, 0, 0, 12, 23, 38, 24,
+ 56, 48, 0, 43, 14, 40, 19, 0, 13, 40,
+ 19, 0, 60, 61, 0, 34, 37, 23, 0, 62,
+ 24, 48, 0, 24, 48, 0, 62, 29, 63, 0,
+ 63, 0, 34, 37, 0
+};
+
+#endif
+
+#if YYDEBUG != 0
+static const short yyrline[] = { 0,
+ 27, 29, 32, 34, 37, 39, 40, 43, 45, 48,
+ 52, 56, 58, 59, 62, 64, 65, 66, 67, 68,
+ 69, 72, 73, 74, 77, 78, 79, 82, 84, 85,
+ 86, 87, 90, 92, 95, 99, 101, 104, 106, 109,
+ 111, 112, 113, 114, 117, 119, 121, 123, 124, 125,
+ 129, 130, 133, 135, 135, 139, 140, 143, 147, 151,
+ 155, 159, 161, 164, 166, 169
+};
+#endif
+
+
+#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)
+
+static const char * const yytname[] = { "$","error","$undefined.","TKNUMBER",
+"TKIDENTIFIER","TKREAL","TKINT","TKLEQ","TKGEQ","TKNEQ","TKIF","TKELSE","TKWHILE",
+"TKRETURN","TKASSIGN","TKAND","TKOR","'['","']'","';'","'='","'<'","'>'","'('",
+"')'","'+'","'-'","'*'","'/'","','","'{'","'}'","glob_decl_list","glob_decl",
+"type","decl_list","decl","decl_id","cond_expr","ao_expr","arith_expr","term",
+"factor","lvalue","variable","arg_list","stmt_list","stmt","block","@1","block_end",
+"if_stmt","@2","else_part","@3","while_stmt","@4","assgn_stmt","return_stmt",
+"func_decl","func_decl_begin","func_decl_end","par_list","par_decl", NULL
+};
+#endif
+
+static const short yyr1[] = { 0,
+ 32, 32, 33, 33, 34, 34, 34, 35, 35, 36,
+ 37, 38, 38, 38, 39, 39, 39, 39, 39, 39,
+ 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
+ 42, 42, 43, 43, 44, 45, 45, 46, 46, 47,
+ 47, 47, 47, 47, 49, 48, 50, 50, 50, 50,
+ 52, 51, 53, 54, 53, 56, 55, 57, 58, 59,
+ 60, 61, 61, 62, 62, 63
+};
+
+static const short yyr2[] = { 0,
+ 2, 1, 1, 1, 1, 1, 4, 2, 1, 3,
+ 1, 3, 3, 1, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 1, 3, 3, 1, 3, 1, 4,
+ 3, 1, 4, 1, 1, 3, 1, 2, 1, 1,
+ 1, 1, 1, 1, 0, 3, 3, 2, 2, 1,
+ 0, 7, 0, 0, 3, 0, 6, 4, 3, 2,
+ 3, 3, 2, 3, 1, 2
+};
+
+static const short yydefact[] = { 0,
+ 5, 6, 0, 2, 0, 4, 3, 0, 1, 11,
+ 0, 0, 0, 0, 60, 0, 65, 29, 35, 0,
+ 0, 24, 27, 32, 34, 10, 61, 45, 63, 66,
+ 0, 0, 0, 7, 0, 0, 0, 0, 0, 0,
+ 0, 62, 64, 28, 22, 23, 25, 26, 0, 31,
+ 37, 0, 0, 0, 0, 50, 0, 0, 9, 0,
+ 32, 0, 39, 44, 46, 40, 41, 42, 43, 33,
+ 30, 0, 0, 0, 0, 0, 49, 8, 0, 0,
+ 48, 38, 36, 0, 0, 14, 0, 0, 59, 47,
+ 0, 0, 0, 0, 0, 51, 0, 0, 0, 0,
+ 0, 0, 56, 58, 21, 12, 13, 0, 19, 20,
+ 16, 15, 17, 18, 0, 53, 57, 54, 52, 0,
+ 55, 0, 0
+};
+
+static const short yydefgoto[] = { 3,
+ 4, 5, 58, 6, 12, 85, 86, 87, 22, 23,
+ 24, 25, 52, 62, 63, 64, 41, 65, 66, 108,
+ 119, 120, 67, 115, 68, 69, 7, 8, 15, 16,
+ 17
+};
+
+static const short yypact[] = { 33,
+-32768,-32768, 148,-32768, 27,-32768,-32768, 0,-32768,-32768,
+ 50, 75, -21, 27,-32768, 128,-32768,-32768,-32768, 50,
+ 25, 102, -5,-32768, 32,-32768,-32768,-32768,-32768,-32768,
+ -21, 33, 137,-32768, 50, 50, 50, 50, 50, 44,
+ 10,-32768,-32768,-32768, 102, 102, -5, -5, 46,-32768,
+ 133, 131, 78, 81, 50,-32768, 27, 53,-32768, -5,
+ 55, 93,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+-32768, 50, 57, 57, 56, 60,-32768,-32768, 105, 50,
+-32768,-32768, 133, 57, 62,-32768, 125, 95,-32768,-32768,
+ 74, 97, 118, 57, 57,-32768, 50, 50, 50, 50,
+ 50, 50,-32768,-32768,-32768,-32768,-32768, -21, 133, 133,
+ 133, 133, 133, 133, -21, 103,-32768,-32768,-32768, -21,
+-32768, 85,-32768
+};
+
+static const short yypgoto[] = {-32768,
+ 117, -6,-32768, -24, -11, -47, 70, -10, 132, -30,
+ -37,-32768,-32768, 64, -43, -13,-32768,-32768,-32768,-32768,
+-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
+ 99
+};
+
+
+#define YYLAST 168
+
+
+static const short yytable[] = { 29,
+ 21, 14, 30, 61, 1, 2, 47, 48, 28, 33,
+ 60, 39, 18, 19, 1, 2, 59, 42, 82, 53,
+ 61, 54, 55, 13, 61, 14, 88, 60, 49, 51,
+ 10, 60, 20, 78, 57, 82, 92, 1, 2, 28,
+ 56, 61, 34, 11, 75, 76, 18, 19, 60, 35,
+ 36, 57, 18, 19, 40, 18, 19, 1, 2, 18,
+ 19, 83, 53, 70, 54, 55, 20, 50, 80, 91,
+ 35, 36, 20, 93, 89, 20, 94, 95, 26, 84,
+ 35, 36, 28, 77, 123, 96, 109, 110, 111, 112,
+ 113, 114, 104, 26, 116, 18, 19, 27, 35, 36,
+ 73, 117, 53, 74, 54, 55, 121, 18, 19, 94,
+ 95, 94, 95, 118, 53, 20, 54, 55, 103, 9,
+ 105, 79, 28, 81, 97, 98, 99, 20, 37, 38,
+ 43, 97, 98, 99, 28, 90, 0, 100, 101, 102,
+ 0, 44, 35, 36, 100, 101, 102, 122, 0, 35,
+ 36, 31, 1, 2, 71, 0, 32, 35, 36, 72,
+ 44, 35, 36, 106, 107, 0, 45, 46
+};
+
+static const short yycheck[] = { 13,
+ 11, 8, 14, 41, 5, 6, 37, 38, 30, 20,
+ 41, 17, 3, 4, 5, 6, 41, 31, 62, 10,
+ 58, 12, 13, 24, 62, 32, 74, 58, 39, 40,
+ 4, 62, 23, 58, 41, 79, 84, 5, 6, 30,
+ 31, 79, 18, 17, 55, 57, 3, 4, 79, 25,
+ 26, 58, 3, 4, 23, 3, 4, 5, 6, 3,
+ 4, 72, 10, 18, 12, 13, 23, 24, 14, 80,
+ 25, 26, 23, 84, 19, 23, 15, 16, 19, 23,
+ 25, 26, 30, 31, 0, 24, 97, 98, 99, 100,
+ 101, 102, 19, 19, 108, 3, 4, 23, 25, 26,
+ 23, 115, 10, 23, 12, 13, 120, 3, 4, 15,
+ 16, 15, 16, 11, 10, 23, 12, 13, 24, 3,
+ 24, 58, 30, 31, 7, 8, 9, 23, 27, 28,
+ 32, 7, 8, 9, 30, 31, -1, 20, 21, 22,
+ -1, 24, 25, 26, 20, 21, 22, 0, -1, 25,
+ 26, 24, 5, 6, 24, -1, 29, 25, 26, 29,
+ 24, 25, 26, 94, 95, -1, 35, 36
+};
+/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
+#line 3 "/usr/share/bison.simple"
+/* This file comes from bison-1.27. */
+
+/* Skeleton output parser for bison,
+ Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison. */
+
+/* This is the parser code that is written into each bison parser
+ when the %semantic_parser declaration is not specified in the grammar.
+ It was written by Richard Stallman by simplifying the hairy parser
+ used when %semantic_parser is specified. */
+
+#ifndef YYSTACK_USE_ALLOCA
+#ifdef alloca
+#define YYSTACK_USE_ALLOCA
+#else /* alloca not defined */
+#ifdef __GNUC__
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#else /* not GNU C. */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))
+#define YYSTACK_USE_ALLOCA
+#include <alloca.h>
+#else /* not sparc */
+/* We think this test detects Watcom and Microsoft C. */
+/* This used to test MSDOS, but that is a bad idea
+ since that symbol is in the user namespace. */
+#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)
+#if 0 /* No need for malloc.h, which pollutes the namespace;
+ instead, just don't use alloca. */
+#include <malloc.h>
+#endif
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+/* I don't know what this was needed for, but it pollutes the namespace.
+ So I turned it off. rms, 2 May 1997. */
+/* #include <malloc.h> */
+ #pragma alloca
+#define YYSTACK_USE_ALLOCA
+#else /* not MSDOS, or __TURBOC__, or _AIX */
+#if 0
+#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,
+ and on HPUX 10. Eventually we can turn this on. */
+#define YYSTACK_USE_ALLOCA
+#define alloca __builtin_alloca
+#endif /* __hpux */
+#endif
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc */
+#endif /* not GNU C */
+#endif /* alloca not defined */
+#endif /* YYSTACK_USE_ALLOCA not defined */
+
+#ifdef YYSTACK_USE_ALLOCA
+#define YYSTACK_ALLOC alloca
+#else
+#define YYSTACK_ALLOC malloc
+#endif
+
+/* Note: there must be only one dollar sign in this file.
+ It is replaced by the list of actions, each action
+ as one case of the switch. */
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY -2
+#define YYEOF 0
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrlab1
+/* Like YYERROR except do call yyerror.
+ This remains here temporarily to ease the
+ transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+#define YYFAIL goto yyerrlab
+#define YYRECOVERING() (!!yyerrstatus)
+#define YYBACKUP(token, value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { yychar = (token), yylval = (value); \
+ yychar1 = YYTRANSLATE (yychar); \
+ YYPOPSTACK; \
+ goto yybackup; \
+ } \
+ else \
+ { yyerror ("syntax error: cannot back up"); YYERROR; } \
+while (0)
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+#ifndef YYPURE
+#define YYLEX yylex()
+#endif
+
+#ifdef YYPURE
+#ifdef YYLSP_NEEDED
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval, &yylloc)
+#endif
+#else /* not YYLSP_NEEDED */
+#ifdef YYLEX_PARAM
+#define YYLEX yylex(&yylval, YYLEX_PARAM)
+#else
+#define YYLEX yylex(&yylval)
+#endif
+#endif /* not YYLSP_NEEDED */
+#endif
+
+/* If nonreentrant, generate the variables here */
+
+#ifndef YYPURE
+
+int yychar; /* the lookahead symbol */
+YYSTYPE yylval; /* the semantic value of the */
+ /* lookahead symbol */
+
+#ifdef YYLSP_NEEDED
+YYLTYPE yylloc; /* location data for the lookahead */
+ /* symbol */
+#endif
+
+int yynerrs; /* number of parse errors so far */
+#endif /* not YYPURE */
+
+#if YYDEBUG != 0
+int yydebug; /* nonzero means print parse trace */
+/* Since this is uninitialized, it does not stop multiple parsers
+ from coexisting. */
+#endif
+
+/* YYINITDEPTH indicates the initial size of the parser's stacks */
+
+#ifndef YYINITDEPTH
+#define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH is the maximum size the stacks can grow to
+ (effective only if the built-in stack extension method is used). */
+
+#if YYMAXDEPTH == 0
+#undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 10000
+#endif
+
+/* Define __yy_memcpy. Note that the size argument
+ should be passed with type unsigned int, because that is what the non-GCC
+ definitions require. With GCC, __builtin_memcpy takes an arg
+ of type size_t, but it can handle unsigned int. */
+
+#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */
+#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT)
+#else /* not GNU C or C++ */
+#ifndef __cplusplus
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (to, from, count)
+ char *to;
+ char *from;
+ unsigned int count;
+{
+ register char *f = from;
+ register char *t = to;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#else /* __cplusplus */
+
+/* This is the most reliable way to avoid incompatibilities
+ in available built-in functions on various systems. */
+static void
+__yy_memcpy (char *to, char *from, unsigned int count)
+{
+ register char *t = to;
+ register char *f = from;
+ register int i = count;
+
+ while (i-- > 0)
+ *t++ = *f++;
+}
+
+#endif
+#endif
+
+#line 216 "/usr/share/bison.simple"
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+ into yyparse. The argument should have type void *.
+ It should actually point to an object.
+ Grammar actions can access the variable by casting it
+ to the proper pointer type. */
+
+#ifdef YYPARSE_PARAM
+#ifdef __cplusplus
+#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL
+#else /* not __cplusplus */
+#define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+#endif /* not __cplusplus */
+#else /* not YYPARSE_PARAM */
+#define YYPARSE_PARAM_ARG
+#define YYPARSE_PARAM_DECL
+#endif /* not YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes. */
+#ifdef __GNUC__
+#ifdef YYPARSE_PARAM
+int yyparse (void *);
+#else
+int yyparse (void);
+#endif
+#endif
+
+int
+yyparse(YYPARSE_PARAM_ARG)
+ YYPARSE_PARAM_DECL
+{
+ register int yystate;
+ register int yyn;
+ register short *yyssp;
+ register YYSTYPE *yyvsp;
+ int yyerrstatus; /* number of tokens to shift before error messages enabled */
+ int yychar1 = 0; /* lookahead token as an internal (translated) token number */
+
+ short yyssa[YYINITDEPTH]; /* the state stack */
+ YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */
+
+ short *yyss = yyssa; /* refer to the stacks thru separate pointers */
+ YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */
+
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp;
+
+#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
+#else
+#define YYPOPSTACK (yyvsp--, yyssp--)
+#endif
+
+ int yystacksize = YYINITDEPTH;
+ int yyfree_stacks = 0;
+
+#ifdef YYPURE
+ int yychar;
+ YYSTYPE yylval;
+ int yynerrs;
+#ifdef YYLSP_NEEDED
+ YYLTYPE yylloc;
+#endif
+#endif
+
+ YYSTYPE yyval; /* the variable used to return */
+ /* semantic values from the action */
+ /* routines */
+
+ int yylen;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Starting parse\n");
+#endif
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss - 1;
+ yyvsp = yyvs;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls;
+#endif
+
+/* Push a new state, which is found in yystate . */
+/* In all cases, when you get here, the value and location stacks
+ have just been pushed. so pushing a state here evens the stacks. */
+yynewstate:
+
+ *++yyssp = yystate;
+
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ /* Give user a chance to reallocate the stack */
+ /* Use copies of these so that the &'s don't force the real ones into memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ short *yyss1 = yyss;
+#ifdef YYLSP_NEEDED
+ YYLTYPE *yyls1 = yyls;
+#endif
+
+ /* Get the current used size of the three stacks, in elements. */
+ int size = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ /* Each stack pointer address is followed by the size of
+ the data in use in that stack, in bytes. */
+#ifdef YYLSP_NEEDED
+ /* This used to be a conditional around just the two extra args,
+ but that might be undefined if yyoverflow is a macro. */
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yyls1, size * sizeof (*yylsp),
+ &yystacksize);
+#else
+ yyoverflow("parser stack overflow",
+ &yyss1, size * sizeof (*yyssp),
+ &yyvs1, size * sizeof (*yyvsp),
+ &yystacksize);
+#endif
+
+ yyss = yyss1; yyvs = yyvs1;
+#ifdef YYLSP_NEEDED
+ yyls = yyls1;
+#endif
+#else /* no yyoverflow */
+ /* Extend the stack our own way. */
+ if (yystacksize >= YYMAXDEPTH)
+ {
+ yyerror("parser stack overflow");
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 2;
+ }
+ yystacksize *= 2;
+ if (yystacksize > YYMAXDEPTH)
+ yystacksize = YYMAXDEPTH;
+#ifndef YYSTACK_USE_ALLOCA
+ yyfree_stacks = 1;
+#endif
+ yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));
+ __yy_memcpy ((char *)yyss, (char *)yyss1,
+ size * (unsigned int) sizeof (*yyssp));
+ yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));
+ __yy_memcpy ((char *)yyvs, (char *)yyvs1,
+ size * (unsigned int) sizeof (*yyvsp));
+#ifdef YYLSP_NEEDED
+ yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));
+ __yy_memcpy ((char *)yyls, (char *)yyls1,
+ size * (unsigned int) sizeof (*yylsp));
+#endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + size - 1;
+ yyvsp = yyvs + size - 1;
+#ifdef YYLSP_NEEDED
+ yylsp = yyls + size - 1;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Stack size increased to %d\n", yystacksize);
+#endif
+
+ if (yyssp >= yyss + yystacksize - 1)
+ YYABORT;
+ }
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Entering state %d\n", yystate);
+#endif
+
+ goto yybackup;
+ yybackup:
+
+/* Do appropriate processing given the current state. */
+/* Read a lookahead token if we need one and don't already have one. */
+/* yyresume: */
+
+ /* First try to decide what to do without reference to lookahead token. */
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* yychar is either YYEMPTY or YYEOF
+ or a valid token in external form. */
+
+ if (yychar == YYEMPTY)
+ {
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Reading a token: ");
+#endif
+ yychar = YYLEX;
+ }
+
+ /* Convert token to internal form (in yychar1) for indexing tables with */
+
+ if (yychar <= 0) /* This means end of input. */
+ {
+ yychar1 = 0;
+ yychar = YYEOF; /* Don't call YYLEX any more */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Now at end of input.\n");
+#endif
+ }
+ else
+ {
+ yychar1 = YYTRANSLATE(yychar);
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
+ /* Give the individual parser a way to print the precise meaning
+ of a token, for further debugging info. */
+#ifdef YYPRINT
+ YYPRINT (stderr, yychar, yylval);
+#endif
+ fprintf (stderr, ")\n");
+ }
+#endif
+ }
+
+ yyn += yychar1;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+ goto yydefault;
+
+ yyn = yytable[yyn];
+
+ /* yyn is what to do for this token type in this state.
+ Negative => reduce, -yyn is rule number.
+ Positive => shift, yyn is new state.
+ New state is final state => don't bother to shift,
+ just return success.
+ 0, or most negative number => error. */
+
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrlab;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Shift the lookahead token. */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
+#endif
+
+ /* Discard the token being shifted unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ /* count tokens shifted since error; after three, turn off error status. */
+ if (yyerrstatus) yyerrstatus--;
+
+ yystate = yyn;
+ goto yynewstate;
+
+/* Do the default action for the current state. */
+yydefault:
+
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+
+/* Do a reduction. yyn is the number of a rule to reduce with. */
+yyreduce:
+ yylen = yyr2[yyn];
+ if (yylen > 0)
+ yyval = yyvsp[1-yylen]; /* implement default value of the action */
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ int i;
+
+ fprintf (stderr, "Reducing via rule %d (line %d), ",
+ yyn, yyrline[yyn]);
+
+ /* Print the symbols being reduced, and their result. */
+ for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
+ fprintf (stderr, "%s ", yytname[yyrhs[i]]);
+ fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+ }
+#endif
+
+
+ switch (yyn) {
+
+case 5:
+#line 38 "minicompg.y"
+{yyval=new_type(DOUBLE);;
+ break;}
+case 6:
+#line 39 "minicompg.y"
+{yyval=new_type(INT);;
+ break;}
+case 7:
+#line 40 "minicompg.y"
+{yyval=new_array(yyvsp[-3],yyvsp[-1]);;
+ break;}
+case 10:
+#line 49 "minicompg.y"
+{add_var(yyvsp[-1],yyvsp[-2]);;
+ break;}
+case 11:
+#line 53 "minicompg.y"
+{yyval=add_string(tkname);;
+ break;}
+case 12:
+#line 57 "minicompg.y"
+{yyval=binary_node(NAND,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 13:
+#line 58 "minicompg.y"
+{yyval=binary_node(NOR,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 15:
+#line 63 "minicompg.y"
+{yyval=binary_node(NEQUALS,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 16:
+#line 64 "minicompg.y"
+{yyval=binary_node(NNEQ,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 17:
+#line 65 "minicompg.y"
+{yyval=binary_node(NLT,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 18:
+#line 66 "minicompg.y"
+{yyval=binary_node(NGT,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 19:
+#line 67 "minicompg.y"
+{yyval=binary_node(NLEQ,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 20:
+#line 68 "minicompg.y"
+{yyval=binary_node(NGEQ,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 21:
+#line 69 "minicompg.y"
+{yyval=yyvsp[-1];
+ break;}
+case 22:
+#line 72 "minicompg.y"
+{yyval=binary_node(NADD,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 23:
+#line 73 "minicompg.y"
+{yyval=binary_node(NSUB,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 25:
+#line 77 "minicompg.y"
+{yyval=binary_node(NMUL,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 26:
+#line 78 "minicompg.y"
+{yyval=binary_node(NDIV,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 28:
+#line 83 "minicompg.y"
+{yyval=yyvsp[-1];;
+ break;}
+case 29:
+#line 84 "minicompg.y"
+{yyval=number_node();;
+ break;}
+case 30:
+#line 85 "minicompg.y"
+{yyval=binary_node(NCALL,yyvsp[-3],yyvsp[-1]);;
+ break;}
+case 31:
+#line 86 "minicompg.y"
+{yyval=binary_node(NCALL,yyvsp[-2],0);;
+ break;}
+case 33:
+#line 91 "minicompg.y"
+{yyval=binary_node(NINDEX,yyvsp[-3],yyvsp[-1]);;
+ break;}
+case 35:
+#line 96 "minicompg.y"
+{yyval=var_node();;
+ break;}
+case 36:
+#line 100 "minicompg.y"
+{yyval=binary_node(NARG,yyvsp[-2],yyvsp[0]);;
+ break;}
+case 45:
+#line 118 "minicompg.y"
+{enter_block();;
+ break;}
+case 47:
+#line 122 "minicompg.y"
+{leave_block();;
+ break;}
+case 48:
+#line 123 "minicompg.y"
+{leave_block();;
+ break;}
+case 49:
+#line 124 "minicompg.y"
+{leave_block();;
+ break;}
+case 50:
+#line 125 "minicompg.y"
+{leave_block();;
+ break;}
+case 51:
+#line 130 "minicompg.y"
+{if_statement(yyvsp[-1]);;
+ break;}
+case 53:
+#line 134 "minicompg.y"
+{if_end();;
+ break;}
+case 54:
+#line 135 "minicompg.y"
+{if_else();;
+ break;}
+case 55:
+#line 135 "minicompg.y"
+{if_end();;
+ break;}
+case 56:
+#line 140 "minicompg.y"
+{while_statement(yyvsp[-1]);;
+ break;}
+case 57:
+#line 140 "minicompg.y"
+{while_end();;
+ break;}
+case 58:
+#line 144 "minicompg.y"
+{assign_statement(yyvsp[-3],yyvsp[-1]);;
+ break;}
+case 59:
+#line 148 "minicompg.y"
+{return_statement(yyvsp[-1]);;
+ break;}
+case 61:
+#line 156 "minicompg.y"
+{enter_func(yyvsp[-1],yyvsp[-2]);;
+ break;}
+case 62:
+#line 160 "minicompg.y"
+{leave_func();;
+ break;}
+case 63:
+#line 161 "minicompg.y"
+{leave_func();;
+ break;}
+case 66:
+#line 170 "minicompg.y"
+{add_var(yyvsp[0],yyvsp[-1]);;
+ break;}
+}
+ /* the action file gets copied in in place of this dollarsign */
+#line 542 "/usr/share/bison.simple"
+
+ yyvsp -= yylen;
+ yyssp -= yylen;
+#ifdef YYLSP_NEEDED
+ yylsp -= yylen;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ *++yyvsp = yyval;
+
+#ifdef YYLSP_NEEDED
+ yylsp++;
+ if (yylen == 0)
+ {
+ yylsp->first_line = yylloc.first_line;
+ yylsp->first_column = yylloc.first_column;
+ yylsp->last_line = (yylsp-1)->last_line;
+ yylsp->last_column = (yylsp-1)->last_column;
+ yylsp->text = 0;
+ }
+ else
+ {
+ yylsp->last_line = (yylsp+yylen-1)->last_line;
+ yylsp->last_column = (yylsp+yylen-1)->last_column;
+ }
+#endif
+
+ /* Now "shift" the result of the reduction.
+ Determine what state that goes to,
+ based on the state we popped back to
+ and the rule number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+ if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTBASE];
+
+ goto yynewstate;
+
+yyerrlab: /* here on detecting error */
+
+ if (! yyerrstatus)
+ /* If not already recovering from an error, report this error. */
+ {
+ ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+ yyn = yypact[yystate];
+
+ if (yyn > YYFLAG && yyn < YYLAST)
+ {
+ int size = 0;
+ char *msg;
+ int x, count;
+
+ count = 0;
+ /* Start X at -yyn if nec to avoid negative indexes in yycheck. */
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ size += strlen(yytname[x]) + 15, count++;
+ msg = (char *) malloc(size + 15);
+ if (msg != 0)
+ {
+ strcpy(msg, "parse error");
+
+ if (count < 5)
+ {
+ count = 0;
+ for (x = (yyn < 0 ? -yyn : 0);
+ x < (sizeof(yytname) / sizeof(char *)); x++)
+ if (yycheck[x + yyn] == x)
+ {
+ strcat(msg, count == 0 ? ", expecting `" : " or `");
+ strcat(msg, yytname[x]);
+ strcat(msg, "'");
+ count++;
+ }
+ }
+ yyerror(msg);
+ free(msg);
+ }
+ else
+ yyerror ("parse error; also virtual memory exceeded");
+ }
+ else
+#endif /* YYERROR_VERBOSE */
+ yyerror("parse error");
+ }
+
+ goto yyerrlab1;
+yyerrlab1: /* here on error raised explicitly by an action */
+
+ if (yyerrstatus == 3)
+ {
+ /* if just tried and failed to reuse lookahead token after an error, discard it. */
+
+ /* return failure if at end of input */
+ if (yychar == YYEOF)
+ YYABORT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
+#endif
+
+ yychar = YYEMPTY;
+ }
+
+ /* Else will try to reuse lookahead token
+ after shifting the error token. */
+
+ yyerrstatus = 3; /* Each real token shifted decrements this */
+
+ goto yyerrhandle;
+
+yyerrdefault: /* current state does not do anything special for the error token. */
+
+#if 0
+ /* This is wrong; only states that explicitly want error tokens
+ should shift them. */
+ yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/
+ if (yyn) goto yydefault;
+#endif
+
+yyerrpop: /* pop the current state because it cannot handle the error token */
+
+ if (yyssp == yyss) YYABORT;
+ yyvsp--;
+ yystate = *--yyssp;
+#ifdef YYLSP_NEEDED
+ yylsp--;
+#endif
+
+#if YYDEBUG != 0
+ if (yydebug)
+ {
+ short *ssp1 = yyss - 1;
+ fprintf (stderr, "Error: state stack now");
+ while (ssp1 != yyssp)
+ fprintf (stderr, " %d", *++ssp1);
+ fprintf (stderr, "\n");
+ }
+#endif
+
+yyerrhandle:
+
+ yyn = yypact[yystate];
+ if (yyn == YYFLAG)
+ goto yyerrdefault;
+
+ yyn += YYTERROR;
+ if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+ goto yyerrdefault;
+
+ yyn = yytable[yyn];
+ if (yyn < 0)
+ {
+ if (yyn == YYFLAG)
+ goto yyerrpop;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+ else if (yyn == 0)
+ goto yyerrpop;
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+#if YYDEBUG != 0
+ if (yydebug)
+ fprintf(stderr, "Shifting error token, ");
+#endif
+
+ *++yyvsp = yylval;
+#ifdef YYLSP_NEEDED
+ *++yylsp = yylloc;
+#endif
+
+ yystate = yyn;
+ goto yynewstate;
+
+ yyacceptlab:
+ /* YYACCEPT comes here. */
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 0;
+
+ yyabortlab:
+ /* YYABORT comes here. */
+ if (yyfree_stacks)
+ {
+ free (yyss);
+ free (yyvs);
+#ifdef YYLSP_NEEDED
+ free (yyls);
+#endif
+ }
+ return 1;
+}
+#line 173 "minicompg.y"
+
+
+#include "minicomplexer.c"
+
diff --git a/minicomplexer.c b/minicomplexer.c
new file mode 100755
index 0000000..b337995
--- /dev/null
+++ b/minicomplexer.c
@@ -0,0 +1,79 @@
+
+FILE *infile;
+static int cur_char=' ';
+
+char tkname[MAXLEN];
+
+int yylex()
+{
+ char *p=tkname;
+ int tmp;
+
+ while(isspace(cur_char))
+ cur_char=getc(infile);
+
+ if(isdigit(cur_char)){
+ do{
+ *p++=cur_char;
+ cur_char=getc(infile);
+ }while(isdigit(cur_char));
+ if(cur_char=='.'){
+ *p++=cur_char;
+ cur_char=getc(infile);
+ while(isdigit(cur_char)){
+ *p++=cur_char;
+ cur_char=getc(infile);
+ }
+ }
+ *p++=0;
+ return TKNUMBER;
+ }
+ if(isalpha(cur_char)){
+ do{
+ *p++=cur_char;
+ cur_char=getc(infile);
+ }while(isalnum(cur_char));
+ *p++=0;
+ if(!strcmp(tkname,"int"))
+ return TKINT;
+ if(!strcmp(tkname,"real"))
+ return TKREAL;
+ if(!strcmp(tkname,"if"))
+ return TKIF;
+ if(!strcmp(tkname,"else"))
+ return TKELSE;
+ if(!strcmp(tkname,"while"))
+ return TKWHILE;
+ if(!strcmp(tkname,"return"))
+ return TKRETURN;
+ return TKIDENTIFIER;
+ }
+ tmp=cur_char;
+ cur_char=getc(infile);
+ if(tmp=='!'&&cur_char=='='){
+ cur_char=getc(infile);
+ return TKNEQ;
+ }
+ if(tmp=='<'&&cur_char=='='){
+ cur_char=getc(infile);
+ return TKLEQ;
+ }
+ if(tmp=='>'&&cur_char=='='){
+ cur_char=getc(infile);
+ return TKGEQ;
+ }
+ if(tmp=='&'&&cur_char=='&'){
+ cur_char=getc(infile);
+ return TKAND;
+ }
+ if(tmp=='|'&&cur_char=='|'){
+ cur_char=getc(infile);
+ return TKOR;
+ }
+ if(tmp==':'&&cur_char=='='){
+ cur_char=getc(infile);
+ return TKASSIGN;
+ }
+ return tmp;
+}
+
diff --git a/misra_errors.h b/misra_errors.h
new file mode 100755
index 0000000..d9a128e
--- /dev/null
+++ b/misra_errors.h
@@ -0,0 +1,380 @@
+/* Kapitel 1 */
+1,1,"All code shall conform to ISO 9899:1990 \"Programming languages - Câ\", amended and "
+"corrected by ISO/IEC 9899/COR1:1995, ISO/IEC 9899/AMD1:1995, and ISO/IEC 9899/COR2:1996.",MISRA|MISRA_2004,
+
+1,2,"No reliance shall be placed on undefined or unspecified behaviour.",MISRA|MISRA_2004,
+
+1,3,"Multiple compilers and/or languages shall only be used if there is a common defined "
+"interface standard for object code to which the languages/compilers/assembler conforms",MISRA|MISRA_2004,
+
+1,4,"The compiler/linker shall be checked to ensure that 31 character significance and "
+"case sensitivity are supported for external identifiers",MISRA|MISRA_2004,
+
+1,5,"Floating point implementations should comply with a defined floating-point standard",MISRA|MISRA_2004,
+
+/* Kapitel 2 */
+2,1,"Assembly language shall be encapsulated and isolated",MISRA|MISRA_2004,
+
+2,2,"Source code shall only use /* ... */ style comments",MISRA|MISRA_2004,
+
+2,3,"The character sequence /* shall not be used within a comment",MISRA|MISRA_2004,
+
+2,4,"Sections of code should not be \"commented out\"",MISRA|MISRA_2004,
+
+
+/* Kapitel 3 */
+3,1,"All usage of implementation-defined behaviour shall be documented ",MISRA|MISRA_2004,
+
+3,2,"The character set and corresponding encoding shall be documented",MISRA|MISRA_2004,
+
+3,3,"The implementation of integer division in the chosen compiler should "
+"be determined, documented and taken into account",MISRA|MISRA_2004,
+
+3,4,"All use of the #pragma directive shall be documented and explained",MISRA|MISRA_2004,
+
+3,5,"If it is being relied upon, the implementation-defined behaviour and "
+"packing of bitfields shall be documented",MISRA|MISRA_2004,
+
+3,6,"All libraries used in production code shall be written to comply with "
+"the provisions of this document, and shall have been subject to appropriate validation",MISRA|MISRA_2004,
+
+
+/* Kapitel 4 */
+4,1,"Only those escape sequences that are defined in the ISO C standard shall be used",MISRA|MISRA_2004|MISRA_PREPROC,
+
+4,2,"Trigraphs shall not be used",MISRA|MISRA_2004,
+
+
+/* Kapitel 5*/
+5,1,"Identifiers (internal and external) shall not rely on the significance "
+"of more than 31 characters",MISRA|MISRA_2004,
+
+5,2,"Identifiers in an inner scope shall not use the same name as an identifier "
+"in an outer scope, and therefor hide that identifier",MISRA|MISRA_2004,
+
+5,3,"A typedef name shall be a unique identifier",MISRA|MISRA_2004,
+
+5,4,"A tag name shall be a unique identifier",MISRA|MISRA_2004,
+
+5,5,"No object or function identifier with static storage duration should be reused",MISRA|MISRA_2004,
+
+5,6,"No identifier in one name space should have the same spelling as an identifier "
+"in another name space, with the exception of structure and union member names",MISRA|MISRA_2004,
+
+5,7,"No identifier name should be reused",MISRA|MISRA_2004,
+
+
+/* Kapitel 6 */
+6,1,"The plain char type shall be used only for the storage and use of character values",MISRA|MISRA_2004,
+
+6,2,"signed and unsigned char type shall be used only for the storage and use of numeric values",MISRA|MISRA_2004,
+
+6,3,"typedefs that indicate size and signedness should be used in place of the basic types",MISRA|MISRA_2004,
+
+6,4,"Bit fields shall only be defined to be of type unsigned int or signed int",MISRA|MISRA_2004,
+
+6,5,"Bit fields of type signed int shall be at least 2 bit long",MISRA|MISRA_2004,
+
+
+/* Kapitel 7 */
+7,1,"Octal constants (other than zero) and octal escape sequences shall not be used",MISRA|MISRA_2004,
+
+
+/* Kapitel 8 */
+8,1,"Functions shall have prototype declaration and the prototype shall "
+"be visible at both the function definition and call",MISRA|MISRA_2004,
+
+8,2,"Whenever an object or function is declared or defined, its type shall "
+"be explicitly stated",MISRA|MISRA_2004,
+
+8,3,"For each function parameter the type given in the declaration and "
+"definition shall be identical, and the return type shall also be identical",MISRA|MISRA_2004,
+
+8,4,"If objects or functions are declared more than once their type shall be compatible",MISRA|MISRA_2004,
+
+8,5,"There shall be no definition of objects or functions in a header file",MISRA|MISRA_2004,
+
+8,6,"Functions shall be declared at file scope",MISRA|MISRA_2004,
+
+8,7,"Objects shall be defined at block scope if they are only accessed from "
+"within a single function",MISRA|MISRA_2004,
+
+8,8,"An external object or function shall be declared in one and only one file",MISRA|MISRA_2004,
+
+8,9,"An identifier with external linkage shall have excactly one external definition",MISRA|MISRA_2004,
+
+8,10,"All declarations and definitions of objects and functions at file scope shall "
+"have internal linkage unless external linkage is required",MISRA|MISRA_2004,
+
+8,11,"The static storage class specifier shall be used in definitions and declarations "
+"of objects and functions that have internal linkage",MISRA|MISRA_2004,
+
+8,12,"When an array is declared with external linkage, its size shall be stated "
+"or defined implicitly be initialisation",MISRA|MISRA_2004,
+
+
+/* Kapitel 9 */
+9,1,"All automatic variables shall have been assigned a value before being used",MISRA|MISRA_2004,
+
+9,2,"Braces shall be used to indicate and match the structure in the non-zero "
+"initialisation of arrays and structures",MISRA|MISRA_2004,
+
+9,3,"In an enumerator list, the \"=\" construct shall not be used to explicitly "
+"initialise members other than the first, unless all items are explicitly initialised",MISRA|MISRA_2004,
+
+
+/* Kapitel 10 */
+10,1,"The value of an expression of integer type shall not be implicitly converted to a different underlying type if: \n"
+" a) it is not a conversion to a wider integer type of the same signedness, or\n"
+" b) the expression is complex, or\n"
+" c) the expression is not constant and is a function argument, or\n"
+" d) the expression is not constant and is a return expression",MISRA|MISRA_2004,
+
+10,2,"The value of an expression of floating type shall not be implicitly converted to a different type if:\n"
+" a) it is not a conversion to a wider floating type, or\n"
+" b) the expression is complex, or\n"
+" c) the expression is a function argument, or\n"
+" d) the expression is a return expression\n",MISRA|MISRA_2004,
+
+10,3,"The value of a complex expression of integer type may only be cast "
+"to a atype that is narrower and of the same signedness as the "
+"underlying type of the expression",MISRA|MISRA_2004,
+
+10,4,"The value of a complex expression of floating type may only be cast "
+"to a narrower floating type",MISRA|MISRA_2004,
+
+10,5,"If the bitwise operators ~ and << are applied to an operand of "
+"underlying type unsigned char or unsigned short, the result "
+"shall be immediately cast to the underlying type of the operand",MISRA|MISRA_2004,
+
+10,6,"A \"U\" suffix shall be applied to all constants of unsigned type",MISRA|MISRA_2004,
+
+/* Kapitel 11 */
+11,1,"Conversions shall not be performed between a pointer to a function and any type "
+"other than an integral type",MISRA|MISRA_2004,
+
+11,2,"Conversions shall not be performed between a pointer to object and any type "
+"other than an integral type, another pointer to object type or a pointer to void",MISRA|MISRA_2004,
+
+11,3,"A cast should not be performed between a pointer type and an integral type",MISRA|MISRA_2004,
+
+11,4,"A cast should not be performed between a pointer to object type and a "
+"different pointer to object type.",MISRA|MISRA_2004,
+
+11,5,"A cast shall not be performed that removes any const or volatile qualification "
+"from the type addresses by a pointer",MISRA|MISRA_2004,
+
+
+/* Kapitel 12 */
+12,1,"Limited dependence should be placed on C's operator precedence rules in expressions",MISRA|MISRA_2004,
+
+12,2,"The value of an expression shall be the same under any order of "
+"evaluation that the standard permits",MISRA|MISRA_2004,
+
+12,3,"The sizeof operator shall not be used on expressions that contain side effects",MISRA|MISRA_2004,
+
+12,4,"The right-hand operand of a logical && or || operator shall not "
+"contain side effects",MISRA|MISRA_2004,
+
+12,5,"The operands of a logical && or || shall be primary-expressions",MISRA|MISRA_2004,
+
+12,6,"The operands of logical operators (&&, || and !) should be effectively Boolean, "
+"Expressions that are effectively Booleand should not be used as operands to "
+"eperators other than(&&, || and !)",MISRA|MISRA_2004,
+
+12,7,"Bitweise operators shall not be applied to operands whose underlying type is signed",MISRA|MISRA_2004,
+
+12,8,"The right-hand operand of a shift operator shall lie between zero and one less "
+"than the width in bits of ther underlying type of the left-hand operand.",MISRA|MISRA_2004,
+
+12,9,"The unary minus operator shall not be applied to an expression whose underlying type is unsigned",MISRA|MISRA_2004,
+
+12,10,"The comma operator shall not be used",MISRA|MISRA_2004,
+
+12,11,"Evaluation of constant unsigned integer expressions should not lead to wrap-around",MISRA|MISRA_2004,
+
+12,12,"The underlying bit representation of floating-point values shall not be used",MISRA|MISRA_2004,
+
+12,13,"The increment (++) and decrement (--) operators should not be mixed with other "
+"operators in an expression",MISRA|MISRA_2004,
+
+
+/* Kapitel 13 */
+13,1,"Assignment opetaors shall not be used in expressions that yield a Boolean value",MISRA|MISRA_2004,
+
+13,2,"Tests of a value against zero should be made explicit, unless the operand is effectively Boolean",MISRA|MISRA_2004,
+
+13,3,"Floating-point expressions shall not be tested for equality or inequality",MISRA|MISRA_2004,
+
+13,4,"The controlling expression of a for statement shall not contain any objects of floating type.",MISRA|MISRA_2004,
+
+13,5,"The three expressions of a for statement shall be concerned only with loop control",MISRA|MISRA_2004,
+
+13,6,"Numeric variables being used within a for loop for iteration counting shall not be modified in the body of the loop",MISRA|MISRA_2004,
+
+13,7,"Boolean operations whose results are invariant shall not be permitted",MISRA|MISRA_2004,
+
+
+/* Kapitel 14 */
+14,1,"There shall be no unreachable code",MISRA|MISRA_2004,
+
+14,2,"All non-null statements shall either:\n"
+" a) have at least one side-effect however executed, or\n"
+" b) cause control flow to change",MISRA|MISRA_2004,
+
+14,3,"Before preprocessing, a null statement shall only occur on a line by itself; it may be "
+"followed by a comment provided that the first character following the null statement "
+"is a white-space character.",MISRA|MISRA_2004,
+
+14,4,"The goto statement shall not be used",MISRA|MISRA_2004,
+
+14,5,"The continue statement shall not be used",MISRA|MISRA_2004,
+
+14,6,"For any interation statement there shall be at most one braek statement used for loop termination",MISRA|MISRA_2004,
+
+14,7,"A function shall have a single point of exit at the end of the function",MISRA|MISRA_2004,
+
+14,8,"The statement forming the body of a switch, while, do ... while or for statement "
+"shall be a compound statement",MISRA|MISRA_2004,
+
+14,9,"An if (expression) construct shall be followed by a compound statement. The else "
+"keyword shall be followed by either a compound statement, or another if statement",MISRA|MISRA_2004,
+
+14,10,"All if ... else if constructs shall be terminated with an else clause",MISRA|MISRA_2004,
+
+
+/* Kapitel 15 */
+15,1,"A switch label shall only be used when the most closely-enclosing compound statement is the body of a switch statement",MISRA|MISRA_2004,
+
+15,2,"An unconditional break statement shall terminate every non-empty switch clause",MISRA|MISRA_2004,
+
+15,3,"The final clause of a switch statement shall be the default clause",MISRA|MISRA_2004,
+
+15,4,"A Switch expression shall not represent a value that is effectively Boolean",MISRA|MISRA_2004,
+
+15,5,"Every switch statement shall have at least one case clause",MISRA|MISRA_2004,
+
+
+/* Kapitel 16 */
+16,1,"Functions shall not be defined with a variable number of arguments",MISRA|MISRA_2004,
+
+16,2,"Functions shall not call themselves, either directly or indirectly",MISRA|MISRA_2004,
+
+16,3,"Identifiers shall be given for all of the parameters in a function prototype declaration",MISRA|MISRA_2004,
+
+16,4,"The identifiers used in the declaration and definition of a function shall be identical",MISRA|MISRA_2004,
+
+16,5,"Functions with no parameters shall be declared with parameter type void",MISRA|MISRA_2004,
+
+16,6,"The number of arguments passed to a function shall match the number of parameters",MISRA|MISRA_2004,
+
+16,7,"A pointer parameter in a function prototype should be declared as pointer to const "
+"if the pointer is not used to modify the addressed object",MISRA|MISRA_2004,
+
+16,8,"All exit paths from a function with non-void return type shall have an explicit "
+"return statement with an expression",MISRA|MISRA_2004,
+
+16,9,"A function identifier shall only be used with either a preceding &, or with a "
+"parenthesised parameter list, which may be empty",MISRA|MISRA_2004,
+
+16,10,"If a function returns error information, then that error information shall be tested",MISRA|MISRA_2004,
+
+
+/* Kapitel 17 */
+17,1,"Pointer arithmetic shall only be applied to pointers that address an array or array element",MISRA|MISRA_2004,
+
+17,2,"Pointer subtraction shall only be apllied to pointers that address elements of the same array",MISRA|MISRA_2004,
+
+17,3,">, >=, <, <= shall not be applied to pointer types except where they point to the same array",MISRA|MISRA_2004,
+
+17,4,"Array indexing shall be the only allowed form of pointer arithmetic",MISRA|MISRA_2004,
+
+17,5,"The declaration of objects should contain no more than 2 levels of pointer indirection",MISRA|MISRA_2004,
+
+17,6,"The address of an object with automatic storage shall not be assigned to an other "
+"object that may persist after the first object has ceased to exist",MISRA|MISRA_2004,
+
+
+/* Kapitel 18 */
+18,1,"All structure and union types shall be complete at the end of a translation unit",MISRA|MISRA_2004,
+
+18,2,"An object shall not be assigned to an overlapping object",MISRA|MISRA_2004,
+
+18,3,"An area of memory shall not be reused for unrelated purposes",MISRA|MISRA_2004,
+
+18,4,"Unions shall not be used",MISRA|MISRA_2004,
+
+
+/* Kapitel 19 */
+19,1,"#include statements in a file should only be preceded by other preprocessor directives or comments",MISRA|MISRA_2004,
+
+19,2,"Non-standard characters should not occur in header file names in #include directives",MISRA|MISRA_2004,
+
+19,3,"The #include directive shall be followed by either a <filename> or \"filename\" sequence",MISRA|MISRA_2004,
+
+19,4,"C macros shall only expand to a braced initialiser, a constant, a parenthesised "
+"expression, a type qualifier, a storage class specifier, or a do-while-zero construct",MISRA|MISRA_2004,
+
+19,5,"Macros shall not be #defined'd or #undef'd within a block",MISRA|MISRA_2004,
+
+19,6,"#undef shall not be used",MISRA|MISRA_2004,
+
+19,7,"A function should be used in preference to a function-like macro",MISRA|MISRA_2004,
+
+19,8,"A function-like macro shall not be invoked without all of its arguments",MISRA|MISRA_2004,
+
+19,9,"Arguments to a function-like macro shall not contain tokens that look like preprocessing directives",MISRA|MISRA_2004,
+
+19,10,"In the definition of a function-like macro each instance of a parameter shall be enclosed "
+"in parentheses unless it is used as the operand of # or ##",MISRA|MISRA_2004,
+
+19,11,"All macro identifiers in preprocessor directives shall be defined before use, except "
+"in #ifdef and #ifndef preprocessor directives and the defined() operator",MISRA|MISRA_2004,
+
+19,12,"There shall be at most one occurrence of the # or ## preprocessor operators in a "
+"single macro definition",MISRA|MISRA_2004,
+
+19,13,"The # and ## preprocessor operators should not be used",MISRA|MISRA_2004,
+
+19,14,"The defined preprocessor operator shall only be used in one of the two standard forms",MISRA|MISRA_2004,
+
+19,15,"Precautions shall be taken in order to prevent the contents of a header file being included twice",MISRA|MISRA_2004,
+
+19,16,"Preprocessing directives shall be syntactically meaningful even when excluded by the preprocessor",MISRA|MISRA_2004,
+
+19,17,"All #else, #elif and #endif preprocessor directives shall reside in the same file as "
+"the #if or #ifdef directive to which they are related",MISRA|MISRA_2004,
+
+
+/* Kapitel 20 */
+20,1,"Reserved identifiers, macros and functions in the standard library, shall not "
+"be defined, redefined or undefined",MISRA|MISRA_2004,
+
+20,2,"The names of standard library macros, objects and functions shall not be reused",MISRA|MISRA_2004,
+
+20,3,"The validity of values passed to library functions shall be checked",MISRA|MISRA_2004,
+
+20,4,"Dynamic heap memory allocation shall not be used",MISRA|MISRA_2004,
+
+20,5,"The error indicator errno shall not be used",MISRA|MISRA_2004,
+
+20,6,"The macro offsetof, in library <stddef.h>, shall not be used",MISRA|MISRA_2004,
+
+20,7,"The setjmp macro and the longjmp function shall not be used",MISRA|MISRA_2004,
+
+20,8,"The signal handling facilities of <signal.h> shall not be used",MISRA|MISRA_2004,
+
+20,9,"The input/output library <stdio.h> shall not be used in production code",MISRA|MISRA_2004,
+
+20,10,"The library functions atof, atoi and atol from library <stdlib.h> shall not be used",MISRA|MISRA_2004,
+
+20,11,"The library functions abort, exit, getenv and system from library <stdlib.h> shall not be used.",MISRA|MISRA_2004,
+
+20,12,"The time handling functions of library <time.h> shall not be used",MISRA|MISRA_2004,
+
+
+/* Kapitel 21 */
+21,1,"Minimisation of run-time failures shall be ensured by the use of at least one of:\n"
+" a) static analysis tools/techniques\n"
+" b) dynamic analysis tools/techniques\n"
+" c) explicit coding of checks to handle run-time faults",MISRA|MISRA_2004,
diff --git a/opt.c b/opt.c
new file mode 100644
index 0000000..c3cec77
--- /dev/null
+++ b/opt.c
@@ -0,0 +1,2300 @@
+/* $VER: vbcc (opt.c) $Revision: 1.52 $ */
+/* allgemeine Routinen fuer den Optimizer und Steuerung der einzelnen */
+/* Laeufe */
+
+#include "opt.h"
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+/* die naechsten Funktionen sollten evtl. in ic.c */
+
+/* Sind use/change-Listen initialisiert? */
+int have_alias;
+
+int static_cse=1,dref_cse=1;
+int no_eff_ics,early_eff_ics;
+
+#ifdef ALEX_REG
+extern flowgraph *pFg;
+#endif
+
+void insert_IC(IC *p,IC *new)
+/* fuegt new hinter p ein; p darf 0 sein */
+{
+ if((new->code==ADDI2P||new->code==SUBIFP||new->code==SUBPFP)&&!ISPOINTER(new->typf2))
+ ierror(0);
+ new->prev=p;
+ if(p){
+ new->next=p->next; p->next=new;
+ }else{
+ new->next=first_ic; first_ic=new;
+ }
+ if(new->next)
+ new->next->prev=new;
+ else
+ last_ic=new;
+ new->q1.am=new->q2.am=new->z.am=0;
+}
+
+#ifndef NO_OPTIMIZER
+
+int gchanged; /* Merker, ob Optimierungslauf etwas geaendert hat */
+int norek; /* diese Funktion wird nicht rekursiv auf */
+int nocall; /* diese Funktion kehrt nicht zum Caller zurueck */
+
+void fix_shortop(flowgraph *fg,IC *p)
+{
+ if((p->typf&NQ)<INT&&!shortcut(p->code,p->typf)){
+ static type ta;
+ type *t;
+ IC *new;
+ if(DEBUG&1024){puts("fix shortop");pric2(stdout,p);puts("to;");}
+ ta.flags=int_erw(p->typf);
+ t=arith_typ(&ta,&ta);
+ new=new_IC();
+ new->code=CONVERT;
+ new->q1=p->q1;
+ new->z.flags=VAR;
+ new->z.v=add_tmp_var(clone_typ(t));
+ new->typf2=p->typf|UNSIGNED;
+ new->typf=t->flags|UNSIGNED;
+ p->q1=new->z;
+ insert_IC_fg(fg,p->prev,new);
+ new=new_IC();
+ new->code=CONVERT;
+ new->q1=p->q2;
+ new->z.flags=VAR;
+ new->z.v=add_tmp_var(clone_typ(t));
+ new->typf2=p->typf|UNSIGNED;
+ new->typf=t->flags|UNSIGNED;
+ p->q2=new->z;
+ insert_IC_fg(fg,p->prev,new);
+ new=new_IC();
+ new->code=CONVERT;
+ new->z=p->z;
+ new->q1.flags=VAR;
+ new->q1.v=add_tmp_var(t);
+ new->typf=p->typf|UNSIGNED;
+ new->typf2=t->flags|UNSIGNED;
+ p->z=new->q1;
+ insert_IC_fg(fg,p,new);
+ p->typf=t->flags|UNSIGNED;
+ if(DEBUG&1024){
+ pric2(stdout,p->prev->prev);
+ pric2(stdout,p->prev);
+ pric2(stdout,p);
+ pric2(stdout,p->next);
+ }
+ }
+}
+
+#if HAVE_LIBCALLS
+extern np gen_libcall(char *fname,np arg1,type *t1,np arg2,type *t2);
+
+
+/* insert libcalls just before register allocation */
+static int insert_libcalls(flowgraph *fg)
+{
+ IC *p,*next,*add;
+ int replaced=0;
+ static node n,nl,nr;
+ static type t,tl,tr;
+ if(DEBUG&1024) printf("insert_libcalls\n");
+ while(fg){
+ for(p=fg->start;p;p=next){
+ int c=p->code,end=0;
+ char *libname;
+ next=p->next;
+ if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=KOMPLEMENT)||c==COMPARE||c==CONVERT||c==MINUS||c==TEST){
+ if(libname=use_libcall(c,p->typf,p->typf2)){
+ IC *merk_first,*merk_last;
+ static node n1,n2;
+ static type t1,t2;
+ if(DEBUG&1024){
+ printf("converting IC to libcall:\n");
+ pric2(stdout,p);
+ }
+#if FIXED_SP
+ {
+ /* move nested pushs */
+ IC *m;flowgraph *g=fg;int fd=0,i;
+ for(i=0;i<p->arg_cnt;i++){
+ m=p->arg_list[i];
+ if(m->code==PUSH){
+ Var *v;type *t;IC *new;
+ fd=1;
+ if(DEBUG&1024){
+ printf("moving push\n");
+ pric2(stdout,m);
+ }
+ if((m->typf&NQ)==STRUCT) ierror(0);
+ if((m->typf&NQ)==CHAR&&!zmeqto(m->q2.val.vmax,Z1)) ierror(0);
+ t=new_typ();
+ t->flags=m->typf;
+ v=add_tmp_var(t);
+ new=new_IC();
+ new->code=PUSH;
+ new->q2.val.vmax=m->q2.val.vmax;
+ new->typf=m->typf;
+ new->q1.flags=VAR;
+ new->q1.v=v;
+ new->q1.val.vmax=Z0;
+ m->z=new->q1;
+ m->code=ASSIGN;
+ insert_IC_fg(g,p,new);
+ if(DEBUG&1024){
+ pric2(stdout,m);
+ pric2(stdout,new);
+ }
+ p->arg_list[i]=new;
+ }
+ }
+ }
+#endif
+ replaced=1;
+ merk_last=last_ic;
+ merk_first=first_ic;
+ first_ic=last_ic=0;
+ n1.flags=REINTERPRET;
+ n1.o=p->q1;
+ n1.ntyp=&t1;
+ t1.flags=q1typ(p);
+ if(p->q2.flags){
+ n2.flags=REINTERPRET;
+ n2.o=p->q2;
+ n2.ntyp=&t2;
+ t2.flags=q2typ(p);
+ gen_libcall(libname,&n1,&t1,&n2,&t2);
+ }else
+ gen_libcall(libname,&n1,&t1,0,0);
+ if(!last_ic||last_ic->code!=GETRETURN) ierror(0);
+ last_ic->z=p->z;
+ add=first_ic;
+ last_ic=merk_last;
+ first_ic=merk_first;
+ for(;add;add=next){
+ next=add->next;
+ insert_IC_fg(fg,p->prev,add);
+ }
+ next=p->next;
+ if(fg->end==p) end=1;
+ if(p->z.flags){
+ remove_IC_fg(fg,p);
+ }else{
+ type *t=new_typ();
+ t->flags=LIBCALL_CMPTYPE;
+ p->code=COMPARE;
+ p->q2.flags=KONST;
+ gval.vmax=Z0;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,LIBCALL_CMPTYPE);
+ p->typf=LIBCALL_CMPTYPE;
+ p->q1.flags=VAR;
+ p->q1.v=add_tmp_var(t);
+ p->q1.val.vmax=l2zm(0L);
+ p->prev->z=p->q1;
+ p->z.flags=0;
+ }
+ }
+ }
+ if(end||p==fg->end) break;
+ }
+ fg=fg->normalout;
+ }
+ return replaced;
+}
+#endif
+
+/* temporary fuer verschiedene Bitvektoren */
+bvtype *tmp;
+
+int in_varlist(varlist *vl,int cnt,Var *v,int flags)
+{
+ int i;
+ /*FIXME: slow */
+ for(i=0;i<cnt;i++){
+ if(vl[i].v==v&&vl[i].flags==flags) return 1;
+ }
+ return 0;
+}
+
+static void add_call_list(void)
+{
+ IC *p;
+ for(p=first_ic;p;p=p->next){
+ if(p->code==CALL&&p->call_cnt==0){
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR){
+ p->call_cnt=1;
+ p->call_list=mymalloc(sizeof(*p->call_list));
+ p->call_list[0].v=p->q1.v;
+ p->call_list[0].flags=0;
+ }
+ }
+ }
+}
+
+void calc_finfo(Var *v,int flags)
+{
+ IC *p;int i,known,maxtyp,t,c;
+ /* 128 types should be enough for everyone :-) */
+ #define TSIZE BVSIZE(128)
+ static bvtype tf[TSIZE];
+ if(!v->fi) ierror(0);
+ if(flags&CALC_USES){
+ if(v->fi->flags&ALL_USES) return;
+ free(v->fi->use_list);
+ v->fi->use_cnt=0;
+ v->fi->use_list=0;
+ memset(tf,0,TSIZE);
+ known=1;maxtyp=-1;
+ for(p=first_ic;p;p=p->next){
+ c=p->code;
+ if(p->q1.flags&DREFOBJ){
+ t=(q1typ(p)&NQ);
+ if(t>maxtyp) maxtyp=t;
+ BSET(tf,t);
+ }
+ if(p->q2.flags&DREFOBJ){
+ t=(q2typ(p)&NQ);
+ if(t>maxtyp) maxtyp=t;
+ BSET(tf,t);
+ }
+ if(c==CALL){
+ if((p->q1.flags&(VAR|DREFOBJ))!=VAR||!p->q1.v->fi||!(p->q1.v->fi->flags&ALL_USES)){
+ free(v->fi->use_list);
+ v->fi->use_cnt=0;
+ v->fi->use_list=0;
+ known=0;
+ break;
+ }else{
+ for(i=0;i<p->q1.v->fi->use_cnt;i++){
+ if(p->q1.v->fi->use_list[i].v){
+ if(!in_varlist(v->fi->use_list,v->fi->use_cnt,p->q1.v->fi->use_list[i].v,p->q1.v->fi->use_list[i].flags)){
+ v->fi->use_cnt++;
+ v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(varlist));
+ v->fi->use_list[v->fi->use_cnt-1]=p->q1.v->fi->use_list[i];
+ }
+ }else{
+ BSET(tf,p->q1.v->fi->use_list[i].flags&NQ);
+ }
+ }
+ }
+ }else{
+ for(i=0;i<p->use_cnt;i++){
+ if(p->use_list[i].v->nesting!=0) continue;
+ if(!in_varlist(v->fi->use_list,v->fi->use_cnt,p->use_list[i].v,p->use_list[i].flags)){
+ v->fi->use_cnt++;
+ v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(varlist));
+ v->fi->use_list[v->fi->use_cnt-1]=p->use_list[i];
+ }
+ }
+ }
+ }
+ for(c=0;c<=maxtyp;c++){
+ if(BTST(tf,c)){
+ v->fi->use_cnt++;
+ v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(varlist));
+ v->fi->use_list[v->fi->use_cnt-1].v=0;
+ v->fi->use_list[v->fi->use_cnt-1].flags=c;
+ }
+ }
+ if(known) v->fi->flags|=ALL_USES;
+ }
+ if(flags&CALC_CHANGES){
+ if(v->fi->flags&ALL_MODS) return;
+ free(v->fi->change_list);
+ v->fi->change_cnt=0;
+ v->fi->change_list=0;
+ memset(tf,0,TSIZE);
+ known=1;maxtyp=-1;
+ for(p=first_ic;p;p=p->next){
+ c=p->code;
+ if(p->z.flags&DREFOBJ){
+ t=(ztyp(p)&NQ);
+ if(t>maxtyp) maxtyp=t;
+ BSET(tf,t);
+ }
+ if(c==CALL){
+ if((p->q1.flags&(VAR|DREFOBJ))!=VAR||!p->q1.v->fi||!(p->q1.v->fi->flags&ALL_MODS)){
+ free(v->fi->change_list);
+ v->fi->change_cnt=0;
+ v->fi->change_list=0;
+ known=0;
+ break;
+ }else{
+ for(i=0;i<p->q1.v->fi->change_cnt;i++){
+ if(p->q1.v->fi->change_list[i].v){
+ if(!in_varlist(v->fi->change_list,v->fi->change_cnt,p->q1.v->fi->change_list[i].v,p->q1.v->fi->change_list[i].flags)){
+ v->fi->change_cnt++;
+ v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(varlist));
+ v->fi->change_list[v->fi->change_cnt-1]=p->q1.v->fi->change_list[i];
+ }
+ }else{
+ BSET(tf,p->q1.v->fi->change_list[i].flags&NQ);
+ }
+ }
+ }
+ }else{
+ for(i=0;i<p->change_cnt;i++){
+ if(p->change_list[i].v->nesting!=0) continue;
+ if(!in_varlist(v->fi->change_list,v->fi->change_cnt,p->change_list[i].v,p->change_list[i].flags)){
+ v->fi->change_cnt++;
+ v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(varlist));
+ v->fi->change_list[v->fi->change_cnt-1]=p->change_list[i];
+ }
+ }
+ }
+ }
+ for(c=0;c<=maxtyp;c++){
+ if(BTST(tf,c)){
+ v->fi->change_cnt++;
+ v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(varlist));
+ v->fi->change_list[v->fi->change_cnt-1].v=0;
+ v->fi->change_list[v->fi->change_cnt-1].flags=c;
+ }
+ }
+ if(known) v->fi->flags|=ALL_MODS;
+ }
+ if(flags&CALC_CALLS){
+ if(v->fi->flags&ALL_CALLS) return;
+ free(v->fi->call_list);
+ v->fi->call_list=0;
+ v->fi->call_cnt=0;
+ p=v->fi->opt_ic;
+ if(!p)
+ p=v->fi->first_ic;
+ for(;p;p=p->next){
+ if(p->code==CALL){
+ if(p->q1.flags&DREFOBJ) return;
+ if(!in_varlist(v->fi->call_list,v->fi->call_cnt,p->q1.v,0)){
+ v->fi->call_cnt++;
+ v->fi->call_list=myrealloc(v->fi->call_list,v->fi->call_cnt*sizeof(varlist));
+ v->fi->call_list[v->fi->call_cnt-1].v=p->q1.v;
+ v->fi->call_list[v->fi->call_cnt-1].flags=0;
+ }
+ }
+ }
+ v->fi->flags|=ALL_CALLS;
+ }
+}
+
+void used_clist(type *t,const_list *cl)
+{
+ int i;zmax l;
+
+ if(ISARRAY(t->flags)){
+ for(l=l2zm(0L);!zmleq(t->size,l)&&cl;l=zmadd(l,l2zm(1L)),cl=cl->next){
+ if(!cl->other){ierror(0);return;}
+ used_clist(t->next,cl->other);
+ }
+ return;
+ }
+ if(ISUNION(t->flags)&&!cl->tree){
+ used_clist((*t->exact->sl)[zm2l(cl->idx)].styp,cl->other);
+ return;
+ }
+ if(ISSTRUCT(t->flags)){
+ type *st;
+ if(!cl||!cl->tree){
+ for(i=0;i<t->exact->count&&cl;i++){
+ st=(*t->exact->sl)[i].styp;
+ if(!(*t->exact->sl)[i].identifier) ierror(0);
+ if(zmeqto(l2zm((long)i),cl->idx)){
+ if((*t->exact->sl)[i].identifier[0]){
+ if(cl->other) used_clist(st,cl->other);
+ cl=cl->next;
+ }
+ }
+ }
+ }
+ return;
+ }
+ if(cl->tree&&(cl->tree->o.flags&VAR))
+ used_objects(cl->tree->o.v);
+ return;
+}
+
+void used_objects(Var *v)
+{
+ int i;
+ if(v->flags&REFERENCED) return;
+ v->flags|=REFERENCED;
+ if(ISFUNC(v->vtyp->flags)){
+ IC *p;
+ if(!(v->flags&DEFINED)) return;
+ if(!v->fi) ierror(0);
+ for(i=0;i<v->fi->call_cnt;i++){
+ if(v->fi->call_list[i].v->flags&DEFINED)
+ used_objects(v->fi->call_list[i].v);
+ }
+ /*FIXME: use/change aus fi */
+ for(p=v->fi->opt_ic;p;p=p->next){
+ if(p->q1.flags&VAR) used_objects(p->q1.v);
+ if(p->q2.flags&VAR) used_objects(p->q2.v);
+ if(p->z.flags&VAR) used_objects(p->z.v);
+ }
+ }else{
+ if(v->clist) used_clist(v->vtyp,v->clist);
+ }
+}
+
+zmax recalc_start_offset;
+
+static void mark_na(bvtype *tmp,int r,int *eqto)
+{
+ int i;
+ if(r<0||r>=vcount-rcount||BTST(tmp,r)) return;
+ /*if(DEBUG&1024) printf("mark_na %s(%p):\n",vilist[r]->identifier,(void*)vilist[r]);*/
+ BSET(tmp,r);
+ for(i=0;i<vcount-rcount;i++){
+ if(eqto[i]!=r&&eqto[r]!=i) continue;
+ /*if((DEBUG&1024)&&!BTST(tmp,i)) printf(" mark_na %s(%p)\n",vilist[i]->identifier,(void*)vilist[i]);*/
+ mark_na(tmp,i,eqto);
+ }
+}
+
+/* TODO: remove ugly hack by decent exit criteria */
+static int reccheck_maxcnt;
+
+/* check if function v can not call callee */
+static int check_nonrecursive(Var *v,Var *callee)
+{
+ int i;
+ Var *f;
+ if(--reccheck_maxcnt==0) return 0;
+ if(v->fi&&(v->fi->flags&ALL_CALLS)){
+ for(i=0;i<v->fi->call_cnt;i++){
+ f=v->fi->call_list[i].v;
+ if(f==v)
+ return 0;
+ if(!check_nonrecursive(f,callee))
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static void cnv_static(Var *v)
+{
+ if((v->storage_class==AUTO||v->storage_class==REGISTER)&&zmleq(Z0,v->offset)&&v->reg==0/*&&!(v->flags&CONVPARAMETER)*/){
+ v->storage_class=STATIC;
+ v->offset=++label;
+ v->flags|=(USEDASSOURCE|USEDASDEST|DEFINED|STATICAUTO);
+ if(v->clist){free_clist(v->clist);v->clist=0;}
+ if(DEBUG&1024) printf("changing %s(%p) to static (L%ld)\n",v->identifier,v,zm2l(v->offset));
+ }
+}
+
+/* replace auto variables by statics if possible */
+void replace_statics(Var *v)
+{
+ IC *p;
+ if(DEBUG&1024) printf("replace_statics()\n");
+ if(force_statics||(v->fi&&(v->fi->flags&ALL_CALLS))){
+ if(!force_statics){
+ reccheck_maxcnt=100;
+ if(!check_nonrecursive(v,v))
+ return;
+ if(DEBUG&1024) printf("non-recursive\n");
+ }
+
+ for(p=first_ic;p;p=p->next){
+ if((p->q1.flags&(VAR|REG))==VAR) cnv_static(p->q1.v);
+ if((p->q2.flags&(VAR|REG))==VAR) cnv_static(p->q2.v);
+ if((p->z.flags&(VAR|REG))==VAR) cnv_static(p->z.v);
+
+ if(p->code==ADDRESS&&p->q1.v->storage_class==STATIC){
+ p->code=ASSIGN;
+ p->q1.flags|=VARADR;
+ p->q2.val.vmax=sizetab[p->typf2&NQ];
+ p->typf=p->typf2;
+ }
+ }
+ }
+}
+
+
+void recalc_offsets(flowgraph *g)
+/* berechnet Offsets fuer auto-Variablen neu und versucht, fuer Variablen, */
+/* die nicht gleichzeitig aktiv sind, den gleichen Platz zu belegen */
+{
+ int i,j,b,bcnt,r,*eqto,pass;size_t bsize,vsize;zmax *al,*sz;
+ bvtype **used,*tmp,*empty,*vtmp,*vpos;
+ IC *p;
+ flowgraph *fg;
+
+ if(DEBUG&1024) printf("recalculating offsets\n");
+ if(DEBUG&1024) printf("setting up arrays\n");
+ /*bsize=(basic_blocks+CHAR_BIT-1)/CHAR_BIT; /* we don's use fg->index but count from 0 */
+ bsize=BVSIZE(basic_blocks);
+ if(DEBUG&1024) printf("bsize=%lu\n",(unsigned long)bsize);
+ tmp=mymalloc(bsize);
+ al=mymalloc(sizeof(*al)*(vcount-rcount));
+ eqto=mymalloc(sizeof(int)*(vcount-rcount));
+ sz=mymalloc(sizeof(*sz)*(vcount-rcount));
+ empty=mymalloc(bsize);
+ memset(empty,0,bsize);
+ used=mymalloc(sizeof(bvtype *)*(vcount-rcount));
+ /* Tabelle, welche Variable in welchem Block belegt ist, aufbauen */
+ for(i=0;i<vcount-rcount;i++){
+ if((vilist[i]->storage_class==AUTO||vilist[i]->storage_class==REGISTER)&&zmleq(l2zm(0L),vilist[i]->offset)){
+ if(DEBUG&2048) printf("setting up for %s,%ld\n",vilist[i]->identifier,zm2l(vilist[i]->offset));
+ used[i]=mymalloc(bsize);
+ memset(used[i],0,bsize);
+ }else{
+ used[i]=0;
+ }
+ sz[i]=szof(vilist[i]->vtyp);
+ al[i]=falign(vilist[i]->vtyp);
+ eqto[i]=-1;
+ }
+ b=0; fg=g;
+ while(fg){
+ if(b>=basic_blocks) ierror(0);
+ for(i=0;i<vcount-rcount;i++){
+ if(used[i]&&(BTST(fg->av_in,i)||BTST(fg->av_out,i))){
+ BSET(used[i],b);
+ for(r=1;r<=MAXR;r++)
+ if(fg->regv[r]&&fg->regv[r]->index==i) BCLR(used[i],b);
+ }
+ }
+ for(p=fg->start;p;p=p->next){
+ if((p->q1.flags&(VAR|REG))==VAR){
+ i=p->q1.v->index;
+ if(i!=-1&&i<vcount-rcount){
+ if(i<0||i>=vcount) ierror(0);
+ if(i>=0&&used[i]){
+ BSET(used[i],b);
+ }
+ }
+ }
+ if((p->q2.flags&(VAR|REG))==VAR){
+ i=p->q2.v->index;
+ if(i!=-1&&i<vcount-rcount){
+ if(i<0||i>=vcount) ierror(0);
+ if(i>=0&&used[i]){
+ BSET(used[i],b);
+ }
+ }
+ }
+ if((p->z.flags&(VAR|REG))==VAR){
+ i=p->z.v->index;
+ if(i!=-1){
+ if(i<0||i>=vcount) ierror(0);
+ if(i>=0&&used[i]){
+ BSET(used[i],b);
+ }
+ }
+ }
+ if(p==fg->end) break;
+ }
+ fg=fg->normalout;
+ b++;
+ }
+ bcnt=b;
+
+ if(DEBUG&1024) printf("local recalc\n");
+ vsize=BVSIZE(vcount-rcount);
+ vtmp=mymalloc(vsize);
+ vpos=mymalloc(vsize);
+ j=0;
+ for(fg=g;fg;fg=fg->normalout){
+ bvcopy(vtmp,fg->av_in,vsize);
+ bvunite(vtmp,fg->av_out,vsize);
+ for(r=1;r<=MAXR;r++)
+ if(fg->regv[r]&&fg->regv[r]->index<vcount-rcount) BSET(vtmp,fg->regv[r]->index);
+ for(i=0;i<vcount-rcount;i++){
+ if(!BTST(vtmp,i)){
+ if(!used[i]||!BTST(used[i],j)||(vilist[i]->storage_class!=AUTO&&vilist[i]->storage_class!=REGISTER))
+ BSET(vtmp,i);
+ else{
+ for(r=0;r<bcnt;r++)
+ if(r!=j&&BTST(used[i],r))
+ BSET(vtmp,i);
+ }
+ }
+ }
+#if 1
+ if(DEBUG&1024){
+ printf("possible for local recalc block %d (%d):\n",j,fg->index);
+ for(i=0;i<vcount-rcount;i++)
+ if(!BTST(vtmp,i))
+ printf(" %s(%p)\n",vilist[i]->identifier,(void*)vilist[i]);
+ }
+#endif
+ for(p=fg->start;p;p=p->next){
+ if((p->z.flags&(VAR|DREFOBJ))==VAR){
+ b=p->z.v->index;
+ if(b>=0&&b<vcount-rcount&&eqto[b]<0&&!BTST(vtmp,b)){
+ /* imprecise, but should do the job */
+ IC *m;
+ /*if(DEBUG&1024) printf("checking %s(%p)\n",vilist[b]->identifier,(void*)vilist[b]);*/
+ bvcopy(vpos,vtmp,vsize);
+ for(m=p->next;m;m=m->next){
+ if(m->q1.flags&VAR) mark_na(vpos,m->q1.v->index,eqto);
+ if(m->q2.flags&VAR) mark_na(vpos,m->q2.v->index,eqto);
+ if(m->z.flags&VAR){
+ mark_na(vpos,m->z.v->index,eqto);
+ if(m->z.v->index==b) BSET(vtmp,b);
+ }
+ if(m==fg->end) break;
+ }
+ for(i=vcount-rcount-1;i>=0;i--){
+ if(!BTST(vpos,i)&&i!=b){
+ if(DEBUG&1024) printf("local memory for %s(%p) and %s(%p) equal",vilist[i]->identifier,(void *)vilist[i],vilist[b]->identifier,(void *)vilist[b]);
+ eqto[b]=i;
+ if(!zmleq(al[b],al[i])) al[i]=al[b];
+ if(!zmleq(sz[b],sz[i])) sz[i]=sz[b];
+ if(!zmleq(al[i],al[b])) al[b]=al[i];
+ if(!zmleq(sz[i],sz[b])) sz[b]=sz[i];
+ if(DEBUG&1024) printf(" sz=%ld al=%ld\n",(long)zm2l(al[i]),(long)zm2l(sz[i]));
+ BSET(vtmp,i);
+ /*bvunite(used[i],used[b],bsize);*/
+ break;
+ }
+ }
+ }
+ }
+ if(p==fg->end) break;
+ }
+ j++;
+ }
+ free(vtmp);
+ free(vpos);
+
+
+ /* schauen, ob Variablen in gleichen Speicher koennen */
+ if(DEBUG&1024) printf("looking for distinct variables\n");
+ for(i=0;i<vcount-rcount;i++){
+
+ if(!used[i]||eqto[i]>=0) continue;
+ if(!memcmp(used[i],empty,bsize)){ free(used[i]);used[i]=0;continue;}
+ for(b=i+1;b<vcount-rcount;b++){
+ if(!used[b]||eqto[b]>=0) continue;
+ if(!memcmp(used[b],empty,bsize)){ free(used[b]);used[b]=0;continue;}
+ if(DEBUG&2048) printf("comparing %s(%p) and %s(%p)\n",vilist[i]->identifier,(void *)vilist[i],vilist[b]->identifier,(void *)vilist[b]);
+
+ memcpy(tmp,used[i],bsize);
+ bvintersect(tmp,used[b],bsize);
+ if(!memcmp(tmp,empty,bsize)){
+ if(DEBUG&1024) printf("memory for %s(%p) and %s(%p) equal\n",vilist[i]->identifier,(void *)vilist[i],vilist[b]->identifier,(void *)vilist[b]);
+ eqto[b]=i;
+ if(!zmleq(al[b],al[i])) al[i]=al[b];
+ if(!zmleq(sz[b],sz[i])) sz[i]=sz[b];
+ if(!zmleq(al[i],al[b])) al[b]=al[i];
+ if(!zmleq(sz[i],sz[b])) sz[b]=sz[i];
+ bvunite(used[i],used[b],bsize);
+ }
+ }
+ }
+
+ if(DEBUG&1024) printf("propagating sz/al\n");
+ do{
+ if(DEBUG&1024) printf("ppass\n");
+ b=0;
+ for(i=0;i<vcount-rcount;i++){
+ j=i;
+ while((j=eqto[j])>=0){
+ if(!zmleq(sz[j],sz[i])){sz[i]=sz[j];b=1;j=i;if(DEBUG&1024) printf("lmset %d(%p) to sz %ld\n",i,vilist[i],zm2l(sz[i]));}
+ if(!zmleq(sz[i],sz[j])){sz[j]=sz[i];b=1;if(DEBUG&1024) printf("lmset %d(%p) to sz %ld\n",j,vilist[j],zm2l(sz[j]));}
+ if(!zmleq(al[j],al[i])){al[i]=al[j];b=1;j=i;if(DEBUG&1024) printf("lmset %d(%p) to al %ld\n",i,vilist[i],zm2l(al[i]));}
+ if(!zmleq(al[i],al[j])){al[j]=al[i];b=1;if(DEBUG&1024) printf("lmset %d(%p) to al %ld\n",j,vilist[j],zm2l(al[j]));}
+
+ }
+ }
+ }while(b);
+
+ if(DEBUG&1024) printf("final recalculating\n");
+ max_offset=recalc_start_offset;
+ for(pass=0;pass<3;pass++){
+ zmax a;
+ for(a=maxalign;!zmeqto(a,Z0);a=zmsub(a,Z1)){
+ for(i=0;i<vcount-rcount;i++){
+ if(!used[i]) continue;
+ if(!zmeqto(a,al[i])) continue;
+ if(eqto[i]>=0&&pass<2) continue;
+
+ if(pass==0){
+ if(!zmleq(sz[i],sizetab[MAXINT])&&!zmleq(sz[i],sizetab[LDOUBLE])) continue;
+ }
+ free(used[i]);
+ used[i]=0;
+ if(DEBUG&2048) printf("adjusting offset for %s,%ld(%p)\n",vilist[i]->identifier,zm2l(vilist[i]->offset),(void*)vilist[i]);
+ if(eqto[i]>=0){
+ j=eqto[i];
+ do{
+ }while(used[j]&&(j=eqto[j])>=0);
+ if(j<0) ierror(0);
+ if(!zmleq(sz[i],sz[j]))
+ {printf("%d(%p) %d(%p) %ld %ld\n",i,vilist[i],j,vilist[j],zm2l(sz[i]),zm2l(sz[j]));ierror(0);}
+ if(!zmleq(al[i],al[j]))
+ {printf("%d(%p) %d(%p) %ld %ld\n",i,vilist[i],j,vilist[j],zm2l(al[i]),zm2l(al[j]));ierror(0);}
+ vilist[i]->offset=vilist[j]->offset;
+ if(DEBUG&2048) printf("set to %ld (eqto)\n",(long)zm2l(vilist[i]->offset));
+ continue;
+ }
+ vilist[i]->offset=zmmult(zmdiv(zmadd(max_offset,zmsub(al[i],l2zm(1L))),al[i]),al[i]);
+ max_offset=zmadd(vilist[i]->offset,sz[i]);
+ if(DEBUG&2048) printf("set to %ld (std)\n",(long)zm2l(vilist[i]->offset));
+ }
+ }
+ }
+ recalc_start_offset=l2zm(0L);
+ free(used);
+ free(sz);
+ free(al);
+ free(tmp);
+ free(empty);
+ free(eqto);
+}
+void remove_IC_fg(flowgraph *g,IC *p)
+/* Entfernt IC p und beachtet Flussgraph. Ausserdem werden */
+/* use/change-Listen freigegeben. */
+{
+ if(p->q1.am||p->q2.am||p->z.am) ierror(0);
+ if(have_alias){
+ free(p->use_list);
+ free(p->change_list);
+ }
+ if(g->start==g->end){
+ g->start=g->end=0;
+ }else{
+ if(p==g->end) g->end=p->prev;
+ if(p==g->start) g->start=p->next;
+ }
+ remove_IC(p);
+}
+
+/* function to decide whether a possible const memcpy shall
+ be implemented using typ t; if noptr is non-zero decide
+ if not introducing a pointer is preferable */
+int decide_const_memcpy(IC *p,int typ,int noptr)
+{
+ zmax cnt;
+
+ /* usually int is the most efficient */
+ if(typ==CHAR){
+ }else if(typ==BESTCOPYT){
+ if((p->z.flags&(VAR|DREFOBJ))!=VAR)
+ return 0;
+ if(!zmleq(align[typ],falign(p->z.v->vtyp)))
+ return 0;
+ if(!zmeqto(zmmod(p->z.val.vmax,align[typ]),Z0))
+ return 0;
+ }else
+ return 0;
+
+ cnt=zmdiv(p->q2.val.vmax,sizetab[typ]);
+
+ if((p->z.flags&(DREFOBJ|KONST))!=DREFOBJ){
+ int sc;
+ if(p->z.flags&DREFOBJ)
+ sc=STATIC;
+ else
+ sc=p->z.v->storage_class;
+ if(sc==AUTO||sc==REGISTER){
+ /* we assume that writes on the stack can be combined */
+ if(typ==CHAR&&noptr)
+ if(zmleq(cnt,zmmult(clist_copy_pointer,sizetab[BESTCOPYT])))
+ return 1;
+ if(zmleq(cnt,l2zm(clist_copy_stack)))
+ return 1;
+ }else{
+ if(zmleq(cnt,l2zm(clist_copy_static)))
+ return 1;
+ }
+ }
+
+ if(noptr==0&&zmleq(cnt,l2zm(clist_copy_pointer)))
+ return 1;
+
+ return 0;
+}
+
+int insert_const_memcpy(flowgraph *fg)
+{
+ int changed =0;
+ flowgraph *g;
+ for(g=fg;g;g=g->normalout){
+ IC *p;
+ for(p=g->start;p;p=p->next){
+ int c=p->code;
+
+ /* TODO: finish support for PUSH */
+ if((c==ASSIGN/*||c==PUSH*/)&&(p->q1.flags&(VAR|VARADR|DREFOBJ))==VAR&&p->q1.v->clist&&is_const(p->q1.v->vtyp)){
+ zmax i,sz=p->q2.val.vmax;
+ zuchar zuc;
+ Var *v=p->q1.v;
+ type *t=v->vtyp;
+ int ok=1;
+
+ for(i=Z0;zmleq(i,sz);i=zmadd(i,Z1)){
+ if(!get_clist_byte(t,v->clist,i,&zuc))
+ ok=0;
+ }
+
+ if(ok==1){
+ int typ=0,noptr=1;
+ int a1,a2;
+ if(DEBUG&1024) {printf("can replace const memcpy:\n");pric2(stdout,p);}
+
+ if(c==ASSIGN&&(p->z.flags&(DREFOBJ|KONST))!=DREFOBJ){
+ if(decide_const_memcpy(p,BESTCOPYT,noptr))
+ typ=BESTCOPYT;
+ else if(decide_const_memcpy(p,CHAR,noptr))
+ typ=CHAR;
+ }
+ if(typ==0){
+ noptr=0;
+ if(decide_const_memcpy(p,BESTCOPYT,noptr))
+ typ=BESTCOPYT;
+ else if(decide_const_memcpy(p,CHAR,noptr))
+ typ=CHAR;
+ }
+
+ if(typ){
+ Var *ptr;
+ IC *new;
+
+ if(DEBUG&1024) printf("will do it (typ=%d noptr=%d)\n",typ,noptr);
+ if(!noptr){
+ type *pt;
+ if(p->z.flags&VAR){
+ if(p->z.flags&DREFOBJ){
+ type *new=new_typ();
+ new->flags=p->z.dtyp&NQ;
+ new->next=new_typ();
+ new->next->flags=typ;
+ pt=new;
+ }else{
+ pt=new_typ();
+ pt->flags=POINTER_TYPE(p->z.v->vtyp);
+ pt->next=clone_typ(p->z.v->vtyp);
+ }
+ }else{
+ static type ct={CHAR};
+ type *new;
+ ct.flags=typ;
+ new=new_typ();
+ new->flags=POINTER_TYPE(&ct);
+ new->next=new_typ();
+ new->next->flags=typ;
+ pt=new;
+ }
+
+ ptr=add_tmp_var(pt);
+ new=new_IC();
+ new->z.flags=VAR;
+ new->z.v=ptr;
+ new->q1=p->z;
+ if(p->z.flags&DREFOBJ){
+ new->code=ASSIGN;
+ new->q1.flags&=~DREFOBJ;
+ new->typf=ptr->vtyp->flags;
+ }else if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN){
+ new->code=ASSIGN;
+ new->q1.flags|=VARADR;
+ new->typf=ptr->vtyp->flags;
+ }else if(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER){
+ new->code=ADDRESS;
+ new->typf=p->z.v->vtyp->flags;
+ new->typf2=ptr->vtyp->flags;
+ }else
+ ierror(0);
+ new->q2.val.vmax=sizetab[new->typf];
+ insert_IC_fg(g,p->prev,new);
+ }
+ i=Z0;
+ while(!zmleq(sz,i)){
+ /* use CHAR for possibly remaining bytes */
+ if(!zmleq(zmadd(sizetab[typ],i),sz))
+ typ=CHAR;
+ new=new_IC();
+ new->code=p->code;
+ new->typf=typ;
+ new->q1.flags=KONST;
+ if(typ==CHAR){
+ if(!get_clist_byte(t,v->clist,zmadd(i,p->q1.val.vmax),&zuc))
+ ierror(0);
+ new->q1.val.vuchar=zuc;
+ }else{
+ int state;
+ gval.vmax=get_clist_int(t,v->clist,zmadd(i,p->q1.val.vmax),zm2l(sizetab[typ]),&state);
+ if(!state) ierror(0);
+ eval_const(&gval,MAXINT);
+ insert_const(&new->q1.val,typ);
+ }
+ new->q2.val.vmax=sizetab[new->typf];
+ if(new->code==ASSIGN){
+ if(noptr){
+ new->z=p->z;
+ new->z.val.vmax=zmadd(new->z.val.vmax,i);
+ }else{
+ new->z.flags=VAR|DREFOBJ;
+ new->z.v=ptr;
+ new->z.dtyp=ptr->vtyp->flags;
+ }
+ }else
+ ierror(0); /* TODO: PUSH */
+ insert_IC_fg(g,p->prev,new);
+ if(!noptr){
+ new=new_IC();
+ new->code=ADDI2P;
+ new->q1.flags=VAR;
+ new->q1.v=ptr;
+ new->z=new->q1;
+ new->q2.flags=KONST;
+ new->q2.val.vint=zm2zi(sizetab[typ]);
+ new->typf=INT;
+ new->typf2=ptr->vtyp->flags;
+ insert_IC_fg(g,p->prev,new);
+ }
+ i=zmadd(i,sizetab[typ]);
+
+ }
+ remove_IC_fg(g,p);
+ p=new;
+ changed=1;
+ }
+ }
+ }
+
+ if(p==g->end) break;
+ }
+ }
+ return changed;
+}
+
+/* combines assignments of constants into a larger type */
+void combine_const_assigns(void)
+{
+ static int ctype[BESTCOPYT],i,j;
+ IC *p=first_ic;
+
+ /* calculate table of combine types */
+ for(i=CHAR;i<BESTCOPYT;i++){
+ ctype[i]=0;
+ for(j=BESTCOPYT;j>CHAR;j--){
+ if(zmeqto(sizetab[j],zmadd(sizetab[i],sizetab[i]))){
+ if(DEBUG&1024) printf("possible combine type %s=>%s\n",typname[i],typname[j]);
+ ctype[i]=j;
+ break;
+ }
+ }
+ }
+ while(p){
+ if(p->code==ASSIGN&&(p->q1.flags&(KONST|DREFOBJ))==KONST&&(p->z.flags&(DREFOBJ|VAR))==VAR){
+ IC *p2=p->next;
+ if(p2&&p2->code==ASSIGN&&(p2->q1.flags&(KONST|DREFOBJ))==KONST&&(p2->z.flags&(DREFOBJ|VAR))==VAR&&p->z.v==p2->z.v&&p->typf==p2->typf&&zmeqto(p->q2.val.vmax,p2->q2.val.vmax)&&zmeqto(p2->z.val.vmax,zmadd(p->z.val.vmax,sizetab[p->typf&NQ]))){
+ int dt,t=p->typf&NQ,sc=p->z.v->storage_class;
+ if(t<BESTCOPYT&&(dt=ctype[t])){
+ zmax os;
+ /* for stack variables we can use the actual offset, for statics
+ we rely on the type alignment */
+ if(sc==AUTO||sc==REGISTER)
+ os=zmadd(p->z.v->offset,p->z.val.vmax);
+ else{
+ if(zmeqto(zmmod(falign(p->z.v->vtyp),align[dt]),Z0))
+ os=p->z.val.vmax;
+ else
+ os=Z1;
+ }
+ if(zmeqto(zmmod(os,align[dt]),Z0)){
+ zumax v1,v2;
+ if(DEBUG&1024){
+ printf("combine const assignment:\n");
+ pric2(stdout,p);
+ pric2(stdout,p2);
+ }
+ p->typf=dt;
+ p->q2.val.vmax=sizetab[dt];
+ eval_const(&p->q1.val,t|UNSIGNED);
+ v1=vmax;
+ eval_const(&p2->q1.val,t|UNSIGNED);
+ v2=vmax;
+ if(BIGENDIAN)
+ v1=zmlshift(v1,zmmult(sizetab[t],char_bit));
+ else
+ v2=zmlshift(v2,zmmult(sizetab[t],char_bit));
+ gval.vmax=zmor(v1,v2);
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q1.val,dt);
+ if(DEBUG&1024){printf("to:\n"); pric2(stdout,p);}
+ remove_IC(p2);
+ if(p->prev) p=p->prev; /* retry for more combining */
+ continue;
+ }
+ }
+ }
+ }
+ p=p->next;
+ }
+}
+
+
+/* allowed to create new variables */
+int early_peephole(void)
+{
+ IC *p;
+ int changed,gchanged=0,c,t;
+ do{
+ changed=0;
+ p=first_ic;
+ while(p){
+ c=p->code;
+ t=p->typf;
+ if(c==COMPARE&&(p->q2.flags&KONST)&&ISINT(p->typf)){
+ case_table *ct;
+ /* TODO: support multiple_ccs */
+ if(!multiple_ccs&&(ct=calc_case_table(p,JUMP_TABLE_DENSITY))&&ct->num>1&&ct->density==1){
+ int i;
+ for(i=0;i<ct->num;i++){
+ if(ct->labels[i]!=ct->labels[0])
+ break;
+ }
+ if(i>=ct->num){
+ IC *new;
+ static type ityp;
+ if(DEBUG&1024) printf("converting cases to range-check\n");
+ if(multiple_ccs) ierror(0);
+ new=new_IC();
+ new->code=SUB;
+ new->typf=ct->typf;
+ new->q1=p->q1;
+ new->q2.flags=KONST;
+ if(ct->typf&UNSIGNED)
+ eval_const(&ct->min,UNSIGNED|MAXINT);
+ else
+ eval_const(&ct->min,MAXINT);
+ insert_const(&new->q2.val,ct->typf);
+ new->z.flags=VAR;
+ ityp.flags=ct->typf;
+ new->z.v=add_tmp_var(clone_typ(&ityp));
+ new->z.val.vmax=l2zm(0L);
+ insert_IC(p->prev,new);
+ new=new_IC();
+ new->code=COMPARE;
+ new->q1=p->prev->z;
+ new->z.flags=0;
+ new->q2.flags=KONST;
+ new->typf=(ct->typf|UNSIGNED);
+ gval.vumax=ct->diff;
+ eval_const(&gval,UNSIGNED|MAXINT);
+ insert_const(&new->q2.val,new->typf);
+ insert_IC(p->prev,new);
+ new=new_IC();
+ new->code=BLE;
+ new->typf=ct->labels[0];
+ insert_IC(p->prev,new);
+ while(p!=ct->next_ic){
+ IC *m=p->next;
+ remove_IC(p);
+ p=m;
+ }
+ changed=1;
+ continue;
+ }
+ }
+ }
+ p=p->next;
+ }
+ gchanged|=changed;
+ }while(changed);
+ return gchanged;
+}
+
+int peephole()
+/* macht alle moeglichen Vereinfachungen/Vereinheitlichungen */
+{
+ IC *p;obj o;int t,c,null,eins,changed,done=0;
+ function_calls=0;
+ do{
+ if(DEBUG&1024) printf("searching for peephole optimizations\n");
+ changed=0;ic_count=0;
+ p=first_ic;
+ while(p){
+ c=p->code;
+ t=p->typf;
+ if(c==NOP&&!p->q1.flags&&!p->q2.flags&&!p->z.flags){
+ IC *m;
+ if(DEBUG&1024) printf("removing nop\n");
+ m=p;p=p->next;
+ remove_IC(m);
+ continue;
+ }
+ ic_count++;
+ if(c==LABEL&&report_suspicious_loops&&p->next&&p->next->code==BRA&&p->next->typf==t){
+ error(208);report_suspicious_loops=0;
+ }
+ if(c==COMPARE&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q2.val,t);
+ if(ISINT(t)&&zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))){
+ IC *p2=p->next;
+ if(p2->code==BGE){
+ vmax=l2zm(0L);insert_const(&gval,MAXINT);
+ p->q2.val=gval;p2->code=BGT;changed=1;
+ if(DEBUG&1024) printf("cmp #1 replaced by cmp #0(1)\n");
+ }else if(p2->code==BLT){
+ vmax=l2zm(0L);insert_const(&gval,MAXINT);
+ p->q2.val=gval;p2->code=BLE;changed=1;
+ if(DEBUG&1024) printf("cmp #1 replaced by cmp #0(2)\n");
+ }
+ }else if(ISINT(t)&&!(t&UNSIGNED)&&zmeqto(vmax,l2zm(-1L))){
+ IC *p2=p->next;
+ if(p2->code==BGT){
+ vmax=l2zm(0L);insert_const(&gval,MAXINT);
+ p->q2.val=gval;p2->code=BGE;changed=1;
+ if(DEBUG&1024) printf("cmp #-1 replaced by cmp #0(1)\n");
+ }else if(p2->code==BLE){
+ vmax=l2zm(0L);insert_const(&gval,MAXINT);
+ p->q2.val=gval;p2->code=BLT;changed=1;
+ if(DEBUG&1024) printf("cmp #-1 replaced by cmp #0\n(2)");
+ }
+ }else if((t&UNSIGNED)&&zmeqto(vmax,Z0)){
+ IC *p2=p->next;
+ if(p2->code==BLT){
+ if(DEBUG&1024){printf("cmp uns,#0; blt eliminated\n");pric2(stdout,p);}
+ remove_IC(p);
+ p=p2->next;
+ remove_IC(p2);
+ continue;
+ }
+ if(p2->code==BGE){
+ if(DEBUG&1024){printf("cmp uns,#0; bge to bra\n");pric2(stdout,p);}
+ remove_IC(p);
+ p2->code=BRA;
+ p=p2;
+ continue;
+ }
+ if(p2->code==BLE){
+ if(DEBUG&1024){printf("cmp uns,#0; ble to beq\n");pric2(stdout,p);}
+ p2->code=BEQ;
+ }else if(p2->code==BGT){
+ if(DEBUG&1024){printf("cmp uns,#0; bgt to bne\n");pric2(stdout,p);}
+ p2->code=BNE;
+ }
+ }else if((t&UNSIGNED)&&zmeqto(vmax,Z1)){
+ IC *p2=p->next;
+ if(p2->code==BLT){
+ if(DEBUG&1024){printf("cmp uns,#1; blt to cmp #0;beq\n");pric2(stdout,p);}
+ gval.vmax=Z0;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,p->typf);
+ p2->code=BEQ;
+ }else if(p2->code==BGE){
+ if(DEBUG&1024){printf("cmp uns,#1; bge to cmp #0;bne\n");pric2(stdout,p);}
+ gval.vmax=Z0;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,p->typf);
+ p2->code=BNE;
+ }
+ }
+ }
+ if(c>=BEQ&&c<BRA&&p->next&&p->next->code==BRA&&p->typf==p->next->typf){
+ IC *p2,*m;
+ if(DEBUG&1024){
+ printf("removing bcc followed by bra\n");
+ pric2(stdout,p);
+ }
+ m=p->next;
+ p2=p->prev;
+ remove_IC(p);
+ if(p2&&(p2->code==TEST||p2->code==COMPARE)&&p2->z.flags==0){
+ if(DEBUG&1024){
+ printf("removing comparison:\n");
+ pric2(stdout,p2);
+ }
+ remove_IC(p2);
+ }
+ p=m;
+ changed=1;
+ continue;
+ }
+ if(c==CALL) function_calls++;
+ if(p->code==COMPARE&&(p->q1.flags&(VAR|VARADR))==(VAR|VARADR)&&(p->q2.flags&(VAR|VARADR))==(VAR|VARADR)&&p->q1.v==p->q2.v){
+ IC *old=p->prev;
+ if(fold(p)){ changed=1; p=old;continue;}
+ p=p->next;continue;
+ }
+ if((p->q1.flags&(KONST|DREFOBJ))==KONST){
+ if(((p->q2.flags&(KONST|DREFOBJ))==KONST)||!p->q2.flags){
+ IC *old=p->prev;
+ if(fold(p)){ changed=1; p=old;continue;}
+ p=p->next;continue;
+ }else{
+ if(c==ADD||c==MULT||(c>=OR&&c<=AND)||(c==COMPARE&&!(p->z.flags)&&p->next&&p->next->code>=BEQ&&p->next->code<BRA)){ /* const nach rechts */
+ if(DEBUG&1024){ printf("swapped commutative op:\n");pric2(stdout,p);}
+ o=p->q1;p->q1=p->q2;p->q2=o;
+ if(c==COMPARE){
+ IC *br=p->next;
+ if(br->code==BLT) br->code=BGT;
+ else if(br->code==BLE) br->code=BGE;
+ else if(br->code==BGT) br->code=BLT;
+ else if(br->code==BGE) br->code=BLE;
+ }
+ }
+ }
+ }
+ if((p->q2.flags&(KONST|DREFOBJ))==KONST){
+ /* algebraische Optimierungen */
+ eval_const(&p->q2.val,q2typ(p));
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))) null=1; else null=0;
+ if(zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))&&zldeqto(vldouble,d2zld(1.0))) eins=1; else eins=0;
+ if(zmeqto(vmax,l2zm(-1L))&&zldeqto(vldouble,d2zld(-1.0))) eins=-1;
+ if(eins<0&&(c==MULT||c==DIV)){
+ if(DEBUG&1024){ printf("MULT/DIV with (-1) converted to MINUS:\n");pric2(stdout,p);}
+ p->code=c=MINUS;p->q2.flags=0;
+ changed=1;
+ }
+#if HAVE_POF2OPT
+ if(((c==MULT)||((c==DIV||c==MOD)&&(t&UNSIGNED)))&&ISINT(t)){
+ /* ersetzt mul etc. mit Zweierpotenzen */
+ long ln;
+ if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
+ if(ln=get_pof2(vumax)){
+ if(c==MOD){
+ vmax=zmsub(vmax,l2zm(1L));
+ p->code=c=AND;
+ }else{
+ if(c==DIV) p->code=RSHIFT; else p->code=LSHIFT;
+ vmax=l2zm(ln-1);
+ }
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ insert_const(&p->q2.val,t);
+ p->typf2=p->typf;
+ changed=1;
+ }
+ }
+ }
+#endif
+ if(c==LSHIFT||c==RSHIFT){
+ zmax size;
+ size=zmmult(sizetab[q1typ(p)&NQ],char_bit);
+ if(zmleq(size,vmax)){
+ if(c==LSHIFT||(q1typ(p)&UNSIGNED)){
+ if(DEBUG&1024){ printf("lshift converted to ASSIGN 0:\n");pric2(stdout,p);}
+ o.val.vmax=l2zm(0L);eval_const(&o.val,MAXINT);
+ insert_const(&p->q1.val,t);p->q1.flags=KONST;
+ p->code=c=ASSIGN;p->q2.flags=0;p->q2.val.vmax=sizetab[t&NQ];
+ changed=1;
+ }else{
+ if(DEBUG&1024){ printf("rshift changed to maxlength:\n");pric2(stdout,p);}
+ o.val.vmax=zmsub(size,l2zm(1L));eval_const(&o.val,MAXINT);
+ insert_const(&p->q2.val,t);
+ changed=1;
+ }
+ }
+ }
+
+ if((c==SUB||c==ADD||c==ADDI2P||c==SUBIFP)&&!(q2typ(p)&UNSIGNED)&&zmleq(vmax,l2zm(0L))&&zldleq(vldouble,d2zld(0.0))){
+ obj o;int ct=q2typ(p);
+ o=p->q2;
+ calc(MINUS,ct,&o.val,0,&o.val,0);
+ eval_const(&o.val,ct);
+ if(!zmleq(vmax,l2zm(0L))&&!zldleq(vldouble,d2zld(0.0))){
+ calc(MINUS,ct,&o.val,0,&o.val,0);
+ if(!compare_objs(&p->q2,&o,ct)){
+ if(DEBUG&1024){ printf("SUB converted to ADD:\n");pric2(stdout,p);}
+ calc(MINUS,ct,&p->q2.val,0,&p->q2.val,0);
+ if(p->code==ADD) p->code=SUB;
+ else if(p->code==SUB) p->code=ADD;
+ else if(p->code==ADDI2P) p->code=SUBIFP;
+ else if(p->code==SUBIFP) p->code=ADDI2P;
+ c=p->code;
+ changed=1;
+ }
+ }
+ }
+ if((eins>0&&(c==MULT||c==DIV))||(null&&(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==LSHIFT||c==RSHIFT||c==OR||c==XOR))){
+ if(DEBUG&1024){ printf("operation converted to simple assignment:\n");pric2(stdout,p);}
+ if(c==ADDI2P||c==SUBIFP) p->typf=t=p->typf2;
+ p->code=c=ASSIGN;p->q2.flags=0;p->q2.val.vmax=sizetab[t&NQ];
+ changed=1;
+ }
+ if(null&&(c==MULT||c==DIV||c==MOD||c==AND)){
+ if(c==DIV||c==MOD){ err_ic=p;error(210);err_ic=0;}
+ if(DEBUG&1024){ printf("operation converted to ASSIGN 0:\n");pric2(stdout,p);}
+ o.val.vmax=l2zm(0L);eval_const(&o.val,MAXINT);
+ insert_const(&p->q1.val,t);p->q1.flags=KONST;
+ p->code=c=ASSIGN;p->q2.flags=0;p->q2.val.vmax=sizetab[t&NQ];
+ changed=1;
+ }
+ if((ISINT(t)||fp_assoc)&&(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==MULT||c==LSHIFT||c==RSHIFT||c==OR||c==AND)){
+ /* assoziative Operatoren */
+ IC *n=p->next;
+ int nc,tp,tn;
+ tp=q2typ(p);
+ if(n){
+ nc=n->code;
+ tn=q2typ(n);
+ if(c==ADD&&nc==SUB) nc=ADD;
+ if(c==ADDI2P&&nc==SUBIFP) nc=ADDI2P;
+ if(c==SUB&&nc==ADD) nc=SUB;
+ if(c==SUBIFP&&nc==ADDI2P) nc=SUBIFP;
+ }
+ if(n&&nc==c&&(n->q2.flags&KONST)&&tn==tp&&(!(tn&VOLATILE))&&(p->z.flags&VAR)&&n->q1.flags==p->z.flags&&n->q1.v==p->z.v&&zmeqto(n->q1.val.vmax,p->z.val.vmax)&&!is_volatile_obj(&n->q1)&&!is_volatile_obj(&p->z)){
+ if(p->q1.flags==p->z.flags&&p->q1.v==p->z.v&&zmeqto(p->q1.val.vmax,p->z.val.vmax)&&!is_volatile_obj(&p->q1)){
+ if(n->q1.flags==n->z.flags&&n->q1.v==n->z.v&&zmeqto(n->q1.val.vmax,n->z.val.vmax)){
+ if(DEBUG&1024){ printf("using associativity(1) with:\n");pric2(stdout,p);pric2(stdout,p->next);}
+ n->q1=p->q1;
+ if(nc!=n->code){
+ gval.vmax=l2zm(0L);
+ eval_const(&gval,MAXINT);
+ insert_const(&gval,t);
+ calc(SUB,tn,&gval,&n->q2.val,&n->q2.val,0);
+ n->code=nc;
+ }
+ if(c==LSHIFT||c==RSHIFT||c==ADDI2P||c==SUB||c==SUBIFP)
+ calc(ADD,tp,&p->q2.val,&n->q2.val,&n->q2.val,0);
+ else
+ calc(c,tp,&p->q2.val,&n->q2.val,&n->q2.val,0);
+ changed=1;
+ if(DEBUG&1024) printf("must remove first operation\n");
+ n=p;p=p->next;
+ if(have_alias){ free(n->use_list); free(n->change_list); }
+ remove_IC(n);
+ continue;
+ }
+ }else{
+ if(DEBUG&1024){ printf("using associativity(2) with:\n");pric2(stdout,p);pric2(stdout,p->next);}
+ n->q1=p->q1;
+ if(nc!=n->code){
+ gval.vmax=l2zm(0L);
+ eval_const(&gval,MAXINT);
+ insert_const(&gval,t);
+ calc(SUB,tn,&gval,&n->q2.val,&n->q2.val,0);
+ n->code=nc;
+ }
+ if(c==LSHIFT||c==RSHIFT||c==ADDI2P||c==SUB||c==SUBIFP)
+ calc(ADD,tp,&p->q2.val,&n->q2.val,&n->q2.val,0);
+ else
+ calc(c,tp,&p->q2.val,&n->q2.val,&n->q2.val,0);
+ changed=1;
+ }
+ }
+ }
+ if((c==ADDI2P||c==SUBIFP)&&(p->q1.flags&VARADR)){
+ /* add #var,#const -> move #var+const */
+ union atyps val;
+ if(DEBUG&1024){printf("add/sub #var,#const changed to assign:\n");pric2(stdout,p);}
+ eval_const(&p->q2.val,t);
+ insert_const(&val,MAXINT);
+ if(c==ADDI2P)
+ calc(ADD,MAXINT,&p->q1.val,&val,&p->q1.val,0);
+ else
+ calc(SUB,MAXINT,&p->q1.val,&val,&p->q1.val,0);
+ p->code=c=ASSIGN;
+ p->q2.flags=0;
+ p->typf=t=p->typf2;
+ p->q2.val.vmax=sizetab[t&NQ];
+ changed=1;
+ }
+ if((c==ADD||c==SUB)&&ISINT(t)&&p->next&&p->next->next){
+ /*FIXME: using SCRATCH is not nice */
+ IC *p1=p->next,*p2=p1->next;
+ if(p1->code==MULT&&p2->code==ADDI2P&&
+ p1->typf==t&&p2->typf==t&&
+ (p1->q2.flags&KONST)&&(p->z.flags&(SCRATCH|DREFOBJ))==SCRATCH&&(p1->z.flags&(SCRATCH|DREFOBJ))==SCRATCH&&
+ !compare_objs(&p->z,&p1->q1,t)&&
+ !compare_objs(&p1->z,&p2->q2,t)){
+
+ if(DEBUG&1024){ printf("rearranging array-access(1):\n");pric2(stdout,p);pric2(stdout,p1);pric2(stdout,p2);}
+ p1->q1=p->q1;
+ p->q1=p2->q1;
+ p2->q1=p2->z;
+ p->z=p2->z;
+ calc(MULT,t,&p->q2.val,&p1->q2.val,&p->q2.val,0);
+ if(c==ADD) p->code=ADDI2P; else p->code=SUBIFP;
+ p->typf2=p2->typf2;
+ if(!(p->q1.flags&VARADR)){
+ /* for static addresses it is best to add the constant
+ part of the offset first (can be folded); for others
+ the constant part might better be the last, as it can
+ frequentlz be reduced bz addressing-modes */
+ if(DEBUG&1024) printf("reversing\n");
+ p2->q1=p->q1;
+ p->q1=p->z;
+ if(p->prev) p->prev->next=p1;
+ p1->prev=p->prev;
+ if(p==first_ic) first_ic=p1;
+ p->next=p2->next;
+ if(p->next) p->next->prev=p;
+ p->prev=p2;
+ p2->next=p;
+ p=p1;
+ }
+ changed=1;continue;
+ }
+ }
+ }
+ if(p->q1.flags&KONST){
+ /* algebraische Optimierungen */
+ eval_const(&p->q1.val,t);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))) null=1; else null=0;
+ if(null&&(c==DIV||c==MOD||c==LSHIFT||c==RSHIFT)){
+ if(DEBUG&1024){ printf("operation converted to ASSIGN 0:\n");pric2(stdout,p);}
+ o.val.vmax=l2zm(0L);eval_const(&o.val,MAXINT);
+ insert_const(&p->q1.val,t);p->q1.flags=KONST;
+ p->code=c=ASSIGN;p->q2.flags=0;p->q2.val.vmax=sizetab[t&NQ];
+ changed=1;
+ }
+ }
+ if(!USEQ2ASZ&&p->z.flags&&!compare_objs(&p->q2,&p->z,p->typf)){
+ if(c==ADD||c==MULT||(c>=OR&&c<=AND)){
+ obj o;
+ if(DEBUG&1024){printf("swapping objs because USEQ2ASZ\n");pric2(stdout,p);}
+ o=p->q2;p->q2=p->q1;p->q1=o;
+ /* kein changed hier! */
+ }else{pric2(stdout,p); ierror(0);}
+ }
+ if((c==ADD||c==SUB)&&p->next){
+ /*FIXME: using SCRATCH is not nice */
+ IC *p1=p->next;
+ if(p1->code==ADDI2P&&p1->typf==t&&(p->z.flags&(SCRATCH|DREFOBJ))==SCRATCH&&!compare_objs(&p->z,&p1->q2,t)&&zmleq(sizetab[p1->typf2&NQ],sizetab[p1->typf&NQ])){
+ if(DEBUG&1024){ printf("rearranging array-access(2):\n");pric2(stdout,p);pric2(stdout,p1);}
+ p1->q2=p->q1;
+ p->q1=p1->q1;
+ p->z=p1->z;
+ p1->q1=p1->z;
+ if(c==ADD) p->code=c=ADDI2P; else p->code=c=SUBIFP;
+ p->typf2=p1->typf2;
+ changed=1;continue;
+ }
+ }
+ if((c==SUB||c==DIV||c==MOD)&&!compare_objs(&p->q1,&p->q2,p->typf)){
+ /* x-x=0, x/x=1, x%x=0 */
+ if(DEBUG&1024){ printf("i-i, i/i, i%%i converted to ASSIGN 0/1:\n");pric2(stdout,p);}
+ if(c==DIV) o.val.vmax=l2zm(1L); else o.val.vmax=l2zm(0L);
+ eval_const(&o.val,MAXINT);insert_const(&p->q1.val,t);p->q1.flags=KONST;
+ p->code=c=ASSIGN;p->q2.flags=0;p->q2.val.vmax=sizetab[t&NQ];
+ changed=1;
+ }
+ if(c==ASSIGN&&(p->z.flags&VAR)&&p->z.flags==p->q1.flags&&p->z.v==p->q1.v&&zmeqto(p->z.val.vmax,p->q1.val.vmax)){
+ IC *d;
+ if(DEBUG&1024){ printf("removing redundant move:\n");pric2(stdout,p);}
+ changed=1;
+ d=p; p=p->next;
+ if(have_alias){ free(d->use_list); free(d->change_list);}
+ remove_IC(d); continue;
+ }
+#if 1
+ /* TODO: better decision when to use for which targets? */
+ if(c==CONVERT&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&(p->z.flags&(VAR|DREFOBJ))==VAR&&!is_volatile_ic(p)){
+ IC *p1=p->next;
+ if(p1&&p1->code==CONVERT&&(p->typf2&NQ)==(p1->typf&NQ)&&(p->typf&NQ)==(p1->typf2&NQ)&&zmleq(sizetab[p->typf2&NQ],sizetab[p->typf&NQ])&&!compare_objs(&p->z,&p1->q1,p->typf2)&&!is_volatile_ic(p1)&&ISFLOAT(p->typf)==ISFLOAT(p->typf2)){
+ if(DEBUG&1024){printf("propagating CONVERTS:\n");pric2(stdout,p);pric2(stdout,p1);}
+ p1->q1=p->q1;
+ p1->code=ASSIGN;
+ p1->q2.val.vmax=sizetab[p1->typf&NQ];
+ continue;
+ }
+ /* TODO: better decision when to use for which targets? */
+ if(p1&&(p1->code==ADDI2P||p1->code==SUBIFP)&&(p1->typf&NU)==(p->typf&NU)&&!compare_objs(&p->z,&p1->q2,p1->typf)&&!is_volatile_ic(p1)&&(p->typf2&NQ)>=MINADDI2P&&(p->typf2&NQ)<=MAXADDI2P&&zmleq(sizetab[p->typf2&NQ],sizetab[p->typf&NQ])){
+ if((p->typf2&UNSIGNED)&&(p->typf2&NU)>=MINADDUI2P){
+ if(DEBUG&1024){printf("propagating CONVERT/ADDI2P:\n");pric2(stdout,p);pric2(stdout,p1);}
+ p1->q2=p->q1;
+ p1->typf=p->typf2;
+ continue;
+ }
+ }
+ }
+#endif
+ if(c>=BEQ&&c<=BGT){
+ IC *p2=p->prev;
+ if(p2&&p2->code==COMPARE&&!compare_objs(&p->q1,&p2->z,0)){
+ IC *p3=p2->prev;
+ if(p3&&p3->code==c){
+ IC *p4=p3->prev;
+ if(p4->code==COMPARE&&!compare_objs(&p3->q1,&p4->z,0)
+ &&!compare_objs(&p2->q1,&p4->q1,p4->typf)&&!compare_objs(&p2->q2,&p4->q2,p4->typf)){
+ if(DEBUG&1024){printf("removing redundant compare\n");pric2(stdout,p2);pric2(stdout,p);}
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ p->typf=0;
+ p2->code=NOP;
+ p2->typf=0;
+ p2->q1.flags=p2->q2.flags=p2->z.flags=0;
+ changed=1;
+ }
+ }
+ }
+ }
+
+ if((c==ADDI2P||c==SUBIFP)&&(p->q1.flags&(VARADR|DREFOBJ))==VARADR){
+ IC *p2=p->next;
+ if(p2->code==ADDI2P&&p->typf2==p2->typf2&&!compare_objs(&p->z,&p2->q1,p->typf2)&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
+ if(DEBUG&1024){printf("rearranging ADDI2P to fold VARADR+const\n");pric2(stdout,p);pric2(stdout,p2);}
+ eval_const(&p2->q2.val,p2->typf);
+ p->q1.val.vmax=zmadd(p->q1.val.vmax,vmax);
+ p2->code=ASSIGN;
+ p2->typf=p2->typf2;
+ p2->q2.val.vmax=sizetab[p2->typf&NQ];
+ }
+ }
+
+ p=p->next;
+ }
+ if(changed) done|=changed;
+ gchanged|=changed;
+ }while(changed);
+ return done;
+}
+
+void insert_loads()
+/* Laedt Speicher in temporaere Variablen */
+{
+ IC *p,*new;
+ type t={0},v={VOID};
+ int c;
+ if(DEBUG&1024) printf("insert_loads()\n");
+ for(p=first_ic;p;p=p->next){
+ c=p->code;
+ if(p->typf&VOLATILE) continue;
+ if(p->typf2&VOLATILE) continue;
+ if(p->q2.flags||c==PUSH){
+ if((dref_cse&&(p->q1.flags&DREFOBJ)&&!(p->q1.dtyp&(PVOLATILE|VOLATILE)))||(static_cse&&(p->q1.flags&(VAR|VARADR))==VAR&&(p->q1.v->storage_class==EXTERN||p->q1.v->storage_class==STATIC))){
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=q1typ(p);
+ if(ISSCALAR(new->typf)){
+ new->q1.am=new->q2.am=new->z.am;
+ new->q1=p->q1;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[new->typf&NQ];
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ t.flags=new->typf;
+ if(ISPOINTER(new->typf)) t.next=&v; else t.next=0;
+ new->z.v=add_tmp_var(clone_typ(&t));
+ insert_IC(p->prev,new);
+ p->q1=new->z;
+ }else
+ free(new);
+ }
+ if((dref_cse&&(p->q2.flags&DREFOBJ)&&!(p->q2.dtyp&(PVOLATILE|VOLATILE)))||(static_cse&&(p->q2.flags&(VAR|VARADR))==VAR&&(p->q2.v->storage_class==EXTERN||p->q2.v->storage_class==STATIC))){
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=q2typ(p);
+ if(ISSCALAR(new->typf)){
+ new->q1.am=new->q2.am=new->z.am;
+ new->q1=p->q2;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[new->typf&NQ];
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ t.flags=new->typf;
+ if(ISPOINTER(new->typf)) t.next=&v; else t.next=0;
+ new->z.v=add_tmp_var(clone_typ(&t));
+ insert_IC(p->prev,new);
+ p->q2=new->z;
+ }else
+ free(new);
+ }
+ if(p->q2.flags&&((dref_cse&&(p->z.flags&DREFOBJ)&&!(p->z.dtyp&(PVOLATILE|VOLATILE)))||(static_cse&&(p->z.flags&(VAR|VARADR))==VAR&&(p->z.v->storage_class==EXTERN||p->z.v->storage_class==STATIC)))){
+ /* translate x op y -> mem to x op y -> tmp; move tmp -> mem */
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=ztyp(p);
+ if(ISSCALAR(new->typf)){
+ new->q1.am=new->q2.am=new->z.am;
+ new->z=p->z;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[new->typf&NQ];
+ new->q1.flags=VAR;
+ new->q1.val.vmax=l2zm(0L);
+ t.flags=new->typf;
+ if(ISPOINTER(new->typf)) t.next=&v; else t.next=0;
+ new->q1.v=add_tmp_var(clone_typ(&t));
+ insert_IC(p,new);
+ p->z=new->q1;
+ }else
+ free(new);
+ }
+ }
+ }
+}
+
+void insert_ccs(void)
+/* Fuegt Variablen fuer ccs ein. */
+{
+ IC *p; Var *v; type *t;
+ if(DEBUG&1024) printf("insert_ccs()\n");
+ for(p=first_ic;p;p=p->next){
+ if(p->code==COMPARE||p->code==TEST){
+ p->z.flags=VAR;
+ p->z.val.vmax=l2zm(0L);
+ t=new_typ();
+ t->flags=0;
+ v=add_tmp_var(t);
+ p->z.v=v;
+ p=p->next;
+ if(p->code<BEQ||p->code>BGT){
+ p=p->prev;
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ p->typf=0;
+ }else{
+ p->q1.flags=VAR;
+ p->q1.val.vmax=l2zm(0L);
+ p->q1.v=v;
+ }
+ }
+ }
+}
+
+static int to_be_inlined(Var *v)
+{
+ /* decide whether function should be inlined */
+ int c;IC *p;
+ /* no code available */
+ if(!v->fi||!v->fi->first_ic) return 0;
+ /* marked as noinline */
+ if(v->fi->flags&NO_INLINE) return 0;
+ /* returns something not in a register (FIXME) */
+ if(!ffreturn(v->vtyp->next)&&(v->vtyp->next->flags&NQ)!=VOID) return 0;
+ /* varargs function */
+ if((c=v->vtyp->exact->count)!=0&&(*v->vtyp->exact->sl)[c-1].styp->flags!=VOID)
+ return 0;
+ /* uses variable length arrays */
+ if(v->fi->flags&USES_VLA) return 0;
+ if(v->fi->inline_size>=0){
+ c=v->fi->inline_size;
+ }else{
+ for(c=0,p=v->fi->first_ic;p;p=p->next) c++;
+ }
+ /* try to always inline functions specified as inline */
+ if(v->flags&INLINEFUNC)
+ return 1;
+ if(c>inline_size) return 0;
+ /* we assume that inlining saves size if the number of arguments
+ is larger than the number of ICs + CALL +SETRETURN */
+ if(optsize&&c-2>(v->vtyp->exact->count)) return 0;
+ return 1;
+}
+
+static int depth_reached;
+
+static int cross_module_inline(int only_full)
+{
+ IC *p,*np,*new,*ip,*cp,*getreturn;
+ Var *v,*vp;
+ int i,c,firstl,lastl,more_passes=0;
+ if(DEBUG&1024) printf("cross_module_inline(only_full=%d)\n",only_full);
+ for(p=first_ic;p;){
+ np=p->next;
+ if(p->code==CALL&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&to_be_inlined(p->q1.v)){
+ zmax pushed=p->q2.val.vmax;
+ IC *gr;
+ v=p->q1.v;
+ if(only_full&&((p->q1.flags&(VAR|DREFOBJ))!=VAR||!p->q1.v->fi||!(p->q1.v->fi->flags&FULL_INLINE))){
+ depth_reached=1;
+ }else{
+ more_passes=1;
+ if(DEBUG&1024){
+ printf("inlining call to %s\n",p->q1.v->identifier);
+ for(vp=v->fi->vars;vp;vp=vp->next)
+ printf("%s(%ld)/%p\n",vp->identifier,zm2l(vp->offset),(void*)vp);
+ }
+ gr=p->next;
+ while(gr&&gr->code==NOP) gr=gr->next;
+ if(gr&&gr->code==GETRETURN){
+ getreturn=gr;
+ np=getreturn->next;
+ }else{
+ getreturn=0;
+ }
+ /* Kopien der Variablen erzeugen */
+ for(vp=v->fi->vars;vp;vp=vp->next){
+ vp->inline_copy=0;
+ }
+ cp=p;
+ /* find first and last label used */
+ firstl=lastl=0;
+ for(ip=v->fi->first_ic;ip;ip=ip->next){
+ if(ip->code>=LABEL&&ip->code<=BRA){
+ if(firstl==0||ip->typf<firstl) firstl=ip->typf;
+ if(lastl==0||ip->typf>lastl) lastl=ip->typf;
+ }
+ }
+ /* Argumente einfuegen */
+ vp=v->fi->vars;
+ for(i=0;i<p->arg_cnt;i++){
+ while(vp&&(!*vp->identifier||(zmleq(l2zm(0L),vp->offset)&&!vp->reg)||(vp->storage_class!=REGISTER&&vp->storage_class!=AUTO))) vp=vp->next;
+ if(!vp)
+ continue;
+ if(DEBUG&1024) printf("arg nr. %d to var <%s>\n",i,vp->identifier);
+ vp->inline_copy=add_tmp_var(clone_typ(vp->vtyp));
+ ip=p->arg_list[i];
+ if(ip->code==ASSIGN){
+ /* find and delete nop for register passing */
+ IC *nop;
+ if(!(ip->z.flags&VAR)||ip->z.v->reg==0) ierror(0);
+ for(nop=ip->next;nop;nop=nop->next){
+ if(nop->code==NOP&&(nop->q1.flags&(VAR|DREFOBJ))==VAR&&nop->q1.v==ip->z.v)
+ break;
+ }
+ if(!nop) ierror(0);
+ if(np==nop) np=nop->next;
+ remove_IC(nop);
+ }else if(ip->code==PUSH){
+ ip->code=ASSIGN;
+ pushed=zmsub(pushed,ip->q2.val.vmax);
+ }else{
+ pric2(stdout,ip);
+ ierror(0);
+ }
+ ip->typf&=~VOLATILE;
+ ip->z.flags=VAR;
+ ip->z.v=vp->inline_copy;
+ if((ip->z.v->vtyp->flags&NU)!=(ip->typf&NU)){
+ /* have to convert */
+ ip->typf2=ip->typf;
+ ip->typf=ip->z.v->vtyp->flags;
+ ip->code=CONVERT;
+ }
+ ip->z.val.vmax=l2zm(0L);
+ vp=vp->next;
+ }
+
+ if(!zmeqto(pushed,l2zm(0L))){
+ /* ueberfluessige PUSHs entfernen */
+ IC *m;
+ ip=p->prev;
+ while(1){
+ m=ip->prev;
+ if(ip->code==PUSH){
+ if(0/*!(c_flags[26]&USEDFLAG)&&ip->q1.flags*/) ierror(0);
+ if(!zmleq(ip->q2.val.vmax,pushed)) ierror(0);
+ pushed=zmsub(pushed,ip->q2.val.vmax);
+ if(np==ip) np=np->next;
+ remove_IC(ip);
+ if(zmeqto(pushed,l2zm(0L))) break;
+ }
+ if(!m) ierror(0);
+ ip=m;
+ }
+ }
+
+ /* Code einfuegen und Labels umschreiben */
+ ip=v->fi->first_ic;
+ while(ip){
+ Var *iv;
+ int c;
+ if(ip->code==CONVERT&&(ip->q1.flags&(VAR|DREFOBJ))==VAR&&(ip->q1.v->flags&CONVPARAMETER)&&(ip->z.flags&(VAR|DREFOBJ))==VAR&&ip->q1.v==ip->z.v){
+ if(DEBUG&1024) {printf("eliminate oldstyle CONVERT:\n");pric2(stdout,ip);}
+ ip=ip->next;
+ continue;
+ }
+ new=new_IC();
+ *new=*ip;
+ ip->copy=new;
+ c=ip->code;
+ /* evtl. ist ein IC praktisch ein SETRETURN, falls das */
+ /* Rueckgabeziel ueber Parameterzeiger angespr. wird */
+ if(ip->z.flags&VAR){
+ iv=ip->z.v;
+ if(iv->storage_class==AUTO||iv->storage_class==REGISTER||(iv->flags&STATICAUTO)){
+ if(0/*!*iv->identifier&&zmeqto(iv->offset,l2zm(0L))*/){
+ if(getreturn){
+ new->z=getreturn->z;
+ }else{
+ new->code=NOP;
+ new->q1.flags=new->q2.flags=new->z.flags=0;
+ new->typf=0;
+ }
+ }else{
+ if(!iv->inline_copy){
+ iv->inline_copy=add_tmp_var(clone_typ(iv->vtyp));
+ iv->inline_copy->reg=iv->reg;
+ }
+ new->z.v=iv->inline_copy;
+ }/*else if(iv->inline_copy) ierror(0);*/
+ }
+ }
+ /* recreate ADDRESS when inlining STATICAUTO */
+ if((new->q1.flags&(VAR|VARADR))==(VAR|VARADR)&&(new->q1.v->flags&STATICAUTO)){
+ if(new->code!=ASSIGN) ierror(0);
+ if(DEBUG&1024) printf("recreating ADDRESS from STATICAUTO:\n");
+ if(DEBUG&1024) pric2(stdout,new);
+ new->code=ADDRESS;
+ new->q1.flags&=~VARADR;
+ new->typf2=new->typf;
+ new->typf=CHAR; /* TODO: Do we restore the old type? */
+ if(DEBUG&1024) pric2(stdout,new);
+ }
+ /* Kopien aller auto/register Variablen erzeugen */
+ if(ip->q1.flags&VAR){
+ iv=ip->q1.v;
+ if(iv->storage_class==AUTO||iv->storage_class==REGISTER||(iv->flags&STATICAUTO)){
+ if(!iv->inline_copy){
+ iv->inline_copy=add_tmp_var(clone_typ(iv->vtyp));
+ iv->inline_copy->reg=iv->reg;
+ }
+ new->q1.v=iv->inline_copy;
+ if(c==ADDRESS) new->q1.v->flags|=USEDASADR;
+ }/*else if(iv->inline_copy) ierror(0);*/
+ }
+ if(ip->q2.flags&VAR){
+ iv=ip->q2.v;
+ if(iv->storage_class==AUTO||iv->storage_class==REGISTER||(iv->flags&STATICAUTO)){
+ if(!iv->inline_copy){
+ iv->inline_copy=add_tmp_var(clone_typ(iv->vtyp));
+ iv->inline_copy->reg=iv->reg;
+ }
+ new->q2.v=iv->inline_copy;
+ }/*else if(iv->inline_copy) ierror(0);*/
+ }
+ if(c==CALL){
+ int i;
+ function_calls+=1;
+ new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+ for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=ip->arg_list[i]->copy;
+ }
+ if(c>=LABEL&&c<=BRA){
+ new->typf+=label+1-firstl;
+ }
+ if(c==SETRETURN){
+ if(getreturn){
+ new->code=ASSIGN;
+ new->z=getreturn->z;
+ }else{
+ new->code=NOP;
+ new->q1.flags=new->q2.flags=new->z.flags=0;
+ new->typf=0;
+ }
+ }
+ new->q1.flags&=~SCRATCH;
+ new->q2.flags&=~SCRATCH;
+ new->z.flags&=~SCRATCH;
+ if(new->code==ASSIGN&&!new->q1.flags) ierror(0);
+ insert_IC(cp,new);
+ cp=new;
+ ip=ip->next;
+ }
+
+ label+=lastl-firstl+1;
+ remove_IC(p);
+ if(getreturn) remove_IC(getreturn);
+ }
+ }
+ p=np;
+ }
+
+ return more_passes;
+}
+
+#endif
+#define FREEAV free(av_globals);free(av_statics);free(av_drefs);free(av_address);
+void optimize(long flags,Var *function)
+/* flags: 1=Register, 2=optimize, 4=cse/cp, 8=constant_propagation, */
+/* 16=dead_assignments, 32=global-optimizations */
+/* 64=blockweise Registervergabe, 128=loop_optimizations (nur */
+/* in Verbindung mit 32), 256=recalc_offsets */
+{
+#ifndef NO_OPTIMIZER
+ flowgraph *g,*fg=0;
+ int r,i,pass=0,mustrepeat,intask;
+ int lc_freed,lc_done=0;
+ if(!function) ierror(0);
+ norek=nocall=0;
+ report_suspicious_loops=report_weird_code=1;
+ if(!strcmp(function->identifier,"main")){norek=1;nocall=1;}
+ /* falls main() rekursiv aufgerufen werden kann, muss nomain==0 sein */
+
+ intask=(function->vattr&&strstr(function->vattr,"taskprio("));
+
+
+#else
+
+ flags&=1;
+
+#endif
+
+
+ if(flags&2){
+#ifndef NO_OPTIMIZER
+ if(DEBUG&1024) printf("\nOptimizing function %s\n",function->identifier);
+ /* Variablen fuer ccs einsetzen. */
+ if(cross_module&&(flags&4096)){
+ int i,notdone=1;
+ for(i=0;notdone;i++){
+ depth_reached=0;
+ notdone=cross_module_inline(i>=inline_depth);
+ }
+ if(!depth_reached){
+ if(!function->fi) function->fi=new_fi();
+ function->fi->flags|=FULL_INLINE;
+ if(DEBUG&1024) printf("function %s set to full-inline\n",function->identifier);
+ }
+ }
+ if(multiple_ccs) insert_ccs();
+ /* Speicherzugriffe in extra tmp-Vars umleiten, wegen cse */
+ if(flags&4) insert_loads();
+ /* nur ein pass, wenn nur lokale Optimierungen */
+ if(!(flags&32)) maxoptpasses=1;
+ do{
+ gchanged=0;pass++;
+ av_globals=av_statics=av_address=av_drefs=0;
+ ae_globals=ae_statics=ae_address=ae_drefs=0;
+ cp_globals=cp_statics=cp_address=cp_drefs=0;
+ dlist=0;vilist=0;elist=0;
+
+ if(DEBUG&1024) printf("\noptimizer (function %s) pass %d\n",function->identifier,pass);
+ early_peephole();
+ num_vars();
+ peephole();
+ fg=jump_optimization();
+ create_alias(fg);
+ if(DEBUG&2048) print_vi();
+
+#if 0
+ if(DEBUG&1024) printf("range analysis\n");
+ range_analysis(fg);
+ myfree(rangebuf);
+ rangebuf=0;
+#endif
+
+ if(flags&8){
+#if 0
+ do{
+ num_defs();
+ if(flags&32){
+ reaching_definitions(fg);
+ if(DEBUG&1024) print_flowgraph(fg);
+ r=constant_propagation(fg,1);
+ }else{
+ r=constant_propagation(fg,0);
+ }
+ if(DEBUG&1024) {printf("constant_propagation returned %d\n",r);print_flowgraph(fg);}
+ if(r){
+ if(peephole()){free_flowgraph(fg);fg=jump_optimization();}
+ }
+ if(r&2){
+ if(DEBUG&1024) printf("must repeat num_vars\n");
+ free(vilist);
+ FREEAV;
+ num_vars();
+ }
+ }while(r);
+#endif
+ num_defs();
+ mustrepeat=0;
+
+
+ if(DEBUG&1024) printf("trying constant propagation\n");
+ if(DEBUG&1024) print_flowgraph(fg);
+ if((flags&32)&&!(disable&4))
+ reaching_definitions(fg);
+ for(g=fg;g;g=g->normalout){
+ do{
+ r=constant_propagation(g,(flags&32)&&!(disable&4));
+ gchanged|=r;
+ if(r){
+ IC *p;
+ if(r&2) mustrepeat=1;
+ r=0;
+ for(p=g->start;p;p=p->next){
+ if((p->q1.flags&(KONST|DREFOBJ))==KONST&&(!p->q2.flags||(p->q2.flags&(KONST|DREFOBJ))==KONST)){
+ if(p->code!=TEST&&p->code!=COMPARE&&fold(p)) r=1;
+ }
+ if(p==g->end) break;
+ }
+ }
+ }while(r);
+ }
+ if(DEBUG&1024) print_flowgraph(fg);
+ free(rd_matrix);
+ free(var_defs);
+ free(defs_kill);
+ free(defs_gen);
+ free(dlist);
+ free_flowgraph(fg);
+ if(mustrepeat){
+ if(DEBUG&1024) printf("must repeat num_vars()\n");
+ free(vilist);
+ FREEAV;
+ early_peephole();
+ num_vars();
+ }
+ peephole();
+ fg=jump_optimization();
+ }
+ if(flags&4){
+ int repeat;
+
+ if(early_eff_ics&&!no_eff_ics)
+ mark_eff_ics();
+
+ do{
+ do{
+ num_exp();
+ if(DEBUG&1024) print_flowgraph(fg);
+ if(disable&32)
+ repeat=r=0;
+ else
+ repeat=r=cse(fg,0); /* local cse */
+ if(DEBUG&1024) printf("local cse returned %d\n",r);
+ gchanged|=r;
+ if(r){ /* neue Variablen eingefuegt */
+ if(DEBUG&1024) printf("must repeat num_vars\n");
+ free(vilist);
+ FREEAV;
+ num_vars();
+ }
+ do{
+ num_copies();
+ if(DEBUG&1024) print_flowgraph(fg);
+ if(disable&128)
+ r=0;
+ else
+ r=copy_propagation(fg,0); /* copy propagation */
+ if(DEBUG&1024) printf("local copy propagation returned %d\n",r);
+ if(r&2){
+ if(DEBUG&1024) printf("must repeat num_vars\n");
+ free(vilist);
+ FREEAV;
+ num_vars();
+ }
+ gchanged|=r;repeat|=r;
+ }while(r);
+ }while(repeat);
+ repeat=0;
+ if(flags&32){
+ num_exp();
+ if(DEBUG&1024) print_flowgraph(fg);
+ available_expressions(fg);
+ if(DEBUG&1024) print_flowgraph(fg);
+ if(disable&48)
+ r=0;
+ else
+ r=cse(fg,1);
+ gchanged|=r;repeat|=r;
+ if(DEBUG&1024) printf("global cse returned %d\n",r);
+ if(r){ /* neue Variablen eingefuegt */
+ if(DEBUG&1024) printf("must repeat num_vars\n");
+ free(vilist);
+ FREEAV;
+ num_vars();
+ gchanged|=r;repeat|=r;
+ do{
+ num_copies();
+ if(DEBUG&1024) print_flowgraph(fg);
+ if(disable&128)
+ r=0;
+ else
+ r=copy_propagation(fg,0); /* copy propagation */
+ if(DEBUG&1024) printf("local copy propagation returned %d\n",r);
+ if(r&2){
+ if(DEBUG&1024) printf("must repeat num_vars\n");
+ free(vilist);
+ FREEAV;
+ num_vars();
+ }
+ gchanged|=r;repeat|=r;
+ }while(r);
+ }
+ num_copies();
+ available_copies(fg);
+ if(DEBUG&1024) print_flowgraph(fg);
+ if(disable&192)
+ r=0;
+ else
+ r=copy_propagation(fg,1); /* copy propagation */
+ if(DEBUG&1024) printf("global copy propagation returned %d\n",r);
+ if(r&2){
+ if(DEBUG&1024) printf("must repeat num_vars\n");
+ free(vilist);
+ FREEAV;
+ num_vars();
+ }
+ gchanged|=r;repeat|=r;
+ }
+ }while(0/*repeat*/);
+ }
+ if((flags&160)==160){
+ if(!no_eff_ics)
+ mark_eff_ics();
+
+ r=loop_optimizations(fg);
+ gchanged|=r;
+ fg=jump_optimization();
+ }
+ if((flags&16)||((flags&1)&&pass>=maxoptpasses)){
+ /* num_vars();*/
+ free_alias(fg);
+ create_alias(fg);
+ active_vars(fg);
+ if(DEBUG&1024) print_flowgraph(fg);
+ if((flags&16)&&pass<=maxoptpasses){
+ r=dead_assignments(fg);
+ if(DEBUG&1024) printf("dead_assignments returned %d\n",r);
+ gchanged|=r;
+ }
+ }
+
+ if(!gchanged){
+ int r;
+ r=insert_const_memcpy(fg);
+ if(r){
+ gchanged|=1;
+ pass--;
+ }
+ }
+
+#if HAVE_LIBCALLS
+ /* if no further optimizations are found, insert libcalls
+ and look some more */
+ if(!lc_done&&(!gchanged||pass>=maxoptpasses)){
+ int r;
+ r=insert_libcalls(fg);
+ lc_done=1;
+ if(r){
+ gchanged|=1;
+ pass--;
+ }
+ }
+#endif
+
+ if((!gchanged||pass>=maxoptpasses)){
+ /* Funktion evtl. fuer inlining vorbereiten und */
+ /* Registervergabe */
+ int varargs=0,c;
+ if((c=function->vtyp->exact->count)!=0&&(*function->vtyp->exact->sl)[c-1].styp->flags!=VOID)
+ varargs=1;
+
+ /* default-Wert fuer inline-Entscheidung */
+ if(!cross_module&&!varargs&&(flags&4096)&&(only_inline||ic_count<=inline_size)){
+ /* fuer function inlining vorbereiten */
+ IC *p,*new;
+ if(DEBUG&1024) printf("function <%s> prepared for inlining(ic_count=%d)\n",function->identifier,ic_count);
+ if(!function->fi) function->fi=new_fi();
+ function->fi->first_ic=first_ic;
+ function->fi->last_ic=last_ic;
+ first_ic=last_ic=0;
+ p=function->fi->first_ic;
+ while(p){
+ new=new_IC();
+ memcpy(new,p,ICS);
+ p->copy=new;
+ if((p->code>=BEQ&&p->code<=BRA)||p->code==LABEL)
+ new->typf-=lastlabel;
+ new->q1.flags&=~SCRATCH;
+ new->q2.flags&=~SCRATCH;
+ new->z.flags&=~SCRATCH;
+ add_IC(new);
+ new->file=p->file;
+ new->line=p->line;
+ if(new->code==CALL){
+ int i;
+ new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+ for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=p->arg_list[i]->copy;
+ }
+ p=p->next;
+ }
+ p=first_ic;first_ic=function->fi->first_ic;function->fi->first_ic=p;
+ p=last_ic;last_ic=function->fi->last_ic;function->fi->last_ic=p;
+ function->fi->vars=0;
+ }
+
+ if(cross_module) calc_finfo(function,CALC_USES|CALC_CHANGES|(prefer_statics?CALC_CALLS:0));
+
+
+ if(flags&1){
+ local_combine(fg);
+ if(DEBUG&1024) print_flowgraph(fg);
+ if(coloring){
+#ifdef ALEX_REG
+ if(DEBUG&1024) print_flowgraph(fg);
+ loops(fg,1);
+ num_defs();
+ reaching_definitions(fg);
+ GCAssignRegs(fg,function->identifier);
+ {
+ int stack_used;IC *p;
+#if 1
+ for(p=pFg->start;p;p=p->next){
+ if((p->q1.flags&(REG|VAR))==VAR&&zmleq(l2zm(0L),p->q1.v->offset))
+ break;
+ if((p->q2.flags&(REG|VAR))==VAR&&zmleq(l2zm(0L),p->q2.v->offset))
+ break;
+ if((p->z.flags&(REG|VAR))==VAR&&zmleq(l2zm(0L),p->z.v->offset))
+ break;
+ }
+ if(!p) max_offset=l2zm(0L);
+#endif
+ }
+
+ fg = pFg;
+#else
+ ierror(0);
+#endif
+ }else{
+ local_regs(fg);
+ if(DEBUG&1024) print_flowgraph(fg);
+ loops(fg,1);
+ if(DEBUG&1024) print_flowgraph(fg);
+ fg=create_loop_headers(fg,1);
+ if(DEBUG&1024) print_flowgraph(fg);
+ fg=create_loop_footers(fg,1);
+ if(DEBUG&1024) print_flowgraph(fg);
+ if(!(disable&8192))
+ create_const_vars(fg);
+ loop_regs(fg,intask);
+ if(DEBUG&1024) print_flowgraph(fg);
+#if 0
+ if(flags&64){
+ block_regs(fg);
+ if(DEBUG&1024) print_flowgraph(fg);
+ }
+#endif
+ /* calculate optimized size for cross-module-inlining */
+ {
+ IC *p;
+ if(!function->fi) function->fi=new_fi();
+ function->fi->inline_size=0;
+ for(p=first_ic;p;p=p->next) function->fi->inline_size++;
+ if(DEBUG&1024) printf("inline_size=%ld\n",function->fi->inline_size);
+ }
+
+ insert_regs(fg);
+ insert_saves(fg);
+ if(prefer_statics||force_statics) replace_statics(function);
+
+ if(flags&256) recalc_offsets(fg);
+ free_const_vars();
+ }
+ }
+ }
+
+ free_alias(fg);
+ free_flowgraph(fg);
+ free(vilist);
+ FREEAV;
+
+ if((flags&32)&&gchanged&&pass>=maxoptpasses) error(172,maxoptpasses);
+
+ }while(gchanged&&pass<maxoptpasses);
+ /* nur, um nochmal ueberfluessige Labels zu entfernen */
+ fg=construct_flowgraph();
+ free_flowgraph(fg);
+ combine_const_assigns();
+
+#endif
+
+ }else{
+ /* keine Optimierungen */
+ if(flags&1) simple_regs();
+ load_simple_reg_parms();
+ }
+#ifndef NO_OPTIMIZER
+ add_call_list();
+#endif
+
+ lastlabel=label;
+}
+
+
+
diff --git a/opt.h b/opt.h
new file mode 100644
index 0000000..528efdf
--- /dev/null
+++ b/opt.h
@@ -0,0 +1,171 @@
+/* $VER: vbcc (opt.h) $Revision: 1.4 $ */
+
+#include "supp.h"
+
+extern int gchanged; /* Merker, ob Optimierungslauf etwas geaendert hat */
+extern int norek; /* diese Funktion wird nicht rekursiv auf */
+extern int nocall; /* diese Funktion kehrt nicht zum Caller zurueck */
+extern int inr; /* number of num_Vars iteration */
+
+/* temporary fuer verschiedene Bitvektoren */
+extern bvtype *tmp;
+
+/* fuer aktive Variablen */
+extern Var **vilist;
+extern unsigned int vcount; /* 0..vcount-rcount-1: vars, vcount-rcount..vcount: DREFOBJs */
+extern unsigned int rcount;
+extern size_t vsize;
+extern bvtype *av_globals,*av_address,*av_statics,*av_drefs;
+extern int report_dead_statements;
+
+/* fuer verfuegbare Definitionen */
+extern unsigned int dcount;
+extern size_t dsize;
+extern IC **dlist;
+extern bvtype **var_defs,**var_undefs;
+extern bvtype **defs_kill,**defs_gen;
+extern bvtype *rd_defs,*rd_tmp;
+extern bvtype *rd_matrix;
+#define UNDEF(x) (x+dcount)
+
+/* fuer verfuegbare Ausdruecke */
+extern IC **elist;
+extern unsigned int ecount;
+extern size_t esize;
+extern bvtype *ae_globals,*ae_address,*ae_statics,*ae_drefs;
+
+/* fuer verfuegbare Kopien */
+extern unsigned int ccount;
+extern size_t csize;
+extern IC **clist;
+
+/* fuer frequency-reduction */
+extern bvtype *inloop,*invariant;
+
+/* alle Assignments, globaler oder Adr. fuer propagation etc. */
+extern bvtype *cp_globals,*cp_address,*cp_statics,*cp_drefs,*cp_act,*cp_dest;
+/* alle Kopieranweisungen, die eine best. Variable als Quelle haben */
+extern bvtype **copies;
+
+extern int have_alias;
+extern int static_cse,dref_cse;
+
+typedef struct {
+ union atyps min,max;
+} range;
+
+extern range *rangebuf;
+
+typedef struct flowgraph{
+ IC *start,*end;
+ struct flowgraph *normalout,*branchout;
+ struct flowlist *in;
+ int index;
+ /* Letzter Block der Schleife, falls Block Start einer Schleife ist */
+ struct flowgraph *loopend;
+ /* Anzahl Funktionsaufrufe im Block/der Schleife */
+ int calls,loop_calls;
+ /* Bitvektoren fuer aktive Variablen, reaching-definitions,
+ available-expressions und available-copies */
+ bvtype *av_in,*av_out,*av_gen,*av_kill;
+ bvtype *rd_in,*rd_out,*rd_gen,*rd_kill;
+ bvtype *ae_in,*ae_out,*ae_gen,*ae_kill;
+ bvtype *cp_in,*cp_out,*cp_gen,*cp_kill;
+ /* points-to-info */
+ bvtype **pt;
+ /* range-info */
+ range *ra_normalout,*ra_branchout;
+ /* Registervariablen */
+ Var *regv[MAXR+1];
+ /* Merker, ob Register gebraucht wurde; MACR+1 Bits */
+ bvtype regused[RSIZE/sizeof(bvtype)];
+#ifdef ALEX_REG
+ int loop_depth; /* schleifentiefe des blocks. Wird nur fuer echte Schleifen gezaehlt. */
+#endif
+} flowgraph;
+
+extern unsigned int basic_blocks;
+
+typedef struct flowlist{
+ flowgraph *graph;
+ struct flowlist *next;
+} flowlist;
+
+int compare_const(union atyps *q1,union atyps *q2,int t);
+int compare_objs(obj *o1,obj *o2,int t);
+void simple_regs(void);
+void load_simple_reg_parms(void);
+void remove_IC_fg(flowgraph *g,IC *p);
+
+extern int lastlabel;
+
+flowgraph *new_flowgraph(void);
+flowgraph *construct_flowgraph(void);
+void print_av(bvtype *bitvector);
+void print_rd(bvtype *bitvector);
+void print_ae(bvtype *bitvector);
+void print_cp(bvtype *bitvector);
+void print_flowgraph(flowgraph *g);
+void free_flowgraph(flowgraph *g);
+void num_vars(void);
+void print_vi(void);
+void av_change(IC *p,bvtype *use,bvtype *def);
+void av_update(IC *,bvtype *);
+void active_vars(flowgraph *fg);
+int dead_assignments(flowgraph *fg);
+void insert_IC(IC *p,IC *new);
+void insert_IC_fg(flowgraph *fg,IC *p,IC *new);
+void insert_allocreg(flowgraph *fg,IC *p,int code,int reg);
+void used_objects(Var *);
+void used_clist(type *,const_list *);
+void fix_shortop(flowgraph *,IC *);
+
+extern Var *lregv[MAXR+1],*first_const,*last_const;
+extern flowgraph *lfg;
+
+extern int report_weird_code,report_suspicious_loops,pointer_call;
+
+int replace_local_reg(obj *);
+void local_regs(flowgraph *);
+void local_combine(flowgraph *);
+void create_const_vars(flowgraph *);
+void free_const_vars(void);
+void loop_regs(flowgraph *,int);
+void block_regs(flowgraph *);
+void insert_saves(flowgraph *);
+flowgraph *jump_optimization(void);
+void num_defs(void);
+void reaching_definitions(flowgraph *);
+void rd_change(IC *);
+void calc(int c,int t,union atyps *q1,union atyps *q2,union atyps *z,IC *p);
+int fold(IC *p);
+int peephole(void);
+int propagate(IC *p,obj *o,int replace,int global);
+int constant_propagation(flowgraph *fg,int global);
+int compare_exp(const void *a1,const void *a2);
+void num_exp(void);
+void available_expressions(flowgraph *fg);
+void available_copies(flowgraph *fg);
+int cse(flowgraph *fg,int global);
+void num_copies(void);
+int copy_propagation(flowgraph *fg,int global);
+int loops(flowgraph *fg,int mode);
+flowgraph *create_loop_headers(flowgraph *fg,int av);
+flowgraph *create_loop_footers(flowgraph *fg,int av);
+void insert_regs(flowgraph *fg);
+void recalc_offsets(flowgraph *fg);
+void optimize(long flags,Var *function);
+int loop_optimizations(flowgraph *fg);
+int decide_reverse(zmax);
+void range_analysis(flowgraph *fg);
+void ic_uses(IC *p,bvtype *result);
+void ic_changes(IC *p,bvtype *result);
+void create_alias(flowgraph *fg);
+void free_alias(flowgraph *fg);
+void update_alias(Var *old,Var *new);
+void print_pt(bvtype **);
+void free_pt(bvtype **);
+#define CALC_CALLS 1
+#define CALC_USES 2
+#define CALC_CHANGES 4
+void calc_finfo(Var *,int);
diff --git a/osek_supp.h b/osek_supp.h
new file mode 100755
index 0000000..bda8d32
--- /dev/null
+++ b/osek_supp.h
@@ -0,0 +1,13 @@
+/* used for special operating system support */
+extern bvtype task_preempt_regs[],task_schedule_regs[];
+typedef struct tasklist {
+ struct Var *v;
+ int prio;
+ int taskid;
+ enum {NON_PREEMPTIVE=1,DOES_BLOCK=2,CALLS_SCHED=4,ISR=8} flags;
+ bvtype context[BVSIZE(MAXR+1)/sizeof(bvtype)];
+ bvtype preempt_context[BVSIZE(MAXR+1)/sizeof(bvtype)];
+ bvtype schedule_context[BVSIZE(MAXR+1)/sizeof(bvtype)];
+ bvtype unsaved_context[BVSIZE(MAXR+1)/sizeof(bvtype)];
+} tasklist;
+
diff --git a/osekrm.c b/osekrm.c
new file mode 100644
index 0000000..62c5528
--- /dev/null
+++ b/osekrm.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BSIZE 4196
+char buf[BSIZE];
+
+int main()
+{
+ int nest=0;
+ while(fgets(buf,BSIZE,stdin)){
+ if(nest==0){
+ fputs(buf,stdout);
+ if(!strncmp(buf,"#if HAVE_OSEK",12)||!strncmp(buf,"#ifdef HAVE_MISRA",17)||!strncmp(buf,"#ifdef HAVE_ECPP",16))
+ nest++;
+ }else{
+ if(!strncmp(buf,"#endif",6))
+ nest--;
+ if(!strncmp(buf,"#if",3))
+ nest++;
+ if(nest==1&&!strncmp(buf,"#else",5))
+ fputs("illegal #else found",stderr);
+ if(nest==1&&!strncmp(buf,"#elif",5))
+ fputs("illegal #elif found",stderr);
+ if(nest==0)
+ fputs(buf,stdout);
+ else
+ puts("/* removed */");
+ }
+ }
+ return 0;
+}
+
diff --git a/parse_expr.c b/parse_expr.c
new file mode 100644
index 0000000..5669c07
--- /dev/null
+++ b/parse_expr.c
@@ -0,0 +1,1050 @@
+/* $VER: vbcc (parse_expr.c) $Revision: 1.22 $ */
+
+#include "vbcc_cpp.h"
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+np new_node(void)
+{
+ np p=mymalloc(NODES);
+ p->flags=0;
+ p->lvalue=0;
+ p->sidefx=0;
+ p->ntyp=0;
+ p->left=0;
+ p->right=0;
+ p->alist=0;
+ p->identifier=0;
+ p->o.flags=0;
+ return p;
+}
+
+np expression(void)
+/* Komma-Ausdruecke */
+{
+ np left,right,new;
+ left=assignment_expression();
+ if(!left->flags) return 0;
+ killsp();
+ while(ctok->type==COMMA){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ next_token();
+ killsp();
+ right=assignment_expression();
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->ntyp=0;
+ new->flags=KOMMA;
+ left=new;
+ killsp();
+ }
+ return left;
+}
+np assignment_expression(void)
+/* Zuweisungsausdruecke */
+{
+ np left,new;int c=ASSIGNOP,op;
+ left=conditional_expression();
+ killsp();
+ switch(ctok->type){
+ case ASGN: c=ASSIGN;break;
+ case ASSTAR: op=MULT;break;
+ case ASSLASH: op=DIV;break;
+ case ASPCT: op=MOD;break;
+ case ASPLUS: op=ADD;break;
+ case ASMINUS: op=SUB;break;
+ case ASAND: op=AND;break;
+ case ASCIRC: op=XOR;break;
+ case ASOR: op=OR;break;
+ case ASLSH: op=LSHIFT;break;
+ case ASRSH: op=RSHIFT;break;
+ default:
+ return left;
+ }
+ next_token();
+ new=new_node();
+ new->left=left;
+ new->ntyp=0;
+ if(c==ASSIGN){
+ new->right=assignment_expression();
+ new->flags=ASSIGN;
+ }else{
+ /* ASSIGNOP(a,b)->ASSIGN(a,OP(a,b)) */
+ new->flags=ASSIGNOP; /* nur um zum Merken, dass nur einmal */
+ /* ausgewertet werden darf */
+ new->right=new_node();
+ new->right->left=left;
+ new->right->right=assignment_expression();
+ new->right->ntyp=0;
+ new->right->flags=op;
+ }
+ return new;
+}
+np conditional_expression(void)
+/* Erledigt ? : */
+{
+ np left,new;
+ left=logical_or_expression();
+ killsp();
+ if(ctok->type==QUEST){
+ next_token();killsp();
+ new=new_node();
+ new->flags=COND;
+ new->ntyp=0;
+ new->left=left;
+ new->right=new_node();
+ new->right->flags=COLON;
+ new->right->ntyp=0;
+ new->right->left=expression();
+ killsp();
+ if(ctok->type==T_COLON){next_token();killsp();} else error(70);
+ new->right->right=conditional_expression();
+ left=new;
+ killsp();
+ }
+ return left;
+}
+np logical_or_expression(void)
+/* Erledigt || */
+{
+ np left,right,new;int bra;
+ if(ctok->type==LPAR) bra=1; else bra=0;
+ left=logical_and_expression();
+ killsp();
+ while(ctok->type==T_LOR){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ next_token();
+ killsp();
+ if(ctok->type==LPAR) bra=1; else bra=0;
+ right=logical_and_expression();
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->flags=LOR;
+ new->ntyp=0;
+ left=new;
+ killsp();
+ if(ctok->type==T_LAND) error(222);
+ }
+ return left;
+}
+np logical_and_expression(void)
+/* Erledigt && */
+{
+ np left,right,new;int bra;
+ if(ctok->type==LPAR) bra=1; else bra=0;
+ left=inclusive_or_expression();
+ killsp();
+ while(ctok->type==T_LAND){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ next_token();
+ killsp();
+ if(ctok->type==LPAR) bra=1; else bra=0;
+ right=inclusive_or_expression();
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->flags=LAND;
+ new->ntyp=0;
+ left=new;
+ killsp();
+ if(ctok->type==T_LOR) error(222);
+ }
+ return left;
+}
+np inclusive_or_expression(void)
+/* Erledigt | */
+{
+ np left,right,new;
+ left=exclusive_or_expression();
+ killsp();
+ while(ctok->type==T_OR){
+ next_token();
+ killsp();
+ right=exclusive_or_expression();
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->flags=OR;
+ new->ntyp=0;
+ left=new;
+ killsp();
+ }
+ return left;
+}
+np exclusive_or_expression(void)
+/* Erledigt ^ */
+{
+ np left,right,new;
+ left=and_expression();
+ killsp();
+ while(ctok->type==CIRC){
+ next_token();
+ killsp();
+ right=and_expression();
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->flags=XOR;
+ new->ntyp=0;
+ left=new;
+ killsp();
+ }
+ return left;
+}
+np and_expression(void)
+
+/* Erledigt & */
+{
+ np left,right,new;
+ left=equality_expression();
+ killsp();
+ while(ctok->type==T_AND){
+ next_token();
+ killsp();
+ right=equality_expression();
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->flags=AND;
+ new->ntyp=0;
+ left=new;
+ killsp();
+ }
+ return left;
+}
+np equality_expression(void)
+/* Erledigt == und != */
+{
+ np left,right,new;int c;
+ left=relational_expression();
+ killsp();
+ while(ctok->type==SAME||ctok->type==NEQ){
+ if(ctok->type==NEQ) c=INEQUAL; else c=EQUAL;
+ next_token();
+ killsp();
+ right=relational_expression();
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->flags=c;
+ new->ntyp=0;
+ left=new;
+ killsp();
+ }
+ return left;
+}
+np relational_expression(void)
+/* Erledigt <,>,<=,>= */
+{
+ np left,right,new;int c;
+ left=shift_expression();
+ killsp();
+ while(ctok->type==LT||ctok->type==GT||ctok->type==LEQ||ctok->type==GEQ){
+ if(ctok->type==LT) c=LESS;
+ else if(ctok->type==GT) c=GREATER;
+ else if(ctok->type==LEQ) c=LESSEQ;
+ else c=GREATEREQ;
+ next_token();
+ killsp();
+ right=shift_expression();
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->flags=c;
+ new->ntyp=0;
+ left=new;
+ killsp();
+ }
+ return left;
+}
+np shift_expression(void)
+/* Erledigt <<,>> */
+{
+ np left,right,new;int c;
+ left=additive_expression();
+ killsp();
+ while(ctok->type==LSH||ctok->type==RSH){
+ if(ctok->type==LSH)
+ c=LSHIFT;
+ else
+ c=RSHIFT;
+ next_token();
+ killsp();
+ right=additive_expression();
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->flags=c;
+ new->ntyp=0;
+ left=new;
+ killsp();
+ }
+ return left;
+}
+np additive_expression(void)
+/* Erledigt +,- */
+{
+ np left,right,new;int c;
+ left=multiplicative_expression();
+ killsp();
+ while(ctok->type==PLUS||ctok->type==T_MINUS){
+ if(ctok->type==PLUS) c=ADD; else c=SUB;
+ next_token();killsp();
+ right=multiplicative_expression();
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->flags=c;
+ new->ntyp=0;
+ left=new;
+ killsp();
+ }
+ return left;
+}
+np multiplicative_expression(void)
+/* Erledigt *,/,% */
+{
+ np left,right,new;int c;
+ left=cast_expression();
+ killsp();
+ while(ctok->type==STAR||ctok->type==SLASH||ctok->type==PCT){
+ if(ctok->type==STAR) c=MULT;
+ else if(ctok->type==SLASH) c=DIV;
+ else c=MOD;
+ next_token();killsp();
+ right=cast_expression();
+ new=new_node();
+ new->left=left;
+ new->right=right;
+ new->flags=c;
+ new->ntyp=0;
+ left=new;
+ killsp();
+ }
+ return left;
+}
+np cast_expression(void)
+/* Erledigt (typ) */
+{
+ np new;char *imerk,buff[MAXI];
+ killsp();
+ if(ctok->type!=LPAR||!declaration(1)) return unary_expression();
+ next_token();killsp();
+ new=new_node();
+ new->right=0;
+ buff[0]=0;
+ imerk=ident;ident=buff;
+ new->ntyp=declarator(declaration_specifiers());
+ ident=imerk;
+ if(buff[0]) error(356);
+ killsp();
+ if(ctok->type!=RPAR) error(59); else next_token();
+ killsp();
+ if(c99&&ctok->type==LBRA){
+ /* compund literals */
+ init_dyn_cnt=0;
+ new->cl=initialization(new->ntyp,nesting!=0,0,0,0,0);
+ killsp();
+ if(new->cl){
+ if(ISARRAY(new->ntyp->flags)&&zmeqto(new->ntyp->size,l2zm(0L))){
+ const_list *p=new->cl;
+ while(p){new->ntyp->size=zmadd(p->idx,l2zm(1L));p=p->next;}
+ }
+ }
+ new->flags=LITERAL;
+ new->left=0;
+ new->val.vmax=l2zm((long)init_dyn_cnt);
+ }else{
+ new->flags=CAST;
+ new->left=cast_expression();
+ }
+ return new;
+}
+np unary_expression(void)
+/* Erledigt !,~,++,--,+,-,*,&,sizeof,__typeof */
+{
+ np new;char *merk;
+ killsp();
+ if(ctok->type!=NAME&&ctok->type!=PLUS&&ctok->type!=PPLUS&&ctok->type!=T_MINUS&&ctok->type!=MMINUS&&ctok->type!=T_AND&&ctok->type!=STAR&&ctok->type!=NOT&&ctok->type!=LNOT)
+ return postfix_expression();
+ if(ctok->type==NAME){
+ enum {SIZEOF,TYPEOF,ALIGNOF,OFFSETOF} op;
+ if(strcmp("sizeof",ctok->name)&&strcmp("__typeof",ctok->name)&&strcmp("__alignof",ctok->name)&&strcmp("__offsetof",ctok->name)){
+ return postfix_expression();
+ }else{
+ if(*ctok->name=='s')
+ op=SIZEOF;
+ else if(ctok->name[2]=='a')
+ op=ALIGNOF;
+ else if(ctok->name[2]=='t')
+ op=TYPEOF;
+ else
+ op=OFFSETOF;
+ next_token();
+ killsp();
+ new=new_node();
+ new->flags=CEXPR;
+ new->ntyp=new_typ();
+ if(op==SIZEOF||op==OFFSETOF){
+ if(HAVE_INT_SIZET)
+ new->ntyp->flags=(UNSIGNED|INT);
+ else
+ new->ntyp->flags=(UNSIGNED|LONG);
+ }else
+ new->ntyp->flags=INT;
+ new->right=0;
+ new->left=0;
+
+ if(ctok->type==LPAR&&declaration(1)){
+ type *t;
+ next_token();killsp();
+ buff[0]=0;
+ merk=ident;ident=buff;
+ t=declarator(declaration_specifiers());
+ if(type_uncomplete(t)) error(176);
+ ident=merk;
+ if(buff[0]) error(356);
+ if(op==OFFSETOF){
+ if(ctok->type==COMMA)
+ next_token();
+ else
+ error(57);
+ if(ctok->type!=NAME) error(76);
+ if(t->flags!=STRUCT){
+ error(310);
+ vumax=ul2zum(0UL);
+ }else
+ vumax=zm2zum(struct_offset(t->exact,ctok->name));
+ next_token();
+ if(HAVE_INT_SIZET)
+ new->val.vuint=zum2zui(vumax);
+ else
+ new->val.vulong=zum2zul(vumax);
+ }else if(op==SIZEOF){
+ if(is_vlength(t)){
+ new->dsize=vlength_szof(t);
+ new->flags=IDENTIFIER;
+ new->val.vmax=l2zm(0L);
+ new->sidefx=0;
+ new->identifier=empty;
+ }else{
+ if(HAVE_INT_SIZET)
+ new->val.vuint=zum2zui(zm2zum(szof(t)));
+ else
+ new->val.vulong=zum2zul(zm2zum(szof(t)));
+ }
+ }else if(op==ALIGNOF){
+ new->val.vint=zm2zi(falign(t));
+ }else if(op==TYPEOF){
+ new->val.vint=zm2zi(l2zm(t->flags));
+ }
+ freetyp(t);
+ killsp();
+ if(ctok->type!=RPAR) error(59); else next_token();
+ }else{
+ np tree;
+ if(op==OFFSETOF) error(0);
+ killsp();
+ tree=unary_expression();
+ if(!tree||!type_expression(tree,0)){
+ if(op==SIZEOF){
+ if(HAVE_INT_SIZET)
+ new->val.vuint=zum2zui(ul2zum(0UL));
+ else
+ new->val.vulong=zum2zul(ul2zum(0UL));
+ error(73);
+ }else{
+ new->val.vint=zm2zi(l2zm(-1L));
+ }
+ }else{
+ if(op==SIZEOF){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(type_uncomplete(tree->ntyp)) error(176);
+ if(is_vlength(tree->ntyp)){
+ new->dsize=vlength_szof(tree->ntyp);
+ new->flags=IDENTIFIER;
+ new->val.vmax=l2zm(0L);
+ new->sidefx=0;
+ new->identifier=empty;
+ }else{
+ if(HAVE_INT_SIZET)
+ new->val.vuint=zum2zui(zm2zum(szof(tree->ntyp)));
+ else
+ new->val.vulong=zum2zul(zm2zum(szof(tree->ntyp)));
+ }
+ }else{
+ if(op==ALIGNOF)
+ new->val.vint=zm2zi(falign(tree->ntyp));
+ else
+ new->val.vint=zm2zi(l2zm(tree->ntyp->flags));
+ }
+ }
+ if(tree) free_expression(tree);killsp();
+ }
+ return new;
+ }
+ }
+ new=new_node();
+ new->right=0;
+ new->ntyp=0;
+ if(ctok->type==PLUS){
+ next_token();
+ free(new);
+ return cast_expression();
+ }else if(ctok->type==T_MINUS){
+ next_token();
+ new->left=cast_expression();
+ new->flags=MINUS;
+ }else if(ctok->type==PPLUS){
+ next_token();
+ new->left=unary_expression();
+ new->flags=PREINC;
+ }else if(ctok->type==MMINUS){
+ next_token();
+ new->left=unary_expression();
+ new->flags=PREDEC;
+ }else if(ctok->type==T_AND){
+ next_token();
+ new->left=cast_expression();
+ new->flags=ADDRESS;
+ }else if(ctok->type==STAR){
+ next_token();
+ new->left=cast_expression();
+ new->flags=CONTENT;
+ }else if(ctok->type==NOT){
+ next_token();
+ new->left=cast_expression();
+ new->flags=KOMPLEMENT;
+ }else if(ctok->type==LNOT){
+ next_token();
+ new->left=cast_expression();
+ new->flags=NEGATION;
+ }
+ new->right=0;
+ new->ntyp=0;
+ return new;
+}
+np postfix_expression(void)
+/* Erledigt [],(),.,->,++,-- */
+{
+ np new,left;
+ left=primary_expression();
+ killsp();
+ while(ctok->type==LBRK||ctok->type==LPAR||ctok->type==DOT||ctok->type==ARROW||ctok->type==PPLUS||ctok->type==MMINUS){
+ new=new_node();
+ new->ntyp=0;
+ new->right=0;
+ new->left=left;
+ if(ctok->type==MMINUS){
+ next_token();
+ new->flags=POSTDEC;
+ }else if(ctok->type==ARROW){
+ next_token(); killsp();
+ new->flags=DSTRUCT;
+ new->right=identifier_expression();
+ new->right->flags=MEMBER;
+ new->left=new_node();
+ new->left->ntyp=0;
+ new->left->left=left;
+ new->left->right=0;
+ new->left->flags=CONTENT;
+ }else if(ctok->type==LBRK){
+ next_token(); killsp();
+ new->flags=CONTENT;
+ new->left=new_node();
+ new->left->flags=ADD;
+ new->left->ntyp=0;
+ new->left->left=left;
+ new->left->right=expression();
+ killsp();
+ if(ctok->type!=RBRK) error(62); else next_token();
+ }else if(ctok->type==PPLUS){
+ next_token();
+ new->flags=POSTINC;
+ }else if(ctok->type==DOT){
+ next_token();killsp();
+ new->right=identifier_expression();
+ new->flags=DSTRUCT;
+ new->right->flags=MEMBER;
+ }else if(ctok->type==LPAR){
+ argument_list *al,*first_alist=0,*last_alist=0;np n;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ new->left=left;
+ new->flags=CALL;
+ new->right=0;
+ new->alist=argument_list_expression();
+ }
+ left=new;
+ killsp();
+ }
+ return left;
+}
+argument_list *argument_list_expression(void)
+/* returns CALL node with alist attached, but without identifier */
+{
+ argument_list *al,*first_alist=0,*last_alist=0;np n;
+ if(ctok->type!=LPAR)ierror(0);
+ next_token();killsp();
+ while(ctok->type!=RPAR){
+ n=assignment_expression();
+ al=mymalloc(sizeof(argument_list));
+ al->arg=n;al->next=0;
+ if(last_alist){
+ last_alist->next=al;
+ last_alist=al;
+ }else{
+ last_alist=first_alist=al;
+ }
+ killsp();
+ if(ctok->type==COMMA){
+ next_token();killsp();
+ if(ctok->type==RPAR) error(59);
+ }else if(ctok->type!=RPAR) error(57);
+ }
+ if(ctok->type!=RPAR) error(59); else next_token();
+ return first_alist;
+}
+np primary_expression(void)
+/* primary-expressions (Konstanten,Strings,(expr),Identifier) */
+{
+ np new;token mtok;
+ if(ctok->type==NUMBER) return constant_expression();
+ if(ctok->type==T_STRING||ctok->type==T_CHAR) return string_expression();
+ if(ctok->type==LPAR){
+ next_token();killsp();
+ new=expression();
+ killsp();
+ if(ctok->type!=RPAR) error(59); else next_token();
+ return new;
+ }
+ return identifier_expression();
+}
+
+const_list *cl_from_string(char *start, char *end)
+{
+ const_list *r,*cl,**prev;int i;
+ prev=&r;
+ for(i=0;i<end-start+1;i++){
+ cl=mymalloc(CLS);
+ cl->next=0;
+ cl->tree=0;
+ cl->idx=l2zm((long)i);
+ cl->val.vmax=l2zm(0L);
+ cl->other=mymalloc(CLS);
+ cl->other->next=cl->other->other=0;
+ cl->other->tree=0;
+ cl->other->idx=l2zm(0L);
+ cl->other->val.vchar=zm2zc(l2zm((long)start[i]));
+ *prev=cl;
+ prev=&cl->next;
+ }
+ return r;
+}
+
+np string_expression(void)
+/* Gibt Zeiger auf string oder Zeichenkonstante zurueck */
+{
+ np new; char f,*s,*p;int flag,val;
+ zmax zm;zumax zum;
+ static char *string;
+ static size_t slen;
+ p=string;
+ while(1){
+ s=ctok->name;
+ if(*s=='L') {
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ s++;} /* Noch keine erweiterten Zeichen */
+ if(ctok->type==T_STRING&&*s!='\"') ierror(0);
+ if(ctok->type==T_CHAR&&*s!='\'') ierror(0);
+ f=*s++;
+ while(*s!=f&&*s!=0){
+ size_t pos=p-string;
+ if(slen<=pos+1){
+ slen+=128;
+ string=myrealloc(string,slen);
+ p=string+pos;
+ }
+ if(*s=='\\'){
+ s++;
+ if(*s=='\\'){*p++=CHARCONV('\\');s++;continue;}
+ if(*s=='n'){*p++=CHARCONV('\n');s++;continue;}
+ if(*s=='t'){*p++=CHARCONV('\t');s++;continue;}
+ if(*s=='r'){*p++=CHARCONV('\r');s++;continue;}
+ if(*s=='v'){*p++=CHARCONV('\v');s++;continue;}
+ if(*s=='b'){*p++=CHARCONV('\b');s++;continue;}
+ if(*s=='f'){*p++=CHARCONV('\f');s++;continue;}
+ if(*s=='a'){*p++=CHARCONV('\a');s++;continue;}
+ if(*s=='\?'){*p++=CHARCONV('\?');s++;continue;}
+ if(*s=='\''){*p++=CHARCONV('\'');s++;continue;}
+ if(*s=='\"'){*p++=CHARCONV('\"');s++;continue;}
+ flag=val=0;
+ while(*s>='0'&&*s<='7'&&flag<3){
+ val=val*8+*s-'0';
+ s++;flag++;
+ }
+ if(flag){*p++=val;continue;}
+ if(*s=='x'){
+ int warned=0;
+ s++;val=0;
+ while((*s>='0'&&*s<='9')||(*s>='a'&&*s<='f')||(*s>='A'&&*s<='F')){
+ val=val*16;
+ if(*s>='0'&&*s<='9') val+=*s-'0';
+ if(*s>='a'&&*s<='f') val+=*s-'a'+10;
+ if(*s>='A'&&*s<='F') val+=*s-'A'+10;
+ if(!warned&&((unsigned long)val)>zum2ul(tu_max[CHAR])){
+ error(364);
+ warned=1;
+ }
+ s++;
+ }
+ *p++=val;continue;
+ }
+ error(71);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ }
+ *p++=CHARCONV(*s);
+ s++;
+ }
+ if(*s!=f) error(74);
+ next_token();
+ killsp();
+ if(f!='\"'||ctok->type!=T_STRING) break;
+ }
+ if(!string){
+ slen+=128;
+ string=myrealloc(string,slen);
+ p=string;
+ }
+ *p=0;
+ new=new_node();
+ new->ntyp=new_typ();
+ if(f=='\"'){
+ new->ntyp->flags=ARRAY;
+ new->ntyp->size=l2zm((long)(p-string)+1);
+ new->ntyp->next=new_typ();
+ new->ntyp->next->flags=STRINGCONST|CHAR;
+ new->ntyp->next->next=0;
+ new->flags=STRING;
+ new->cl=cl_from_string(string,p);
+ /* new->identifier=add_identifier(string,p-string);*/
+ new->val.vmax=l2zm(0L);
+ }else{
+ char *l;
+ if(ecpp)new->ntyp->flags=CONST|CHAR;
+ else new->ntyp->flags=CONST|INT;
+ new->ntyp->next=0;
+ new->flags=CEXPR;
+ /* TODO: Hier eventuell was mitspeichern das char */
+ zm=l2zm(0L);zum=ul2zum(0UL);
+ p--;
+ if(p>string){ error(72);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ }
+ for(BIGENDIAN?(l=string):(l=p);BIGENDIAN?(l<=p):(l>=string);BIGENDIAN?(l++):(l--)){
+ /* zm=zm<<CHAR_BIT+*p */
+ if(default_unsigned){
+ zum=zumlshift(zum,char_bit);
+ zum=zmadd(zum,ul2zum(*(unsigned char *)l));
+ new->val.vint=zm2zi(zum2zm(zum));
+ }else{
+ zm=zmlshift(zm,char_bit);
+ zm=zmadd(zm,l2zm((long)*l));
+ new->val.vint=zm2zi(zm);
+ }
+ }
+ }
+ new->left=new->right=0;
+ return new;
+}
+np constant_expression(void)
+/* Gibt Zeiger auf erzeugt Struktur fuer Konstante zurueck */
+{
+ np new; zldouble db;
+ zumax value,zbase,digit;unsigned long base=10,t;
+ char *s,*merk;int warned=0,tm=0;
+ merk=s=ctok->name;
+ value=ul2zum(0L);
+ new=new_node();
+ new->ntyp=new_typ();
+ new->ntyp->flags=0;
+ new->flags=CEXPR;
+ new->left=new->right=0;
+ new->sidefx=0;
+ if(*s=='0'){
+ s++;
+ if(*s=='x'||*s=='X'){s++;base=16;} else base=8;
+ }
+ zbase=ul2zum(base);
+ if(*s>='0'&&*s<='9') t=*s-'0';
+ else if(*s>='a'&&*s<='f') t=*s-'a'+10;
+ else if(*s>='A'&&*s<='F') t=*s-'A'+10;
+ else t=20;
+ while(t<base){
+ digit=ul2zum(t);
+ if(!warned){
+ if(!c99&&!zumleq(value,zumdiv(zumsub(t_max(UNSIGNED|LONG),digit),zbase)))
+ warned=1;
+ if(c99&&!zumleq(value,zumdiv(zumsub(t_max(UNSIGNED|LLONG),digit),zbase)))
+ warned=1;
+ }
+ value=zumadd(zummult(value,zbase),digit);
+ s++;
+ if(*s>='0'&&*s<='9') t=*s-'0';
+ else if(*s>='a'&&*s<='f') t=*s-'a'+10;
+ else if(*s>='A'&&*s<='F') t=*s-'A'+10;
+ else t=20;
+ }
+ while((!(tm&UNSIGNED)&&(*s=='u'||*s=='U'))||((tm&NQ)==0&&(*s=='l'||*s=='L'))){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(!(tm&UNSIGNED)&&(*s=='u'||*s=='U')){
+ if((tm&NQ)==LONG){
+ if(!c99||zumleq(value,t_max(UNSIGNED|LONG)))
+ new->ntyp->flags=(UNSIGNED|LONG);
+ else
+ new->ntyp->flags=(UNSIGNED|LLONG);
+ }else if((tm&NQ)==LLONG)
+ new->ntyp->flags=(UNSIGNED|LLONG);
+ else if(zumleq(value,t_max(UNSIGNED|INT)))
+ new->ntyp->flags=UNSIGNED|INT;
+ else if(!c99||zumleq(value,t_max(UNSIGNED|LONG)))
+ new->ntyp->flags=UNSIGNED|LONG;
+ else
+ new->ntyp->flags=UNSIGNED|LLONG;
+ tm|=UNSIGNED;
+ }else{
+ if(c99&&s[1]==s[0]){
+ s++;
+ if(tm&UNSIGNED)
+ new->ntyp->flags=(UNSIGNED|LLONG);
+ else if(base==10||zumleq(value,t_max(LLONG)))
+ new->ntyp->flags=LLONG;
+ else
+ new->ntyp->flags=UNSIGNED|LLONG;
+ tm|=LLONG;
+ }else{
+ if(tm&UNSIGNED){
+ if(!c99||zumleq(value,t_max(UNSIGNED|LONG)))
+ new->ntyp->flags=(UNSIGNED|LONG);
+ else
+ new->ntyp->flags=(UNSIGNED|LLONG);
+ }else{
+ if(!c99){
+ if(base==10||zumleq(value,t_max(LONG)))
+ new->ntyp->flags=LONG;
+ else
+ new->ntyp->flags=UNSIGNED|LONG;
+ }else{
+ if(zumleq(value,t_max(LONG)))
+ new->ntyp->flags=LONG;
+ else if(base!=10&&zumleq(value,t_max(UNSIGNED|LONG)))
+ new->ntyp->flags=UNSIGNED|LONG;
+ else if(base==10||zumleq(value,t_max(LLONG)))
+ new->ntyp->flags=LLONG;
+ else
+ new->ntyp->flags=UNSIGNED|LLONG;
+ }
+ }
+ tm|=LONG;
+ }
+ }
+ s++;
+ }
+ if(*s=='.'||*s=='e'||*s=='E'){
+ /* Fliesskommakonstante, ignoriert vorher berechneten Wert, falls er */
+ /* nicht dezimal und nicht 0 war (da er dann oktal war) */
+ if(*merk=='0'&&!zumeqto(value,ul2zum(0UL))){
+ value=ul2zum(0UL);zbase=ul2zum(10UL);
+ while(*merk>='0'&&*merk<='9'){
+ digit=ul2zum((unsigned long)(*merk-'0'));
+ value=zumadd(zummult(value,zbase),digit);
+ merk++;
+ }
+ if(merk!=s) error(75);
+ }
+ db=zum2zld(value);
+ if(*s=='.'){
+ /* Teil hinter Kommastellen */
+ zldouble zdiv,zbased,zsum,digit;
+ int cnt=0;
+ s++;
+ zbased=d2zld(10.0);zdiv=d2zld(1.0);zsum=d2zld(0.0);
+ while(*s>='0'&&*s<='9'){
+ if (cnt<35){
+ cnt++;
+ digit=d2zld((double)(*s-'0'));
+ zsum=zldadd(zldmult(zsum,zbased),digit);
+ zdiv=zldmult(zdiv,zbased);
+ }
+ s++;
+ }
+ db=zldadd(db,zlddiv(zsum,zdiv));
+
+ }
+ if(*s=='e'||*s=='E'){
+ /* Exponentialdarstellung */
+ int exp,vorz,i;zldouble zbased;
+ zbased=d2zld((double)10);
+ s++;
+ if(*s=='-'){
+ s++;vorz=-1;
+ }else{
+ vorz=1;if(*s=='+') s++;
+ }
+ exp=0;
+ while(*s>='0'&&*s<='9') exp=exp*10+*s++-'0';
+ for(i=0;i<exp;i++){
+ if(vorz>0) db=zldmult(db,zbased);
+ else db=zlddiv(db,zbased);
+ }
+ }
+ new->ntyp->flags=DOUBLE;
+ if(*s=='f'||*s=='F'){
+ new->ntyp->flags=FLOAT;s++;
+ }else if(*s=='l'||*s=='L'){
+ new->ntyp->flags=LDOUBLE;s++;
+ }
+ }else{
+ if(warned) error(211);
+ if(new->ntyp->flags==0){
+ if(base==10){
+ if(zumleq(value,t_max(INT)))
+ new->ntyp->flags=INT;
+ else if(!c99||zumleq(value,t_max(LONG)))
+ new->ntyp->flags=LONG;
+ else
+ new->ntyp->flags=LLONG;
+ }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(zumleq(value,t_max(INT)))
+ new->ntyp->flags=INT;
+ else
+ if(zumleq(value,t_max(UNSIGNED|INT)))
+ new->ntyp->flags=UNSIGNED|INT;
+ else if(zumleq(value,t_max(LONG)))
+ new->ntyp->flags=LONG;
+ else if(!c99||zumleq(value,t_max(UNSIGNED|LONG))){
+ new->ntyp->flags=UNSIGNED|LONG;error(212);
+ }else if(zumleq(value,t_max(LLONG)))
+ new->ntyp->flags=LLONG;
+ else
+ new->ntyp->flags=UNSIGNED|LLONG;
+ }
+ }
+ }
+
+ if(*s) error(232);
+
+ if(new->ntyp->flags==FLOAT) new->val.vfloat=zld2zf(db);
+ else if(new->ntyp->flags==DOUBLE) new->val.vdouble=zld2zd(db);
+ else if(new->ntyp->flags==LDOUBLE) new->val.vldouble=db;
+ else if(new->ntyp->flags==INT) new->val.vint=zm2zi(zum2zm(value));
+ else if(new->ntyp->flags==(UNSIGNED|INT)) new->val.vuint=zum2zui(value);
+ else if(new->ntyp->flags==LONG) new->val.vlong=zm2zl(zum2zm(value));
+ else if(new->ntyp->flags==(UNSIGNED|LONG)) new->val.vulong=zum2zul(value);
+ else if(new->ntyp->flags==LLONG) new->val.vllong=zm2zll(zum2zm(value));
+ else if(new->ntyp->flags==(UNSIGNED|LLONG)) new->val.vullong=zum2zull(value);
+ else ierror(0);
+ next_token();
+ return new;
+}
+np identifier_expression(void)
+/* Erzeugt Identifier mit Knoten */
+{
+ np new;char buff[MAXI];
+ killsp();
+ if(ctok->type==NAME){
+ if(is_keyword(ctok->name)) error(216,ctok->name);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ new=new_node();
+ new->flags=IDENTIFIER;
+ new->left=new->right=0;
+ new->identifier=add_identifier(ctok->name,strlen(ctok->name));
+ if(!strncmp(ctok->name,"__maskm_",8)){
+ unsigned long mask;
+ if(sscanf(ctok->name,"__maskm_%lu_%s",&mask,new->identifier)!=2) ierror(0);
+ sprintf(new->identifier+strlen(new->identifier),".%lu",mask);
+ }
+ new->ntyp=0;
+ new->sidefx=0;
+ new->val.vmax=l2zm(0L);
+ new->o.v=0;
+ next_token();
+ }else{
+ error(76);
+ new=0;
+ }
+ return new;
+}
+void free_alist(argument_list *p)
+/* Gibt argument_list inkl. expressions frei */
+{
+ argument_list *merk;
+ while(p){
+ merk=p->next;
+ if(p->arg) free_expression(p->arg);
+ free(p);
+ p=merk;
+ }
+}
+void free_expression(np p)
+/* Gibt expression mit allen Typen etc. frei */
+{
+ if(!p) return;
+ if(p->flags==ASSIGNOP){
+ if(!p->right){ierror(0);return;}
+ if(p->right->left==p->left) p->left=0;
+ if(p->right->right==p->left) p->left=0;
+ }
+ if(p->flags==CALL&&p->alist) free_alist(p->alist);
+ if(p->ntyp) freetyp(p->ntyp);
+ if(p->left) free_expression(p->left);
+ if(p->right) free_expression(p->right);
+ free(p);
+}
+
diff --git a/pp.c b/pp.c
new file mode 100755
index 0000000..385cb1d
--- /dev/null
+++ b/pp.c
@@ -0,0 +1,975 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+FILE *infile;
+int line=1;
+
+#define INCSIZE 16
+FILE **incfile;
+char **incname;
+int *incline;
+int incn,incsize;
+
+#define PP_TSIZE 1024
+
+/*FIXME*/
+#define ierror(x) abort();
+#define mymalloc(x) malloc(x)
+#define myrealloc(x,y) realloc(x,y)
+
+/* must not collide with source character-set */
+enum {
+ TKKEYWORD=-32,
+ TKMARG,
+ TKIDENTIFIER,
+ TKNUMBER,
+ TKPLUSPLUS,
+ TKMINMIN,
+ TKEOL,
+ TKLTLT,
+ TKGTGT,
+ TKSREF,
+ TKLE,
+ TKGE,
+ TKEQ,
+ TKNE,
+ TKLAND,
+ TKLOR,
+ TKMULEQ,
+ TKDIVEQ,
+ TKMODEQ,
+ TKPLUSEQ,
+ TKMINEQ,
+ TKLTLTEQ,
+ TKGTGTEQ,
+ TKANDEQ,
+ TKOREQ,
+ TKXOREQ,
+ TKDDD,
+ TKNUMNUM
+};
+
+static char *tokout[]={"err","err","err","err","++","--","","<<",">>","->","<=",">=","==",
+ "!=","&&","||","*=","/=","%=","+=","-=","<<=",">>=","&=",
+ "|=","^=","...","##"
+};
+
+static char *desc[]={
+ "TKKEYWORD",
+ "TKMARG",
+ "TKIDENTIFIER",
+ "TKNUMBER",
+ "TKPLUSPLUS",
+ "TKMINMIN",
+ "TKEOL",
+ "TKLTLT",
+ "TKGTGT",
+ "TKSREF",
+ "TKLE",
+ "TKGE",
+ "TKEQ",
+ "TKNE",
+ "TKLAND",
+ "TKLOR",
+ "TKMULEQ",
+ "TKDIVEQ",
+ "TKMODEQ",
+ "TKPLUSEQ",
+ "TKMINEQ",
+ "TKLTLTEQ",
+ "TKGTGTEQ",
+ "TKANDEQ",
+ "TKOREQ",
+ "TKXOREQ",
+ "TKDDD",
+ "TKNUMNUM"
+};
+
+typedef struct {
+ int size;
+ int next;
+ int *tokens;
+} tokenlist;
+
+#ifndef OBFUSCATOR
+
+#define VARARG_MACRO 1
+#define BUILTIN_MACRO 2
+#define NEED_PAREN 4
+
+typedef struct {
+ char *name;
+ int flags;
+ int nargs;
+ tokenlist repl;
+} macro;
+
+#define PP_HSIZE 16384
+static int **hash_table;
+
+#define PP_MSIZE 128
+static macro *macro_table;
+static int macro_cnt=1,macro_size;
+
+void print_tokenlist(FILE *,tokenlist *);
+
+static void copy_tokenlist(tokenlist *new,tokenlist *old)
+{
+ if(new->size<old->next+new->next){
+ new->size=old->next+new->next;
+ new->tokens=myrealloc(new->tokens,new->size*sizeof(*new->tokens));
+ }
+ memcpy(new->tokens+new->next,old->tokens,old->next*sizeof(*new->tokens));
+ new->next+=old->next;
+}
+
+static int new_macro(char *name,int flags,int nargs,tokenlist *repl)
+{
+ int i,*p;
+ if(macro_cnt>=macro_size){
+ macro_size+=PP_MSIZE;
+ macro_table=myrealloc(macro_table,macro_size*sizeof(*macro_table));
+ macro_table[0].name=0; /* dummy */
+ }
+ macro_table[macro_cnt].name=mymalloc(strlen(name)+1);
+ strcpy(macro_table[macro_cnt].name,name);
+ macro_table[macro_cnt].flags=flags;
+ macro_table[macro_cnt].nargs=nargs;
+ macro_table[macro_cnt].repl.size=0;
+ macro_table[macro_cnt].repl.next=0;
+ macro_table[macro_cnt].repl.tokens=0;
+ copy_tokenlist(¯o_table[macro_cnt].repl,repl);
+ return macro_cnt++;
+}
+
+static void free_macro(int n)
+{
+ free(macro_table[n].name);
+ free(macro_table[n].repl.tokens);
+ macro_table[n].name=0;
+}
+
+static int hash(char *p)
+{
+ int s=0;
+ while(*p)
+ s+=*p++;
+ return s%PP_HSIZE;
+}
+
+static int find_macro(char *name)
+{
+ int i=hash(name),n,*p;
+ if(!(p=hash_table[i])) return 0;
+ n=p[0];
+ for(i=1;i<=n;i++)
+ if(macro_table[p[i]].name&&!strcmp(macro_table[p[i]].name,name))
+ return p[i];
+ return 0;
+}
+
+static void add_macro(int n)
+{
+ int i=hash(macro_table[n].name),*p;
+ if(!(p=hash_table[i])){
+ hash_table[i]=p=mymalloc(2*sizeof(*hash_table[i]));
+ p[0]=1;
+ p[1]=n;
+ }else{
+ p=hash_table[i]=myrealloc(p,(p[0]+1)*sizeof(*p));
+ p[0]++;
+ p[p[0]]=n;
+printf("hash_collisio, depth=%d\n",p[0]);
+ }
+}
+
+#endif /* OBFUSCATOR */
+
+static FILE *include_file(const char *name)
+{
+ if(incn>=incsize){
+ incsize+=INCSIZE;
+ incfile=myrealloc(incfile,incsize*sizeof(*incfile));
+ incname=myrealloc(incname,incsize*sizeof(*incname));
+ incline=myrealloc(incline,incsize*sizeof(*incline));
+ }
+ if(!name){
+ incfile[incn]=stdin;
+ name="<stdin>";
+ }else{
+ incfile[incn]=fopen(name,"r");
+ }
+printf("include file %s\n",name);
+ incname[incn]=mymalloc(strlen(name)+1);
+ strcpy(incname[incn],name);
+ incn++;
+ return incfile[incn-1];
+}
+
+static FILE *close_file(void)
+{
+ --incn;
+ free(incname[incn]);
+ if(incfile[incn])
+ fclose(incfile[incn]);
+ if(incn<=0)
+ return 0;
+ return incfile[incn-1];
+}
+
+static void add_token(tokenlist *p,int c)
+{
+ if(p->next>=p->size){
+ p->size+=PP_TSIZE;
+ p->tokens=myrealloc(p->tokens,p->size*sizeof(*p->tokens));
+ }
+ p->tokens[p->next]=c;
+ p->next++;
+}
+
+int read_char(void)
+/* Read next input character. Counts line numbers. */
+{
+ int tmp=getc(infile);
+ if(tmp=='\n') line++;
+ return tmp;
+}
+
+static int push_back=EOF;
+
+static int get_next_char(void)
+/* Read next character. Handles trigraphs and line-concatenation. */
+{
+ static int buf[2],inbuf;
+ int tmp,tmp2;
+ if(push_back!=EOF){
+ tmp=push_back;
+ push_back=EOF;
+ return tmp;
+ }
+ if(inbuf==0){
+ tmp=read_char();
+ if(tmp!='\\'&&tmp!='?'){
+ return tmp;
+ }else{
+ buf[0]=tmp;
+ inbuf=1;
+ /* fall through */
+ }
+ }
+ if(inbuf==1){
+ if(buf[0]!='?'&&buf[0]!='\\'){
+ inbuf=0;
+ return buf[0];
+ }else{
+ tmp=read_char();
+ if(buf[0]=='\\'){
+ if(tmp=='\n'){
+ inbuf=0;
+ return get_next_char();
+ }else{
+ buf[0]=tmp;
+ return '\\';
+ }
+ }else{
+ if(tmp=='?'){
+ buf[1]='?';
+ inbuf=2;
+ /* fall through */
+ }else{
+ buf[0]=tmp;
+ return '?';
+ }
+ }
+ }
+ }
+ if(inbuf==2){
+ if(buf[0]!='?') ierror(0);
+ if(buf[1]!='?'){
+ inbuf=1;
+ tmp=buf[0];
+ buf[0]=buf[1];
+ return tmp;
+ }else{
+ tmp2=tmp=read_char();;
+ /* FIXME: only if on */
+ if(tmp=='=') tmp2='#';
+ else if(tmp=='(') tmp2='[';
+ else if(tmp=='/') tmp2='\\';
+ else if(tmp==')') tmp2=']';
+ else if(tmp=='\'') tmp2='^';
+ else if(tmp=='<') tmp2='{';
+ else if(tmp=='!') tmp2='|';
+ else if(tmp=='>') tmp2='}';
+ else if(tmp=='-') tmp2='~';
+ if(tmp!=tmp2){
+ /* FIXME: warning */
+ if(tmp2!='\\'){
+ inbuf=0;
+ return tmp2;
+ }else{
+ inbuf=1;
+ buf[0]=tmp2;
+ return get_next_char();
+ }
+ }else{
+ tmp=buf[0];
+ buf[0]=buf[1];
+ buf[1]=tmp2;
+ return tmp;
+ }
+ }
+ }
+ ierror(0);
+}
+
+static int get_next_token(tokenlist *p)
+{
+ int c,z,tmp,*cnt;
+ while(1){
+ c=get_next_char();
+ if(c=='"'||c=='\''){
+ int term=c,escape=0;
+ add_token(p,c);
+ z=p->next;
+ add_token(p,0);
+ while(1){
+ c=get_next_char();
+ /* FIXME */
+ if(c==EOF||c=='\n'){
+ puts("unterminated string");
+ return 0;
+ }
+ if(c==term&&!escape) return 0;
+ if(escape&&c=='\\')
+ escape=0;
+ else
+ escape=(c=='\\');
+ add_token(p,c);
+ p->tokens[z]++;
+ }
+ }else if(c=='_'||isalpha((unsigned char)c)){
+ add_token(p,TKIDENTIFIER);
+ z=p->next;
+ add_token(p,1);
+ add_token(p,c);
+ while((c=get_next_char())=='_'||isalnum((unsigned char)c)){
+ add_token(p,c);
+ p->tokens[z]++;
+ }
+ push_back=c;
+ return 0;
+ }else if(isdigit((unsigned char)c)){
+ tmp=c;
+ c=TKNUMBER;
+ }else if(c=='.'){
+ tmp=get_next_char();
+ if(isdigit((unsigned char)tmp)){
+ push_back=tmp;
+ tmp='.';
+ c=TKNUMBER;
+ }else if(tmp=='.'){
+ c=get_next_char();
+ if(c!='.'){puts("..x-token");return 0;}/*FIXME*/
+ add_token(p,TKDDD);
+ return 0;
+ }else
+ push_back=tmp;
+ /* fall through */
+ }else if(c=='+'){
+ c=get_next_char();
+ if(c=='+'){
+ add_token(p,TKPLUSPLUS);
+ }else if(c=='='){
+ add_token(p,TKPLUSEQ);
+ }else{
+ add_token(p,'+');
+ push_back=c;
+ }
+ return 0;
+ }else if(c=='-'){
+ c=get_next_char();
+ if(c=='-'){
+ add_token(p,TKMINMIN);
+ }else if(c=='='){
+ add_token(p,TKMINEQ);
+ }else if(c=='>'){
+ add_token(p,TKSREF);
+ }else{
+ add_token(p,'-');
+ push_back=c;
+ }
+ return 0;
+ }else if(c=='|'){
+ c=get_next_char();
+ if(c=='|'){
+ add_token(p,TKLOR);
+ }else if(c=='='){
+ add_token(p,TKOREQ);
+ }else{
+ add_token(p,'|');
+ push_back=c;
+ }
+ return 0;
+ }else if(c=='&'){
+ c=get_next_char();
+ if(c=='&'){
+ add_token(p,TKLAND);
+ }else if(c=='='){
+ add_token(p,TKANDEQ);
+ }else{
+ add_token(p,'&');
+ push_back=c;
+ }
+ return 0;
+ }else if(c=='<'){
+ c=get_next_char();
+ if(c=='<'){
+ c=get_next_char();
+ if(c=='='){
+ add_token(p,TKLTLTEQ);
+ }else{
+ add_token(p,TKLTLT);
+ push_back=c;
+ }
+ }else if(c=='='){
+ add_token(p,TKLE);
+ }else{
+ add_token(p,'<');
+ push_back=c;
+ }
+ return 0;
+ }else if(c=='>'){
+ c=get_next_char();
+ if(c=='>'){
+ c=get_next_char();
+ if(c=='=')
+ add_token(p,TKGTGTEQ);
+ else{
+ add_token(p,TKGTGT);
+ push_back=c;
+ }
+ }else if(c=='='){
+ add_token(p,TKGE);
+ }else{
+ add_token(p,'>');
+ push_back=c;
+ }
+ return 0;
+ }else if(c=='!'){
+ c=get_next_char();
+ if(c=='='){
+ add_token(p,TKNE);
+ }else{
+ add_token(p,'!');
+ push_back=c;
+ }
+ return 0;
+ }else if(c=='*'){
+ c=get_next_char();
+ if(c=='='){
+ add_token(p,TKMULEQ);
+ }else{
+ add_token(p,'*');
+ push_back=c;
+ }
+ return 0;
+ }else if(c=='%'){
+ c=get_next_char();
+ if(c=='='){
+ add_token(p,TKMODEQ);
+ }else{
+ add_token(p,'%');
+ push_back=c;
+ }
+ return 0;
+ }else if(c=='#'){
+ c=get_next_char();
+ if(c=='#'){
+ add_token(p,TKNUMNUM);
+ }else{
+ add_token(p,'#');
+ push_back=c;
+ }
+ return 0;
+ }else if(c=='/'){
+ /*FIXME*/
+ c=get_next_char();
+ if(c=='*'){
+ int cstate=0;
+ while(1){
+ c=get_next_char();
+ if(c=='*'){
+ if(cstate==2) /*FIXME*/;
+ cstate=1;
+ }else if(c=='/'){
+ if(cstate==1) break;
+ cstate=2;
+ }else cstate=0;
+ }
+ if(p->next>=1&&p->tokens[p->next-1]!=' '){
+ add_token(p,' ');
+ return 0;
+ }else
+ continue;
+ }else if(c=='/'/*FIXME*/){
+ while((c=get_next_char())!=EOF&&c!='\n');
+ if(c==EOF) ierror(0); /*FIXME*/
+ add_token(p,'\n');
+ return 0;
+ }else if(c=='='){
+ add_token(p,TKDIVEQ);
+ return 0;
+ }
+ push_back=c;
+ c='/';
+ /* fall through */
+ }
+ if(c==TKNUMBER){
+ add_token(p,TKNUMBER);
+ z=p->next;
+ add_token(p,1);
+ add_token(p,tmp);
+ while(1){
+ c=get_next_char();
+ if(c=='e'||c=='E'||/*FIXME?*/c=='p'||c=='P'){
+ add_token(p,c);
+ p->tokens[z]++;
+ tmp=get_next_char();
+ if(tmp=='+'||tmp=='-'){
+ add_token(p,tmp);
+ p->tokens[z]++;
+ }else{
+ push_back=tmp;
+ }
+ }else if(c=='.'||c=='_'||isalnum((unsigned char)c)){
+ add_token(p,c);
+ p->tokens[z]++;
+ }else{
+ push_back=c;
+ break;
+ }
+ }
+ return 0;
+ }
+ if(c==EOF||c=='\n'){
+ add_token(p,c);
+ return c;
+ }
+ if(!isspace((unsigned char)c)){
+ add_token(p,c);
+ return 0;
+ }else{
+ if(p->next>=1&&p->tokens[p->next-1]!=' ')
+ add_token(p,' ');
+ return 0;
+ }
+ }
+}
+
+void print_tokenlist(FILE *f,tokenlist *p)
+{
+ int i,*tr=p->tokens,*end=tr+p->next;
+ while(tr<end){
+ if(*tr=='"'||*tr=='\''||*tr==TKIDENTIFIER||*tr==TKNUMBER){
+ int n;
+ if(*tr=='"')
+ fprintf(f,"STRING: ");
+ else if(*tr=='\'')
+ fprintf(f,"CCONST: ");
+ else if(*tr==TKNUMBER)
+ fprintf(f,"NUMBER: ");
+ else
+ fprintf(f,"IDENT: ");
+ tr++;
+ n=*tr++;
+ for(i=0;i<n;i++)
+ fprintf(f,"%c",*tr++);
+ fprintf(f,"\n");
+ continue;
+ }
+ if(*tr==TKMARG){
+ fprintf(f,"ARG %d\n",tr[1]);
+ tr+=2; continue;
+ }
+ if(*tr==EOF){
+ fprintf(f,"EOF\n");
+ tr++; continue;
+ }
+ if(*tr=='\n'){
+ fprintf(f,"NEWLINE\n");
+ tr++; continue;
+ }
+ if(*tr>=TKPLUSPLUS&&*tr<=TKNUMNUM){
+ fprintf(f,"%s\n",desc[*tr-TKKEYWORD]);
+ tr++; continue;
+ }
+ fprintf(f,"OTHER: %d(%c)\n",*tr,*tr);
+ tr++;
+ }
+}
+
+void print_code(FILE *f,tokenlist *p)
+{
+ int i,*tr=p->tokens,*end=tr+p->next;
+ while(tr<end){
+ if(*tr=='"'||*tr=='\''||*tr==TKIDENTIFIER||*tr==TKNUMBER){
+ int n,c;
+ if(*tr==TKIDENTIFIER||*tr==TKNUMBER)
+ c=0;
+ else
+ c=*tr;
+ tr++;
+ if(c)
+ fprintf(f,"%c",c);
+ n=*tr++;
+ for(i=0;i<n;i++)
+ fprintf(f,"%c",*tr++);
+ if(c)
+ fprintf(f,"%c",c);
+ continue;
+ }
+ if(*tr==EOF){
+ return;
+ }
+ if(*tr=='\n'){
+ fprintf(f,"\n");
+ tr++; continue;
+ }
+ if(*tr>=TKPLUSPLUS&&*tr<=TKNUMNUM){
+ fprintf(f,"%s",tokout[*tr-TKKEYWORD]);
+ tr++; continue;
+ }
+ fprintf(f,"%c",*tr);
+ tr++;
+ }
+}
+
+char *token2string(int *p)
+{
+ int n=p[1];char *s;
+ static char *buf,len;
+ if(n+1>len){
+ len=n+1;
+ buf=mymalloc(len);
+ }
+ s=buf;
+ p+=2;
+ while(--n>=0) *s++=*p++;
+ *s=0;
+ return buf;
+}
+
+#ifndef OBFUSCATOR
+
+static int *get_macro_arg(tokenlist *arg,int *p,int vararg)
+{
+ int par=0;
+ while(1){
+ if(*p==EOF||*p=='\n') puts("unterminated macro invocation"); /*FIXME*/
+ if(*p==','&&par==0&&!vararg) return p;
+ if(*p==')'){
+ if(par>0){
+ add_token(arg,*p++);
+ par--;
+ continue;
+ }else
+ return p;
+ }
+ if(*p==TKIDENTIFIER||*p==TKNUMBER||*p=='"'||*p=='\''){
+ int n;
+ add_token(arg,*p++);
+ n=*p;
+ add_token(arg,*p++);
+ while(--n>=0) add_token(arg,*p++);
+ continue;
+ }
+ if(*p=='(') par++;
+ add_token(arg,*p++);
+ }
+}
+
+void stringize(tokenlist *new,tokenlist *src)
+{
+ int z,f,n;
+ int *p=src->tokens,*end=p+src->next;
+puts("1");
+ add_token(new,'"');
+ z=new->next;
+ add_token(new,0);
+ while(p<end){
+puts("2");
+ f=*p;
+ if(f==TKIDENTIFIER||f==TKNUMBER||f=='"'||f=='\''){
+ if(f=='"'){
+ add_token(new,'\\');
+ add_token(new,'"');
+ new->tokens[z]+=2;
+ }else if(f=='\''){
+ add_token(new,'\'');
+ new->tokens[z]++;
+ }
+ p++;
+ n=*p++;
+ while(--n>=0){
+ if((f=='"'||f=='\'')&&(*p=='\\'||*p=='"')){
+ add_token(new,'\\');
+ new->tokens[z]++;
+ }
+ add_token(new,*p++);
+ new->tokens[z]++;
+ }
+ continue;
+ }
+puts("3b");
+ add_token(new,*p++);
+ new->tokens[z]++;
+ }
+}
+
+int expand(tokenlist *dest,tokenlist *old,tokenlist *scratch1,tokenlist *scratch2)
+{
+ int n,i,*p,*end;
+ int did_replace=0,notdone;
+ tokenlist *new=scratch1,*src=old,t1={0},t2={0};
+ do{
+puts("starting expand iteration");
+ notdone=0;
+ p=src->tokens;
+ end=p+src->next;
+ while(p<end){
+ if(*p==TKIDENTIFIER||*p==TKNUMBER||*p=='"'||*p=='\''){
+ if(*p==TKIDENTIFIER&&(n=find_macro(token2string(p)))!=0){
+ tokenlist *repl=¯o_table[n].repl;
+ if(!(macro_table[n].flags&NEED_PAREN)){
+ n=repl->next;
+ for(i=0;i<n;i++) add_token(new,repl->tokens[i]);
+ p+=p[1]+2;
+ did_replace=notdone=1;
+ continue;
+ }else if(p[p[1]+2]=='('){
+ tokenlist **args=mymalloc((macro_table[n].nargs+1)*sizeof(*args));
+ /* tokenlist *scratch=mymalloc(sizeof(*scratch));*/
+ int *r,*end;
+ p+=p[1]+3;
+ for(i=0;i<macro_table[n].nargs;i++){
+ if(i!=0){
+ if(*p==',') p++; else puts(", expect");/*FIXME*/
+ }
+ args[i]=mymalloc(sizeof(**args));
+ args[i]->size=0;
+ args[i]->next=0;
+ args[i]->tokens=0;
+ p=get_macro_arg(args[i],p,0);
+ printf("arg %d:\n",i);
+ print_tokenlist(stdout,args[i]);
+ }
+ if(macro_table[n].flags&VARARG_MACRO){
+ args[i]=mymalloc(sizeof(**args));
+ args[i]->size=0;
+ args[i]->next=0;
+ args[i]->tokens=0;
+ if(*p==',') p++; else puts(", expect");/*FIXME*/
+ p=get_macro_arg(args[i],p,1);
+ printf("vararg:\n");
+ print_tokenlist(stdout,args[i]);
+ }
+ if(*p==')') p++; else puts(") expect");/*FIXME*/
+
+ r=macro_table[n].repl.tokens;
+ end=r+macro_table[n].repl.next;
+ while(r<end){
+ if(*r==TKIDENTIFIER||*r==TKNUMBER||*r=='"'||*r=='\''){
+ n=r[1];
+ puts("insert idnt");
+ r+=2;
+ while(--n>=0) add_token(new,*r++);
+ continue;
+ }
+ if(*r=='#'){
+ r++;
+ if(*r!=TKMARG) {puts("huch?");ierror(0);/*FIXME*/}
+ r++;
+ n=*r++;
+ stringize(new,args[n]);
+ continue;
+ }
+ if(*r==TKMARG){
+ t1.next=t2.next=0;
+ expand(new,args[r[1]],&t1,&t2);
+ r+=2;
+ continue;
+ }
+ puts("insert other");
+ add_token(new,*r++);
+ }
+
+ for(i=0;i<macro_table[n].nargs;i++) free(args[i]);
+ if(macro_table[n].flags&VARARG_MACRO) free(args[i]);
+ free(args);
+ did_replace=notdone=1;
+ continue;
+ }
+ }
+ add_token(new,*p++);
+ n=*p++;
+ add_token(new,n);
+ for(i=0;i<n;i++) add_token(new,*p++);
+ }else
+ add_token(new,*p++);
+ }
+ if(!notdone){
+puts("expand done, copying");
+print_tokenlist(stdout,new);
+ copy_tokenlist(dest,new);
+puts("copy done");
+ }else{
+puts("need another iteration");
+ src=new;
+ if(new==scratch1)
+ new=scratch2;
+ else
+ new=scratch1;
+ new->next=0;
+ }
+ }while(notdone);
+ return did_replace;
+}
+
+#endif /* OBFUSCATOR */
+
+main()
+{
+ int i,lastline=line,*p;
+ tokenlist tl={0},t2={0},t3={0},t4={0};
+ infile=include_file(0);
+#ifndef OBFUSCATOR
+ hash_table=mymalloc(PP_HSIZE*sizeof(*hash_table));
+ for(i=0;i<PP_HSIZE;i++) hash_table[i]=0;
+#endif
+ while(1){
+ tl.next=0;
+ while(!(i=get_next_token(&tl)));
+ add_token(&tl,TKEOL);
+ print_code(stdout,&tl);
+ if(i==EOF){
+ infile=close_file();
+ if(!infile) exit(0);
+ }
+#ifndef OBFUSCATOR
+ p=&tl.tokens[0];
+ while(*p==' ') p++;
+ if(*p=='#'&&(p[1]==TKIDENTIFIER||(p[1]==' '&&p[2]==TKIDENTIFIER))){
+ char *s;
+ p++;
+ if(*p!=TKIDENTIFIER) p++;
+ s=token2string(p);
+ if(!strcmp(s,"include")){
+ puts("include found");
+ *p=TKNUMBER; /* prevent expansion */
+ p+=2+p[1];
+ i=p-&tl.tokens[0];
+ t2.next=0;
+ t3.next=0;
+ t4.next=0;
+ expand(&t2,&tl,&t3,&t4);
+ p=&t2.tokens[i];
+ while(*p==' ') p++;
+printf("*p=%d\n",*p);
+ if(*p=='\"'){
+ s=token2string(p);
+ infile=include_file(s);
+ if(!infile) infile=close_file();
+ if(!infile) {exit(EXIT_FAILURE);/*FIXME*/}
+ }
+
+ continue;
+ }else if(!strcmp(s,"define")){
+ puts("define found");
+ p+=2+p[1];
+ while(*p==' ') p++;
+ if(*p!=TKIDENTIFIER){
+ puts("#define needs ID");
+ }else{
+ char *mname;
+ int flags=0,nargs=0;
+ static char **pnames;
+ static int pnsize;
+
+ s=token2string(p);
+ p+=2+p[1];
+ mname=mymalloc(strlen(s)+1);
+ strcpy(mname,s);
+ printf("id=%s\n",mname);
+ while(*p==' ') p++;
+ if(*p=='('){
+ puts("function-like");
+ p++;
+ while(*p==' ') p++;
+ while(*p==TKIDENTIFIER){
+ flags=0;
+ s=token2string(p);
+ p+=p[1]+2;
+ printf("parameter %s\n",s);
+ if(nargs>=pnsize){
+ pnsize+=PP_MSIZE;
+ pnames=myrealloc(pnames,pnsize*sizeof(*pnames));
+ }
+ for(i=0;i<nargs;i++)
+ if(!strcmp(pnames[i],s)) puts("double parameter");
+ pnames[nargs]=mymalloc(strlen(s)+1);
+ strcpy(pnames[nargs],s);
+ nargs++;
+ while(*p==' ') p++;
+ if(*p==','){ p++;flags=1;}
+ while(*p==' ') p++;
+ }
+ if(flags){
+ flags=NEED_PAREN;
+ if(*p==TKDDD){p++;flags|=VARARG_MACRO;}else puts(".../,");/*FIXME*/
+ while(*p==' ') p++;
+ if(*p==')') p++; else puts(") expect");/*FIXME*/
+ }else{
+ flags=NEED_PAREN;
+ if(*p==')') p++; else puts(") expect");/*FIXME*/
+ }
+ }
+ /*FIXME: # must be followed by parameter */
+ t2.next=0;
+ while(*p==' ') p++;
+ while(p<tl.tokens+tl.next&&*p!='\n'){
+ if(*p==TKIDENTIFIER){
+ s=token2string(p);
+ for(i=0;i<nargs;i++){
+ if(!strcmp(pnames[i],s)) break;
+ }
+ if(i<nargs||((flags&VARARG_MACRO)&&!strcmp("__VA_ARGS__",s))){
+ p+=p[1]+2;
+ add_token(&t2,TKMARG);
+ add_token(&t2,i);
+ continue;
+ }
+ }
+ add_token(&t2,*p++);
+ }
+ for(i=0;i<nargs;i++) free(pnames[i]);
+ i=new_macro(mname,flags,nargs,&t2);
+ add_macro(i);
+ printf("replacement-list for %s\n",mname);
+ print_tokenlist(stdout,&t2);
+ }
+ }
+ }else{
+ t2.next=0;
+ t3.next=0;
+ t4.next=0;
+ expand(&t2,&tl,&t3,&t4);
+ /* print_tokenlist(stdout,&t2);*/
+ print_code(stdout,&t2);
+ }
+#endif /* OBFUSCATOR */
+ }
+}
diff --git a/pptst.h b/pptst.h
new file mode 100755
index 0000000..788fb45
--- /dev/null
+++ b/pptst.h
@@ -0,0 +1,34 @@
+test
+hello
+con\
+catenated
+not\
+concatenated
+??=
+??(
+??/
+??)
+??'
+??<
+??!
+??>
+??-
+From standard: printf("Eh???/n");
+con??/
+catenated with trigraph
+
+# /* */ define fail succeed
+fail
+#undef fail
+ #define fail succeed
+fail
+
+#define x(a,b) a+b
+
+x(12
+23
+,
+34
+45
+)
+
diff --git a/preproc.c b/preproc.c
new file mode 100755
index 0000000..54f6701
--- /dev/null
+++ b/preproc.c
@@ -0,0 +1,2506 @@
+/* TODO:
+
+ ---- HIGHEST PRIORITY ----
+
+ * #ifndef
+
+ * #if/#elif - Bearbeitung
+
+ * leere argument-/tokenlists erlauben
+
+ * Anzahl der Argumente checken (auch zuviele ergeben einen Error)
+
+ * bei REDEFINING und allowredefinition=0 tokenlist genau ueberpruefen
+
+ * Aufteilen in mehrere Sourcen main.c pplists.c etc.
+ * Einige Variablen umbenennen (x,y,i,j,l,n etc =8)
+
+ -----------------------------------------------------------------
+
+ * Verbesserungen:
+ * - Nach malloc()/vor free() ueberpruefen ob NULL-Pointer
+ * - Statt per dlen per Ptr2EOL abfragen..
+
+ * Fragen an Volker:
+ * - _ alleine ein Identifier ? Ja
+
+ ---- LOWEST PRIORITY ----
+
+ * - Token loeschen, wenn nur noch TokenList benutzt wird.
+
+ * - ParseIdent.. optimieren
+
+ * - Rest optimieren =8)
+
+ * - PreParsing umschreiben.. __LINE__ muss mit der echten
+ * Zeilennummer uebereinstimmen (die LFs drinlassen)
+ */
+
+/*
+ * PreProcessor
+ * $VER: VBPP V0.00 (19 Sep 1995)
+ * (w) 1995 by Thorsten Schaaps
+ */
+
+#include <time.h>
+
+#include "vbc.h"
+#include "vbpp.h"
+
+/*vb: */
+static char FILE_[]=__FILE__;
+
+/*vb: */
+char pp_version[] = "vbpp V0.00 (w) 1995 by Thorsten Schaaps";
+
+ /* #define MAXIFNESTING 1024 *//*vb: ifnesting==incnesting */
+
+FILE *in[MAXINCNESTING]; /* Sourcefiles */
+int zn[MAXINCNESTING]; /* Zeilennummern */
+char *filenames[MAXINCNESTING]; /* Filenamen */
+int incnesting; /* aktuelle Verschachtelungstiefe */
+unsigned long linenr; /* Zeilennummer */
+
+char *incpath[MAXINCPATHS] =
+{"vinclude:"}; /* Includepfade */
+
+int incpathc = 1; /* Anzahl der Includepfade */
+
+char ppstring[MAXPPINPUT];
+
+int cmtnesting = 0; /* aktuelle Kommentar-Versch.-Tiefe */
+
+ /*int ifnesting; *//*vb: *//* aktuelle IF-Tiefe */
+/*vb: ifnesting==incnesting */
+short ifstatus[MAXINCNESTING]; /* Array fuer Status-Verschachtelung */
+int if_cnt; /* Zaehler fuer #if's waehrend do_output=0 */
+int abs_if_cnt; /* zaehlt auch waehrend do_output */
+
+int do_output = 1; /* Flag zur Erzeugung eines Outputs */
+
+struct strnode *strlist;
+
+struct mnode *mlist;
+
+int did_expand;
+
+/* Temporaere Debugging-Routinen */
+void PrintSN(struct strnode *tl)
+{
+ switch (tl->type) {
+ case NORMAL:
+ printf(" Normal........:");
+ break;
+ case PP_IDENT:
+ printf(" Identifier....:");
+ break;
+ case ARGUMENT:
+ printf(" Argument Nr.%2d:", tl->number);
+ break;
+ case NUMBER:
+ printf(" Number........:");
+ break;
+ case PP_STR:
+ printf(" String........:");
+ break;
+ case SPACE:
+ printf(" Space.........:");
+ break;
+ case SPECIAL:
+ printf(" Special..Nr.%2d:", tl->flags);
+ break;
+ default:
+ printf(" unknown..Nr.%2d:", tl->type);
+ break;
+ }
+ printf(" %s\n", tl->str);
+}
+void PrintTL(struct strnode *tl)
+{
+
+#ifdef bla
+
+ if (tl) {
+ printf("TokenList:\n");
+ while (tl) {
+ PrintSN(tl);
+ tl = tl->next;
+ }
+ }
+#endif
+
+}
+
+
+/* ******* Listen-Funktionen ******* */
+
+/* AddMakroNode - Fuegt eine Node an den Anfang einer Liste ein */
+void AddMakroNode(struct mnode **list, struct mnode *node)
+{
+
+ if (DEBUG & 32)
+ puts("AddMakroNode");
+
+ if (node) {
+ node->prev = NULL;
+ node->next = *list;
+ *list = node;
+ if (node->next)
+ node->next->prev = node;
+ }
+}
+
+
+/* AddStrNode - Fuegt eine Node in die Liste ein */
+void AddStrNode(struct strnode **list, struct strnode *node, char *str)
+{
+
+ if (DEBUG & 32)
+ puts("AddStrNode");
+
+
+ if (node || str) {
+ if (!node)
+ node = (struct strnode *) malloc(sizeof(struct strnode));
+ /* HIER: Rueckgabewert wegen Fehler ! */
+ if (!node) {
+ error(196);
+ } else {
+ node->prev = NULL;
+ node->next = *list;
+ if (str)
+ node->str = str;
+ *list = node;
+ if (node->next)
+ node->next->prev = node;
+ }
+ }
+}
+
+
+/* AddStrNodeBehind - Fuegt eine Node ans Ende der Liste ein */
+void AddStrNodeBehind(struct strnode **list, struct strnode *node, char *str)
+{
+ struct strnode *listnode;
+
+ if (DEBUG & 32)
+ puts("AddStrNodeBehind");
+
+
+ if (node || str) {
+ if (!node)
+ node = (struct strnode *) malloc(sizeof(struct strnode));
+ if (!node) {
+ error(196);
+ } else {
+ if (!*list) {
+ node->prev = NULL;
+ node->next = NULL;
+ *list = node;
+ } else {
+ listnode = *list;
+ while (listnode->next) {
+ listnode = listnode->next;
+ }
+ node->prev = listnode;
+ node->next = NULL;
+ listnode->next = node;
+ }
+ if (str)
+ node->str = str;
+ }
+ }
+}
+
+
+/* RemMakroNode - Entfernt eine Node aus der Liste ohne sie zu loeschen */
+void RemMakroNode(struct mnode **list, struct mnode *node)
+{
+
+ if (DEBUG & 32)
+ puts("RemMakroNode");
+
+
+ if (node->prev) {
+ if (node->next)
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+ } else {
+ if (node->next)
+ node->next->prev = NULL;
+ *list = node->next;
+ }
+ node->next = node->prev = NULL;
+}
+
+/* InsertMakroNode - Setzt eine Node hinter einer anderen ein */
+void InsertMakroNode(struct mnode **list, struct mnode *node, struct mnode *behind)
+{
+
+ if (DEBUG & 32)
+ puts("InsertMakroNode");
+
+
+ if (behind) {
+ node->prev = behind;
+ node->next = behind->next;
+ behind->next = node;
+ if (node->next)
+ node->next->prev = node;
+ } else
+ AddMakroNode(list, node);
+}
+
+/* RemStrNode - Entfernt eine Node aus der Liste ohne sie zu loeschen */
+void RemStrNode(struct strnode **list, struct strnode *node)
+{
+
+ if (DEBUG & 32)
+ puts("RemStrNode");
+
+
+ if (node->prev) {
+ if (node->next)
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+ } else {
+ if (node->next)
+ node->next->prev = NULL;
+ *list = node->next;
+ }
+ node->next = node->prev = NULL;
+}
+
+
+/* FindMakroNode - sucht den passenden Eintrag in der Liste
+ * len=0 - der gesamte String muss uebereinstimmen
+ * len>0 - die ersten len Zeichen muessen stimmen
+ */
+struct mnode *FindMakroNode(struct mnode *list, char *str, int len)
+{
+
+ if (DEBUG & 32)
+ puts("FindMakroNode");
+
+ while (list) {
+ if (len) {
+ if ((strlen(list->name) == len) && (!strncmp(list->name, str, len)))
+ return (list);
+ } else {
+ if (!strcmp(list->name, str))
+ return (list);
+ }
+ list = list->next;
+ }
+ return (0);
+}
+
+
+/* DelMakroNode - gibt den gesamten Speicher einer Node frei, ist list#NULL
+ * wird die Node vorher aus der Liste entfernt
+ */
+void DelMakroNode(struct mnode **list, struct mnode *node)
+{
+
+ if (DEBUG & 32)
+ puts("DelMakroNode");
+
+
+ if (node) {
+ if (list && *list)
+ RemMakroNode(list, node);
+ if (node->name)
+ free(node->name);
+ if (node->args)
+ free(node->args);
+ if (node->token)
+ free(node->token);
+ if (node->tokenlist)
+ DelStrList(&node->tokenlist);
+ free(node);
+ }
+}
+
+
+/* DelStrNode - gibt den gesamten Speicher einer Node frei, ist list#NULL
+ * wird die Node vorher aus der Liste entfernt
+ */
+void DelStrNode(struct strnode **list, struct strnode *node)
+{
+
+ if (DEBUG & 32)
+ puts("DelStrNode");
+
+
+ if (node) {
+ if (list && *list)
+ RemStrNode(list, node);
+ if (node->str)
+ free(node->str);
+ free(node);
+ }
+}
+
+void MergeStrNodes(struct strnode *prev, struct strnode *next)
+{
+ /* next will now be deleted and prev->str will be */
+ /* the joined strings from prev&next */
+ char *newstr;
+/*vb: */
+ char c, *s, *d;
+
+ if (DEBUG & 32)
+ puts("MergeStrNodes");
+
+
+ newstr = (char *) malloc(prev->len + next->len + 1);
+/*vb: string-Routinen ersetzt (hoffentlich schneller)
+ strcpy(newstr,prev->str);
+ strcat(newstr,next->str);
+ */
+ d = newstr;
+ s = prev->str;
+ do {
+ c = *s++;
+ *d++ = c;
+ } while (c);
+ d--;
+ s = next->str;
+ do {
+ c = *s++;
+ *d++ = c;
+ } while (c);
+
+ if (prev->str)
+ free(prev->str); /*vb: wenn prev->str==0 knallts doch schon oben? */
+ prev->str = newstr;
+ prev->len += next->len;
+ DelStrNode(NULL, next);
+}
+
+/* DelMakroList - loescht eine gesamte Liste */
+void DelMakroList(struct mnode **list)
+{
+
+ if (DEBUG & 32)
+ puts("DelMakroList");
+
+
+ while (*list)
+ DelMakroNode(list, *list);
+ /* *list=NULL; *//*vb: *list==0 */
+}
+
+
+/* DelStrList - loescht eine gesamte Liste samt der Nodes/Strings */
+void DelStrList(struct strnode **list)
+{
+
+ if (DEBUG & 32)
+ puts("DelStrList");
+
+
+ while (*list)
+ DelStrNode(list, *list);
+ /* *list=NULL; *//*vb: *list==0 */
+}
+
+/* AllocSpace - erzeugt eine StrNode vom Typ Space */
+struct strnode *AllocSpace()
+{
+ struct strnode *newnode;
+ char *newstr;
+
+
+ if (DEBUG & 32)
+ puts("AllocSpace");
+
+
+ newstr = (char *) malloc(2);
+ if (newstr) {
+ newstr[0] = ' ';
+ newstr[1] = 0;
+ newnode = (struct strnode *) malloc(sizeof(struct strnode));
+ if (newnode) {
+ newnode->str = newstr;
+ newnode->type = SPACE;
+ newnode->len = 1;
+ newnode->next = newnode->prev = NULL;
+ newnode->flags = newnode->number = 0;
+ return (newnode);
+ }
+ }
+ return (NULL);
+}
+
+
+/* CloneStrList - erstellt eine exakte Kopie der Liste oder eines Ausschnittes */
+/* wenn listend#NULL */
+struct strnode *CloneStrList(struct strnode *list, struct strnode *listend)
+{
+ struct strnode *prevnode = NULL, *newnode, *newlist = NULL;
+ char *newstr;
+
+ if (DEBUG & 32)
+ puts("CloneStrList");
+
+
+ while (list) {
+ newnode = (struct strnode *) malloc(sizeof(struct strnode));
+ if (!newnode) {
+ DelStrList(&newlist);
+ return (NULL);
+ }
+ newstr = (char *) malloc(list->len + 1);
+ if (!newstr) {
+ free(newnode);
+ DelStrList(&newlist);
+ return (NULL);
+ }
+ strcpy(newstr, list->str);
+ newnode->str = newstr;
+ newnode->len = list->len;
+ newnode->flags = list->flags;
+ newnode->type = list->type;
+ newnode->number = list->number;
+ newnode->next = NULL;
+ newnode->prev = prevnode;
+
+ if (prevnode)
+ prevnode->next = newnode;
+ else
+ newlist = newnode;
+ prevnode = newnode;
+
+ if (listend && list == listend)
+ list = NULL;
+ else
+ list = list->next;
+ }
+ return (newlist);
+}
+
+
+/* DoMakroFunction - erstellt eine StrList entsprechend des Function-Makros */
+struct strnode *DoMakroFunction(struct mnode *makro)
+{
+ struct strnode *result = NULL;
+ char *newstr = NULL, *timestr = NULL;
+ int len, type;
+ time_t timevalue;
+
+ if (DEBUG & 32)
+ puts("DoMakroFunction");
+
+
+ if (makro->flags & FUNCTION) {
+ switch (makro->funcnum) {
+ case FUNCLINE:
+ newstr = (char *) malloc(11);
+ if (!newstr)
+ return (NULL);
+ sprintf(newstr, "%lu", linenr);
+ len = strlen(newstr);
+ type = NUMBER;
+ break;
+ case FUNCFILE:
+ len = strlen(filenames[incnesting]);
+ newstr = (char *) malloc(len + 1 + 2);
+ if (!newstr)
+ return (NULL);
+ *newstr = '\"';
+ strcpy((newstr + 1), filenames[incnesting]);
+ strcat(newstr, "\"");
+ type = PP_STR;
+ break;
+ case FUNCDATE:
+ type = PP_STR;
+ newstr = (char *) malloc(14);
+ if (!newstr)
+ return (NULL);
+ timevalue = time(0);
+ timestr = ctime(&timevalue);
+ newstr[0] = '\"';
+ strncpy(newstr + 1, timestr + 4, 7); /* copy 'Mmm dd ' */
+ strcpy(newstr + 8, timestr + 20); /* copy 'yyyy' */
+ newstr[12] = '\"';
+ newstr[13] = 0;
+ len = 13;
+ break;
+ case FUNCTIME:
+ type = PP_STR;
+ newstr = (char *) malloc(11);
+ if (!newstr)
+ return (NULL);
+ timevalue = time(0);
+ timestr = ctime(&timevalue);
+ newstr[0] = '\"';
+ strncpy(newstr + 1, timestr + 11, 8); /* copy 'hh:mm:ss' */
+ newstr[9] = '\"';
+ newstr[10] = 0;
+ len = 10;
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+ result = (struct strnode *) malloc(sizeof(struct strnode));
+ if (!result) {
+ if (newstr)
+ free(newstr);
+ return (NULL);
+ }
+ result->prev = result->next = NULL;
+ result->str = newstr;
+ result->len = len;
+ result->number = result->flags = 0;
+ result->type = type;
+ }
+ return (result);
+}
+
+
+/* ******* String-Funktionen ****** */
+
+/* Str2List - parsed einen String in eine StrList */
+struct strnode *Str2List(char *str)
+{
+ struct strnode *newlist = NULL, *newnode = NULL;
+ char *temp, *string;
+ int length, type, flags;
+
+ if (DEBUG & 32)
+ puts("Str2List");
+
+ while (*str) {
+ flags = 0;
+/*vb: casts eingefuegt */
+ if (isspace((unsigned char) *str)) { /* Spaces parsen */
+ temp = str + 1;
+ length = 1;
+ while (*temp && isspace((unsigned char) *temp)) {
+ temp++;
+ length++;
+ }
+ type = SPACE;
+ } else if (*str == '\"') { /* String parsen */
+ temp = str + 1;
+ length = 2;
+ while (*temp && *temp != '\"')
+ if (*temp == '\\') {
+ temp += 2;
+ length += 2;
+ } else {
+ temp++;
+ length++;
+ }
+ type = PP_STR;
+ } else if (*str == '\'') { /* String parsen */
+ temp = str + 1;
+ length = 2;
+ while (*temp && *temp != '\'')
+ if (*temp == '\\') {
+ temp += 2;
+ length += 2;
+ } else {
+ temp++;
+ length++;
+ }
+ type = PP_STR;
+ } else if (isdigit((unsigned char) *str) || (*str == '.' && isdigit((unsigned char) *(str + 1)))) {
+ /* Zahlen parsen */
+ temp = str;
+ length = 0;
+ while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
+ temp++;
+ length++;
+ }
+ if (*temp == '.') {
+ temp++;
+ length++;
+ if (isdigit((unsigned char) *temp) || *temp == 'e' || *temp == 'E')
+ while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
+ temp++;
+ length++;
+ }
+ }
+ if (*(temp - 1) == 'e' || *(temp - 1) == 'E')
+ if (isdigit((unsigned char) *temp) || *temp == '+' || *temp == '-') {
+ temp++;
+ length++;
+ while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
+ temp++;
+ length++;
+ }
+ }
+ type = NUMBER;
+ } else if (isalpha((unsigned char) *str) || *str == '_') { /* moegl. Identifier parsen */
+ temp = str + 1;
+ length = 1;
+ while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
+ temp++;
+ length++;
+ }
+ type = PP_IDENT;
+ } else if (*str) { /* alles andere als einzelne Zeichen */
+ length = 1;
+ type = NORMAL;
+ }
+ string = (char *) malloc(length + 1);
+ if (!string) {
+ error(196);
+ DelStrList(&newlist);
+ return (NULL);
+ }
+ strncpy(string, str, length);
+ string[length] = 0;
+ str += length;
+
+ newnode = (struct strnode *) malloc(sizeof(struct strnode));
+ if (!newnode) {
+ error(196);
+ if (string)
+ free(string);
+ return (NULL);
+ }
+ newnode->str = string;
+ newnode->len = length;
+ newnode->flags = flags;
+ newnode->type = type;
+
+ AddStrNodeBehind(&newlist, newnode, NULL);
+ }
+ return (newlist);
+}
+
+/* List2Str - schreibt eine Liste als String zurueck */
+int List2Str(struct strnode *list, char *str, int maxchars)
+{
+ int len = 0;
+ char c, *p;
+
+ if (DEBUG & 32)
+ puts("List2Str");
+
+
+ *str = 0;
+ if (list) {
+ while (list) {
+ if ((len + (list->len)) > (maxchars - 1)) {
+ error(177);
+ return (0);
+ } else {
+ /*vb: */
+ p = list->str;
+ do {
+ c = *p++;
+ *str++ = c;
+ } while (c);
+ str--;
+/* strcat(str,list->str); */
+ len += list->len;
+ }
+ list = list->next;
+ }
+ return (len + 1);
+ } else {
+ *str = 0;
+ return (1);
+ }
+}
+
+/* ListLen - ermittelt die Laenge einer Str-Liste (in Zeichen) */
+int ListLen(struct strnode *list)
+{
+ int len = 0;
+ while (list) {
+ len += list->len;
+ list = list->next;
+ }
+ return (len);
+}
+
+/* ListStrLen - ermittelt die Laenge einer Str-List als String */
+/* d.h. mit " am Anfang und Ende, sowie einem \ vor */
+/* jedem \ und " */
+int ListStrLen(struct strnode *list)
+{
+ int len = 2;
+ while (list) {
+ if (list->type == SPACE)
+ len++;
+ else {
+ len += list->len;
+ if (list->type == PP_STR && list->str[0] == '\"')
+ len += 2;
+ else if (list->type == NORMAL && list->str[0] == '\\')
+ len++;
+ }
+ list = list->next;
+ }
+ return (len);
+}
+
+/* CopyList2StrStr - kopiert eine Str-List als String um */
+/* d.h. mit " am Anfang und Ende, sowie einem \ vor */
+/* jedem \ und " */
+CopyList2StrStr(struct strnode * list, char *str)
+{
+ int len;
+
+ if (DEBUG & 32)
+ puts("CopyList2StrStr");
+
+
+ str[0] = 0;
+ if (list) {
+ strcpy(str, "\"");
+ len = 1;
+ while (list) {
+ if (list->type == SPACE) {
+ len++;
+ strcat(str, " ");
+ } else {
+ len += list->len;
+ if (list->type == PP_STR && list->str[0] == '\"') {
+ strcat(str, "\\");
+ strncat(str, list->str, list->len - 1);
+ strcat(str, "\\\"");
+ } else if (list->type == NORMAL && list->str[0] == '\\') {
+ strcat(str, "\\");
+ strcat(str, list->str);
+ } else
+ strcat(str, list->str);
+ }
+ list = list->next;
+ }
+ strcat(str, "\"");
+ len++;
+ }
+ return (len);
+}
+
+/* NextToSpecial - checked, ob die StrNode neben einem # oder ## steht */
+int NextToSpecial(struct strnode *node)
+{
+ struct strnode *search;
+
+ if (DEBUG & 32)
+ puts("NextToSpecial");
+
+
+ if (node->prev) {
+ search = node->prev;
+ while (search && search->type == SPACE)
+ search = search->prev;
+ if (search && search->type == SPECIAL)
+ return (search->flags);
+ }
+ if (node->next) {
+ search = node->next;
+ while (search && search->type == SPACE)
+ search = search->next;
+ /* Hinter der Node ist ein # (ToString) ohne Bedeutung */
+ if (search && search->type == SPECIAL
+ && search->flags == KILLSPACES)
+ return (KILLSPACES);
+ }
+ return (NONE);
+}
+
+/* FindBracket - sucht das passende Gegenstueck zu der (, auf die Node zeigt */
+/* dabei werden verschachtelte Klammern beachtet */
+struct strnode *FindBracket(struct strnode *node)
+{
+
+ if (DEBUG & 32)
+ puts("FindBracket");
+
+
+ if (node && node->next && node->type == NORMAL && node->str[0] == '(') {
+ do {
+ node = node->next;
+ if (node && node->type == NORMAL) {
+ if (node->str[0] == ')')
+ return (node);
+ if (node->str[0] == '(')
+ node = FindBracket(node);
+ }
+ } while (node);
+ return (NULL);
+ } else
+ return (NULL);
+}
+
+/* CloneArg - gibt eine Liste zurueck, die das n. Argument des Makros enthaelt */
+struct strnode *CloneArg(struct strnode *list, int n, int *error)
+{
+ int argnum = 0;
+ struct strnode *start;
+
+ if (error)
+ *error = OK;
+
+ if (list) {
+ if (DEBUG & 32)
+ printf("CloneArg\n");
+ if (list->type == PP_IDENT)
+ list = list->next;
+ while (list && list->type == SPACE)
+ list = list->next;
+
+ if (list && list->type == NORMAL && list->str[0] == '(') {
+ list = list->next; /* Skip ( */
+
+ if (DEBUG & 32)
+ printf("- IDENT skipped, ( found\n");
+
+ while (list && (argnum < n)) {
+ if (list->type == NORMAL) {
+ if (list->str[0] == ')')
+ list = NULL;
+ if (list && list->str[0] == '(')
+ list = (FindBracket(list))->next;
+ if (list && list->str[0] == ',')
+ argnum++;
+ }
+ if (list)
+ list = list->next;
+ }
+
+ while (list && list->type == SPACE)
+ list = list->next;
+
+ if (list) {
+ if (list->type == NORMAL && (list->str[0] == ')' || list->str[0] == ',')) { /* HIER evtl. ein Space erzeugen */
+ return (NULL);
+ }
+ start = list;
+ } else {
+ if (error)
+ *error = ARG_EXPECTED;
+ return (NULL);
+ }
+
+ if (DEBUG & 32)
+ printf("- Okay, Arg-Start found: %s\n", start->str);
+
+ while (list && (argnum == n)) {
+ if (list->type == NORMAL) {
+ switch (list->str[0]) {
+ case ')':
+ case ',':
+ argnum++;
+ list = list->prev;
+ break;
+ case '(':
+ list = FindBracket(list);
+ default:
+ if (list)
+ list = list->next;
+ break;
+ }
+ } else if (list)
+ list = list->next;
+ }
+
+ while (list && list->type == SPACE)
+ list = list->prev;
+
+ if (DEBUG & 32)
+ printf("- Okay, Arg-End found: %s\n", list->str);
+ return (CloneStrList(start, list));
+
+ } else {
+ if (error)
+ *error = ARG_EXPECTED;
+ return (NULL);
+ }
+ } else
+ return (NULL);
+}
+
+/* ExpandArgMakro - ersetzt ein Makro mit Argumenten */
+int ExpandArgMakro(struct mnode *makro, struct strnode **list,
+ struct strnode **pos)
+{
+ struct strnode *clone, *temp, *temp1, *arg, *new;
+ struct strnode *prev, *next;
+ struct mnode *prevmakro;
+ char *newstr;
+ int spec, len, x;
+
+ clone = CloneStrList(makro->tokenlist, NULL);
+ if (!clone)
+ return (OUT_OF_MEM);
+
+ if (DEBUG & 32)
+ printf("ExpandArgMakro - Clone build.\n");
+
+ temp = clone;
+ while (temp) {
+ if (temp->type == ARGUMENT) {
+ arg = CloneArg(*pos, temp->number, &x);
+ if (!arg) {
+ DelStrList(&clone);
+ return (x);
+ }
+ if (DEBUG & 32) {
+ printf("ARGUMENT:\n");
+ PrintTL(arg);
+ printf("Argument found - ");
+ }
+ if (spec = NextToSpecial(temp)) {
+ /* nicht expandieren, nur einsetzen */
+ if (spec == TOSTRING) {
+
+ if (DEBUG & 32)
+ printf("next to #\n");
+ /* als String einsetzen */
+ new = (struct strnode *) malloc(sizeof(struct strnode));
+ if (!new) {
+ DelStrList(&clone);
+ DelStrList(&arg);
+ return (OUT_OF_MEM);
+ }
+ len = ListStrLen(arg);
+ newstr = (char *) malloc(len + 1);
+ if (!newstr) {
+ DelStrList(&clone);
+ DelStrList(&arg);
+ if (new)
+ free(new);
+ return (OUT_OF_MEM);
+ }
+ CopyList2StrStr(arg, newstr);
+ DelStrList(&arg);
+ new->len = len + 2;
+ new->flags = new->number = 0;
+ new->type = PP_STR;
+ new->str = newstr;
+
+ prev = temp->prev;
+ next = temp->next;
+ DelStrNode(NULL, temp); /* Argument */
+
+ while (prev && prev->type == SPACE) {
+ temp = prev->prev;
+ DelStrNode(&clone, prev);
+ prev = temp;
+ }
+
+ if (prev && prev->type == SPECIAL && prev->flags == TOSTRING) {
+ temp = prev->prev;
+ DelStrNode(&clone, prev);
+ prev = temp;
+ } else
+ ierror(0);
+
+ new->prev = prev;
+ if (prev)
+ prev->next = new;
+ else
+ clone = new;
+ new->next = next;
+ if (next)
+ next->prev = new;
+ temp = new;
+ } else {
+ /* Einfach nur einsetzen */
+ if (DEBUG & 32)
+ printf("next to ##\n");
+ prev = temp->prev;
+ next = temp->next;
+ DelStrNode(NULL, temp);
+ arg->prev = prev;
+ if (prev)
+ prev->next = arg;
+ else
+ clone = arg;
+ while (arg->next)
+ arg = arg->next;
+ arg->next = next;
+ if (next)
+ next->prev = arg;
+ temp = arg;
+ }
+ } else {
+ /* expandieren und einsetzen */
+ if (DEBUG & 32)
+ printf("normal arg\n");
+ if (x = ExpandList(&arg)) {
+ DelStrList(&clone);
+ DelStrList(&arg);
+ return (x);
+ }
+ if (DEBUG & 32) {
+ printf("expanded arg:\n");
+ PrintTL(arg);
+ }
+ prev = temp->prev;
+ next = temp->next;
+ DelStrNode(NULL, temp);
+ arg->prev = prev;
+ if (prev)
+ prev->next = arg;
+ else
+ clone = arg;
+ while (arg->next)
+ arg = arg->next;
+ arg->next = next;
+ if (next)
+ next->prev = arg;
+ temp = arg;
+ } /* of N2Special */
+ }
+ if (temp)
+ temp = temp->next;
+ }
+
+ if (DEBUG & 32)
+ printf("Arguments expanded.\n");
+
+ temp = clone;
+ while (temp) {
+ if (temp->type == SPECIAL && temp->flags == KILLSPACES) {
+ prev = temp->prev;
+ next = temp->next;
+ if ((prev->type == PP_IDENT || prev->type == NUMBER)) {
+ switch (next->type) {
+ case NUMBER: /* merge -> ident */
+ case PP_IDENT:
+ RemStrNode(&clone, next);
+ MergeStrNodes(prev, next);
+ next = temp->next;
+ /* next will now be deleted and prev->str will be */
+ /* the joined strings from prev&next */
+ default: /* no merge / del ## */
+ DelStrNode(&clone, temp);
+ temp = next;
+ break;
+ } /* of switch */
+ } else {
+ DelStrNode(&clone, temp);
+ temp = next;
+ }
+ }
+ if (temp)
+ temp = temp->next;
+ }
+
+ /* 'makro' aus mlist ausklinken */
+ prevmakro = makro->prev;
+ RemMakroNode(&mlist, makro);
+
+ /* alles expandieren */
+ if (!(x = ExpandList(&clone))) {
+ /* akt. StrNode durch clone-Liste ersetzen */
+
+ if (DEBUG & 32) {
+ printf("Complete Makro expanded\n");
+ PrintTL(clone);
+ }
+ /* clone anstelle von pos in list einsetzen */
+ prev = (*pos)->prev;
+ next = (*pos)->next;
+
+ DelStrNode(NULL, *pos);
+
+#ifdef bla
+ while (next && next->type == SPACE) {
+ temp = next->next;
+ DelStrNode(NULL, next); /* SPACE zwischen Makro und Args loeschen */
+ next = temp;
+ }
+#endif
+ while (next && next->type == SPACE)
+ next = next->next;
+ /* SPACE hinter Makro ueberspringen */
+
+ if (next && next->type == NORMAL && next->str[0] == '(') {
+ temp = next;
+ next = FindBracket(temp);
+ if (next)
+ next = next->next;
+ do {
+ temp1 = temp->next;
+ DelStrNode(NULL, temp); /* ARG-List hinter Makro loeschen */
+ temp = temp1;
+ } while (temp != next);
+ } else {
+ ierror(0);
+ }
+
+
+ /* vor clone ein SPACE einsetzen, wenn nicht PREV==SPACE */
+/*vb: hier !prev|| wegen Enforcerhit eingesetzt; waere prev&& besser? */
+ if (!prev || prev->type != SPACE) {
+ if (temp = AllocSpace()) {
+ temp->next = clone;
+ if (clone)
+ clone->prev = temp;
+ clone = temp;
+ }
+ }
+ clone->prev = prev;
+ if (prev)
+ prev->next = clone;
+ else
+ *list = clone;
+
+ while (clone->next)
+ clone = clone->next;
+ /* nach clone ein SPACE einsetzen, wenn nicht NEXT==SPACE */
+/*vb: hier !next|| wegen Enforcerhit eingesetzt; waere next&& besser? */
+ if (!next || next->type != SPACE) {
+ if (temp = AllocSpace()) {
+ temp->prev = clone;
+ if (clone)
+ clone->next = temp;
+ clone = temp;
+ }
+ }
+ *pos = clone;
+ clone->next = next;
+ if (next)
+ next->prev = clone;
+
+ /* 'makro' wieder einsetzen */
+ InsertMakroNode(&mlist, makro, prevmakro);
+ return (OK);
+ } else {
+ InsertMakroNode(&mlist, makro, prevmakro);
+ return (x);
+ }
+
+}
+
+/* ExpandList - ersetzt alle Makros in der Liste */
+int ExpandList(struct strnode **list)
+{
+ struct mnode *found, *before;
+ struct strnode *clone, *beforestr, *afterstr, *listtemp, *temp2,
+ *temp3;
+ int result = OK;
+
+ if (DEBUG & 32)
+ puts("ExpandList");
+
+
+ listtemp = *list;
+ while (listtemp) {
+
+ if (listtemp->type == PP_IDENT) {
+
+ found = FindMakroNode(mlist, listtemp->str, 0);
+ if (found) {
+/*vb: merken, ob mind. ein Makro expandiert wurde */
+ did_expand = 1;
+ if (found->flags & PARAMETER) {
+ /* Makro mit Argument(en) */
+ if (DEBUG & 32)
+ printf("Makro with args\n");
+
+ temp2 = listtemp->next;
+ while (temp2 && temp2->type == SPACE)
+ temp2 = temp2->next;
+
+ if (temp2 && temp2->type == NORMAL && temp2->str[0] == '(')
+ if (result = ExpandArgMakro(found, list, &listtemp))
+ return (result);
+
+ } else {
+
+ /* Makro ohne Argument */
+
+ /* ExpandNormMakro - expandiert ein Makro ohne Argumente */
+ /* Parameter: s.o. */
+
+ if (found->flags & FUNCTION) {
+ clone = DoMakroFunction(found);
+ } else {
+ clone = CloneStrList(found->tokenlist, NULL);
+ }
+ if (!clone)
+ return (OUT_OF_MEM);
+ /* akt. MakroNode ausklinken um rekursive Exp. zu verhindern */
+ before = found->prev;
+ RemMakroNode(&mlist, found);
+ if (!(result = ExpandList(&clone))) {
+ /* akt. StrNode durch clone-Liste ersetzen */
+ beforestr = listtemp->prev;
+ afterstr = listtemp->next;
+ DelStrNode(NULL, listtemp);
+ listtemp = afterstr;
+ clone->prev = beforestr;
+ if (beforestr)
+ beforestr->next = clone;
+ else
+ *list = clone;
+ while (clone->next)
+ clone = clone->next;
+ clone->next = afterstr;
+ if (afterstr)
+ afterstr->prev = clone;
+ /* akt. Makronode wieder einsetzen */
+ InsertMakroNode(&mlist, found, before);
+ } else {
+ /* akt. Makronode wieder einsetzen */
+ InsertMakroNode(&mlist, found, before);
+ return (result);
+ }
+ }
+ }
+ }
+ if (listtemp)
+ listtemp = listtemp->next;
+ }
+
+ return (OK);
+}
+
+
+/* ParseIdentifier - parsed den Input-Define-String und haengt das Makro */
+/* in die Liste */
+
+struct mnode *ParseIdentifier(char *str)
+{
+ int x, numargs = 0, flags = 0, len = 0;
+ char *name = NULL, *args = NULL, *token = NULL, *temp, *temp2, *argtemp;
+ struct mnode *newmakro, *found;
+ struct strnode *tokenlist = NULL, *templist, *arglist = NULL, *templist2;
+ struct strnode *next, *prev;
+
+ if (DEBUG & 32)
+ puts("ParseIdentifier");
+
+/*vb: casts eingefuegt */
+ while (isspace((unsigned char) *str)) {
+ str++;
+ }
+ if (!(isalpha((unsigned char) *str) || *str == '_')) {
+ error(178);
+ return (0);
+ }
+ temp = str;
+ while (isalnum((unsigned char) *temp) || (*temp == '_')) {
+ temp++;
+ len++;
+ }
+
+ /* auf schon vorhandene (evtl. FESTE) Definition suchen */
+ found = FindMakroNode(mlist, str, len);
+ if (found && (found->flags & NOREDEF)) {
+ error(179);
+ return (0);
+ }
+/*vb: */
+ if (1) {
+ /* Okay, ist egal, wie das alte Makro aussah */
+
+/*vb: */
+ if (found && !(c_flags[15] & USEDFLAG)) {
+ error(197);
+ }
+ temp = name = (char *) malloc(len + 1); /* Speicher fuer Name-String belegen */
+ if (!name) {
+ error(196);
+ return (0);
+ }
+ for (x = 0; x < len; x++) {
+ *temp++ = *str++;
+ } /* Namen kopieren */
+ *temp = 0;
+
+ if (*str == '(') {
+ flags |= PARAMETER;
+ str++; /* jump over '(' */
+ temp = str;
+ len = 0;
+/*vb: casts eingefuegt */
+ while (*temp && (*temp != ')'))
+ if (!(isspace((unsigned char) *temp))) {
+ len++;
+ temp++;
+ } else {
+ temp++;
+ }
+ if (*temp == 0) {
+ error(180);
+ if (name)
+ free(name);
+ return (0);
+ }
+ args = temp = (char *) malloc(len + 1);
+ if (!args) {
+ error(196);
+ if (name)
+ free(name);
+ return (0);
+ }
+ for (x = 0; x < len;)
+ if (!(isspace((unsigned char) *str))) {
+ x++;
+ *temp++ = *str++;
+ } else {
+ str++;
+ }
+ *temp = 0;
+ str++; /* jump over ')' */
+
+ /* Argumentliste parsen und auf Fehler pruefen */
+ temp = args;
+ while (*temp && (isalpha((unsigned char) *temp) || *temp == '_')) {
+ temp++;
+ while (*temp && (isalnum((unsigned char) *temp) || *temp == '_')) {
+ temp++;
+ }
+ if (!(*temp) || *temp == ',') {
+ numargs++;
+ if ((*temp == ',') && (isalpha((unsigned char) *(temp + 1)) || *(temp + 1) == '_'))
+ temp++;
+ }
+ }
+ if (*temp) {
+ if (args)
+ free(args);
+ if (name)
+ free(name);
+ if (*temp == ',') {
+ error(181);
+ } else {
+ error(182);
+ }
+ return (0);
+ }
+ }
+ while (isspace((unsigned char) *str))
+ str++; /* Skip Spaces */
+ /* HIER: pruefen, ob tokenlist erstellt werden konnte (leere tokenlist->ok) */
+ tokenlist = Str2List(str);
+ if (DEBUG & 32)
+ printf(" - build TokenList\n");
+ templist = tokenlist;
+ while (templist) {
+ if ((templist->type == NORMAL) && (!strcmp(templist->str, "#"))) {
+
+ if ((templist->next) && (templist->next->type == NORMAL)
+ && (!strcmp(templist->next->str, "#"))) {
+ /* ## KILLSPACES */
+ if ((templist->prev) && (templist->next->next)) {
+ templist->type = SPECIAL;
+ templist->flags = KILLSPACES;
+ DelStrNode(&tokenlist, templist->next);
+ } else {
+ error(183);
+ if (name)
+ free(name);
+ if (args)
+ free(args);
+ if (tokenlist)
+ DelStrList(&tokenlist);
+ return (0);
+ }
+ }
+ }
+ templist = templist->next;
+ }
+
+ /* Token parsen/kopieren */
+ if ((flags & PARAMETER)) { /* Argumente parsen */
+ arglist = NULL;
+ temp = temp2 = args;
+ while (*temp) {
+ len = 0;
+ while (*temp && *temp != ',') {
+ temp++;
+ len++;
+ }
+ if (*temp == ',')
+ temp++;
+ argtemp = (char *) malloc(len + 1);
+ if (!argtemp) {
+ error(196);
+ if (name)
+ free(name);
+ if (args)
+ free(args);
+ if (arglist)
+ DelStrList(&arglist);
+ if (tokenlist)
+ DelStrList(&tokenlist);
+ return (0);
+ }
+ strncpy(argtemp, temp2, len);
+ temp2 = temp;
+ *(argtemp + len) = 0;
+ AddStrNodeBehind(&arglist, NULL, argtemp);
+ }
+ templist = tokenlist;
+ while (templist) {
+ if (templist->type == PP_IDENT) {
+ x = 0;
+ templist2 = arglist;
+ while (templist2) {
+ if (!strcmp(templist->str, templist2->str)) {
+ templist->type = ARGUMENT;
+ templist->number = x;
+ }
+ x++;
+ templist2 = templist2->next;
+ }
+ }
+ templist = templist->next;
+ }
+ DelStrList(&arglist);
+ if (DEBUG & 32)
+ printf(" - Arguments found.\n");
+ /* #-Specials korrigieren, nachdem die Argumente erkannt wurden */
+ templist = tokenlist;
+ while (templist) {
+ if ((templist->type == NORMAL) && (!strcmp(templist->str, "#"))) {
+ if ((templist->next) && (templist->next->type == ARGUMENT)) {
+ templist->type = SPECIAL;
+ templist->flags = TOSTRING;
+ } else {
+ error(184);
+ if (name)
+ free(name);
+ if (args)
+ free(args);
+ if (arglist)
+ DelStrList(&arglist);
+ if (tokenlist)
+ DelStrList(&tokenlist);
+ return (0);
+ }
+ }
+ templist = templist->next;
+ }
+ if (DEBUG & 32)
+ printf(" - Special-# corrected.\n");
+ } else { /* Token kopieren */
+ temp = str;
+ len = 0;
+ while ((*temp) && (*temp != '\n')) {
+ temp++;
+ len++;
+ }
+ temp = token = (char *) malloc(len + 1);
+ if (!token) {
+ error(196);
+ if (name)
+ free(name);
+ if (args)
+ free(args);
+ if (tokenlist)
+ DelStrList(&tokenlist);
+ return (0);
+ }
+ for (x = 0; x < len; x++) {
+ *temp++ = *str++;
+ }
+ *temp = 0;
+ }
+
+
+ templist = tokenlist;
+ while (templist) {
+ if (templist->type == SPECIAL && templist->flags == KILLSPACES) {
+ next = templist->next;
+ prev = templist->prev;
+
+ /* Kill Spaces before/after ## */
+ while (prev && prev->type == SPACE) {
+ templist2 = prev->prev;
+ DelStrNode(&tokenlist, prev);
+ prev = templist2;
+ }
+ while (next && next->type == SPACE) {
+ templist2 = next->next;
+ DelStrNode(&tokenlist, next);
+ next = templist2;
+ }
+ if ((!next) || (!prev))
+ ierror(0);
+
+ if (next->type != ARGUMENT && prev->type != ARGUMENT) {
+ if ((prev->type == PP_IDENT || prev->type == NUMBER)) {
+ switch (next->type) {
+ case NUMBER: /* merge -> ident */
+ case PP_IDENT:
+ RemStrNode(&tokenlist, next);
+ MergeStrNodes(prev, next);
+ next = templist->next;
+ /* next will now be deleted and prev->str will be */
+ /* the joined strings from prev&next */
+ default: /* no merge / del ## */
+ DelStrNode(&tokenlist, templist);
+ templist = next;
+ break;
+ } /* of switch */
+ } else {
+ DelStrNode(&tokenlist, templist);
+ templist = next;
+ }
+ }
+ }
+ if (templist)
+ templist = templist->next;
+ }
+
+
+/* erst HIER bei allowredefinition=0 abfragen ?? */
+
+ if (newmakro = (struct mnode *) malloc(sizeof(struct mnode))) {
+ newmakro->name = name;
+ newmakro->args = args;
+ newmakro->token = token;
+ newmakro->tokenlist = tokenlist;
+ newmakro->flags = flags;
+ newmakro->funcnum = 0;
+ AddMakroNode(&mlist, newmakro);
+ } else {
+ error(196);
+ if (name)
+ free(name);
+ if (token)
+ free(token);
+ if (args)
+ free(args);
+ if (tokenlist)
+ DelStrList(&tokenlist);
+ }
+ return (newmakro);
+
+ } else {
+/*vb: das ist irgendwie Unsinn hier, glaube ich */
+ ierror(0);
+ /* HIER: ueberpruefen, ob Macrodefinitionen uebereinstimmen, sonst Error */
+ if (*temp == '(') {
+ if (found->flags & PARAMETER) {
+ temp++; /* skip ( */
+
+
+
+ } else {
+ error(185);
+ return (NULL);
+ }
+ }
+ /* HIER nur noch tokenlisten vergleichen */
+
+ }
+ if (DEBUG & 32)
+ printf("ParseIdent falls of\n");
+}
+
+
+/* PreParse - 3-Zeichen-Folgen ersetzen, \+CR Zeilen anhaengen, usw.. */
+
+int PreParse()
+{
+ char *src, *dest, *dest2;
+ int slen, dlen = 0;
+ int cat = 0; /*vb: um zu merken, ob Zeilen mit \ verbunden werden */
+ dest2 = string;
+
+ if (DEBUG & 32)
+ puts("PreParse");
+
+
+ if (!fgets(ppstring, MAXPPINPUT, in[incnesting])) {
+ if (cmtnesting)
+ error(186);
+/*vb: */
+/* if(ifstatus[incnesting]) error(186); */
+/* ifnesting--; */
+ if (DEBUG & 32)
+ printf("-- end of file ifnesting-1:%d\n\n", incnesting);
+ if (incnesting) {
+ fclose(in[incnesting]);
+ incnesting--;
+ return (pp_nextline());
+ } else
+ return (0);
+ } else if (DEBUG & 32)
+ printf("gets1:%s\n", ppstring); /*vb: */
+
+ if ((strlen(ppstring) == (MAXPPINPUT - 1)) && (ppstring[MAXPPINPUT - 2] != '\n')) {
+ error(177);
+ return (0);
+ }
+ zn[incnesting]++;
+ linenr = zn[incnesting];
+
+ do {
+ /* Zeilen einlesen, bis kein Kommentar mehr */
+
+ /* Zeilen einlesen bis kein \ mehr am Ende */
+ do {
+ /* Source-String an Dest-String anhaengen und ??x-Folgen ersetzen */
+/*vb: das killt sonst das angehaengte wieder */
+ if (cat == 0) {
+ dest = src = ppstring;
+ slen = 0;
+ }
+ do {
+ if (*src != '\n') {
+
+ if ((*src == '?') && (*(src + 1) == '?') && !(c_flags[16] & USEDFLAG)) {
+ switch (*(src + 2)) {
+ case '=':
+ *dest++ = '#';
+ src += 2;
+ break;
+ case '/':
+ *dest++ = '\\';
+ src += 2;
+ break;
+ case '\'':
+ *dest++ = '^';
+ src += 2;
+ break;
+ case '(':
+ *dest++ = '[';
+ src += 2;
+ break;
+ case ')':
+ *dest++ = ']';
+ src += 2;
+ break;
+ case '!':
+ *dest++ = '|';
+ src += 2;
+ break;
+ case '<':
+ *dest++ = '{';
+ src += 2;
+ break;
+ case '>':
+ *dest++ = '}';
+ src += 2;
+ break;
+ case '-':
+ *dest++ = '~';
+ src += 2;
+ break;
+ default:
+ *dest++ = *src;
+ break;
+ } /* of switch */
+ } else {
+ *dest++ = *src;
+ }
+
+ if (slen < MAXPPINPUT) {
+ slen++;
+ } else {
+ error(177);
+ return (0);
+ }
+ }
+ } while (*src++);
+
+ src = dest;
+ /* dest->lastchar+2/NULL+1 (dest-1)-> 0 (dest-2)->lastchar */
+ if (*(dest - 2) == '\\') {
+ /*vb: sollte das slen statt dlen sein? */
+ if (fgets(src, MAXPPINPUT - dlen, in[incnesting])) {
+ if (DEBUG & 32)
+ printf("gets2:%s\n", src); /*vb: */
+/* Hier auf LF+0 abfragen */
+ dest -= 2;
+ zn[incnesting]++;
+ cat = 1; /*vb: merken, dass Zeilen verbunden wurden */
+ }
+ }
+ } while (*dest == '\\');
+
+ src = ppstring;
+ while (*src) {
+ /* ' Strings ueberlesen */
+ if ((*src == '\'') && (!cmtnesting)) {
+ if (dlen < MAXINPUT) {
+ *dest2++ = *src++;
+ dlen++;
+ } else {
+ error(177);
+ return (0);
+ }
+ while (*src && *src != '\'') {
+ if (*src == '\\') {
+ *dest2++ = *src++;
+ dlen++;
+ };
+ if (dlen < MAXINPUT) {
+ *dest2++ = *src++;
+ dlen++;
+ } else {
+ error(177);
+ return (0);
+ }
+ }
+ if (dlen < MAXINPUT) {
+ *dest2++ = *src++;
+ dlen++;
+ } else {
+ error(177);
+ return (0);
+ }
+ }
+ /* " Strings ueberlesen */
+ if ((*src == '\"') && (!cmtnesting)) {
+ *dest2++ = *src++;
+ dlen++;
+ while (*src && *src != '\"') {
+ if (*src == '\\') {
+ *dest2++ = *src++;
+ dlen++;
+ };
+ if (dlen < MAXINPUT) {
+ *dest2++ = *src++;
+ dlen++;
+ } else {
+ error(177);
+ return (0);
+ }
+ }
+ if (dlen < MAXINPUT) {
+ *dest2++ = *src++;
+ dlen++;
+ } else {
+ error(177);
+ return (0);
+ }
+ }
+ /* Kommentare weglassen */
+ if ((*src == '/') && (*(src + 1) == '*')) {
+ src += 2;
+ if (dlen < MAXINPUT) {
+ *dest2++ = ' ';
+ dlen++;
+ } else {
+ error(177);
+ return (0);
+ }
+ if ((cmtnesting && (c_flags[13] & USEDFLAG)) || (!cmtnesting))
+ cmtnesting++;
+ else
+ error(198);
+ } else {
+ if ((*src == '*') && (*(src + 1) == '/') && cmtnesting) {
+ src += 2;
+ cmtnesting--;
+ }
+ }
+
+ /* C++-Comment weglassen */
+ if ((!cmtnesting) && (*src == '/') && (*(src + 1) == '/') && (c_flags[14] & USEDFLAG))
+ *src = 0;
+
+ if (!cmtnesting) {
+ if (*src) {
+ *dest2++ = *src++;
+ }
+ if (dlen < MAXINPUT) {
+ dlen++;
+ } else {
+ error(177);
+ return (0);
+ }
+ } else {
+ if (*src)
+ src++;
+ }
+ }
+
+ if (cmtnesting) {
+ if (!fgets(ppstring, MAXPPINPUT, in[incnesting])) {
+ if (cmtnesting)
+ error(186);
+ if (incnesting) {
+ fclose(in[incnesting]);
+ incnesting--;
+ return (pp_nextline());
+ } else
+ return (0);
+ } else if (DEBUG & 32)
+ printf("gets2:%s\n", ppstring); /*vb: */
+
+ if ((strlen(ppstring) == (MAXPPINPUT - 1)) && (ppstring[MAXPPINPUT - 2] != '\n')) {
+ error(177);
+ return (0);
+ }
+ zn[incnesting]++;
+ }
+ } while (cmtnesting);
+
+/*vb: das ueberschreibt den Speicher */
+#if 0
+ *dest2-- = 0;
+ while (isspace(*dest2))
+ *dest2-- = 0; /* Spaces killen */
+#endif
+
+/*vb: hoffe, das ist besser */
+ *dest2 = 0;
+ while (dest2 > string && isspace((unsigned char) *--dest2))
+ *dest2 = 0;
+
+
+ return (1);
+}
+
+/* **************** PreProcessor ***************** */
+
+int pp_init(void)
+{
+ char *macroname;
+ struct mnode *macronode;
+
+ if (!(c_flags[6] & USEDFLAG))
+ printf("%s\n", pp_version);
+
+ incnesting = /*ifnesting= */ -1; /*vb: */
+ cmtnesting = if_cnt = abs_if_cnt = 0;
+ mlist = NULL;
+ strlist = NULL;
+
+ macroname = (char *) malloc(9);
+ if (!macroname)
+ return (0);
+ strcpy(macroname, "__LINE__");
+ macronode = (struct mnode *) malloc(sizeof(struct mnode));
+ if (!macronode) {
+ if (macroname)
+ free(macroname);
+ return (0);
+ }
+ macronode->name = macroname;
+ macronode->args = macronode->token = NULL;
+ macronode->tokenlist = NULL;
+ macronode->flags = FUNCTION | NODELETE | NOREDEF;
+ macronode->funcnum = FUNCLINE;
+ AddMakroNode(&mlist, macronode);
+
+ macroname = (char *) malloc(9);
+ if (!macroname)
+ return (0);
+ strcpy(macroname, "__FILE__");
+ macronode = (struct mnode *) malloc(sizeof(struct mnode));
+ if (!macronode) {
+ if (macroname)
+ free(macroname);
+ DelMakroList(&mlist);
+ return (0);
+ }
+ macronode->name = macroname;
+ macronode->args = macronode->token = NULL;
+ macronode->tokenlist = NULL;
+ macronode->flags = FUNCTION | NODELETE | NOREDEF;
+ macronode->funcnum = FUNCFILE;
+ AddMakroNode(&mlist, macronode);
+
+ macroname = (char *) malloc(9);
+ if (!macroname)
+ return (0);
+ strcpy(macroname, "__DATE__");
+ macronode = (struct mnode *) malloc(sizeof(struct mnode));
+ if (!macronode) {
+ if (macroname)
+ free(macroname);
+ DelMakroList(&mlist);
+ return (0);
+ }
+ macronode->name = macroname;
+ macronode->args = macronode->token = NULL;
+ macronode->tokenlist = NULL;
+ macronode->flags = FUNCTION | NODELETE | NOREDEF;
+ macronode->funcnum = FUNCDATE;
+ AddMakroNode(&mlist, macronode);
+
+ macroname = (char *) malloc(9);
+ if (!macroname)
+ return (0);
+ strcpy(macroname, "__TIME__");
+ macronode = (struct mnode *) malloc(sizeof(struct mnode));
+ if (!macronode) {
+ if (macroname)
+ free(macroname);
+ DelMakroList(&mlist);
+ return (0);
+ }
+ macronode->name = macroname;
+ macronode->args = macronode->token = NULL;
+ macronode->tokenlist = NULL;
+ macronode->flags = FUNCTION | NODELETE | NOREDEF;
+ macronode->funcnum = FUNCTIME;
+ AddMakroNode(&mlist, macronode);
+
+ macroname = (char *) malloc(9);
+ if (!macroname)
+ return (0);
+ strcpy(macroname, "__STDC__");
+ macronode = (struct mnode *) malloc(sizeof(struct mnode));
+ if (!macronode) {
+ if (macroname)
+ free(macroname);
+ DelMakroList(&mlist);
+ return (0);
+ }
+ macronode->name = macroname;
+ macronode->args = NULL;
+ macroname = (char *) malloc(2);
+ if (!macroname) {
+ if (macronode->name)
+ free(macronode->name);
+ if (macronode)
+ free(macronode);
+ DelMakroList(&mlist);
+ return (0);
+ }
+ strcpy(macroname, "1");
+ macronode->token = macroname;
+ macronode->tokenlist = Str2List(macroname);
+ if (!macronode->tokenlist) {
+ if (macronode->name)
+ free(macronode->name);
+ if (macronode->token)
+ free(macronode->token);
+ if (macronode)
+ free(macronode);
+ DelMakroList(&mlist);
+ return (0);
+ }
+ macronode->flags = NODELETE;
+ macronode->funcnum = 0;
+ AddMakroNode(&mlist, macronode);
+
+ return (1);
+}
+
+
+void pp_free(void)
+{
+ int i;
+
+ if (DEBUG & 32)
+ puts("pp_free");
+
+/*vb: Schleifenindex korrekt gesetzt */
+ for (i = incnesting; i >= 0; i--)
+ if (in[i])
+ fclose(in[i]);
+ DelMakroList(&mlist);
+ DelStrList(&strlist);
+}
+
+int pp_include(char *f)
+{
+ if (DEBUG & 32)
+ printf("trying to include %s\n", f); /*vb: */
+
+ if (incnesting >= MAXINCNESTING - 1) {
+ error(187);
+ return (0);
+ }
+/*vb: */
+/* if(ifnesting>=MAXIFNESTING-1) {error("Too many nested #ifs or #includes",0);return(0);} */
+ incnesting++;
+ /* ifnesting++; *//*vb: */
+ ifstatus[incnesting] = 0; /*vb: */
+
+ if (DEBUG & 32)
+ printf("-- include: ifnesting:%d ifstatus:0 \n\n", incnesting);
+
+ in[incnesting] = fopen(f, "r");
+ if (!in[incnesting]) {
+ incnesting--;
+ return (0);
+ }
+ filenames[incnesting] = f;
+ zn[incnesting] = linenr = 0;
+ return (1);
+}
+
+
+
+/* ********************** Main-Function ******************* */
+int pp_nextline(void)
+{
+ char *src, *dest, *temp;
+ int complete_len, len, i, result;
+ struct mnode *makro;
+ struct strnode *linelist, *inclinelist;
+
+ if (DEBUG & 32)
+ puts("pp_nextline");
+
+ dest = string;
+ dest[0] = 0;
+
+ /* String vorbereiten, 3ZF ersetzen, \-Zeilen anhaengen, Kommentare loeschen */
+ if (!PreParse())
+ return (0);
+
+ /* Ueberpruefung auf PreProcessor-Commands */
+ src = string;
+/*vb: casts eingefuegt */
+ while (isspace((unsigned char) *src)) {
+ src++;
+ } /* SkipSpaces */
+
+ if (*src == '#') { /* #-Direktive gefunden */
+ src++; /* # ueberlesen */
+
+ while (isspace((unsigned char) *src)) {
+ src++;
+ } /* SkipSpaces */
+
+/*vb: Direktiven, die nichts mit #if etc. zu tun haben, nach hinten */
+
+
+/* IFDEF */
+ if (!strncmp(src, "ifdef", 5)) {
+ src += 5;
+ abs_if_cnt++; /*vb: */
+ if (isspace((unsigned char) *src)) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+ /* identifier suchen */
+ if (do_output) {
+/*vb: */
+/* if(ifnesting>=MAXIFNESTING-1) {error("Too many nested #if's",0); return(0);} */
+/* ifnesting++; */
+ temp = src;
+ len = 0;
+ while ((isalnum((unsigned char) *temp)) || (*temp == '_')) {
+ temp++;
+ len++;
+ }
+ makro = FindMakroNode(mlist, src, len);
+ if (DEBUG & 32)
+ printf("-- #ifdef found, ");
+ if (makro) {
+/*vb: */
+ ifstatus[incnesting] = 1; /* Bedingung == TRUE */
+ if (DEBUG & 32)
+ printf(" condition '%s' found (TRUE)\n", makro->name);
+ } else {
+/*vb: */
+ ifstatus[incnesting] = 2; /* Bedingung == FALSE */
+ do_output = 0;
+ if (DEBUG & 32)
+ printf(" condition not found (FALSE)\n\n");
+ }
+ } else {
+ if_cnt++;
+ if (DEBUG & 32)
+ printf("-- #ifdef found and if_cnt increased\n\n");
+ }
+ string[0] = 0; /*vb: yo */
+ return (1);
+ }
+ } /* EO IFDEF */
+ /* IFNDEF */
+ if (!strncmp(src, "ifndef", 6)) {
+ src += 6;
+ abs_if_cnt++; /*vb: */
+ if (isspace((unsigned char) *src)) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+
+ /* identifier suchen */
+ if (do_output) {
+/*vb: */
+/* if(ifnesting>=MAXIFNESTING-1) {error("Too many nested #if's",0); return(0);} */
+/* ifnesting++; */
+ temp = src;
+ len = 0;
+ while ((isalnum((unsigned char) *temp)) || (*temp == '_')) {
+ temp++;
+ len++;
+ }
+ if (DEBUG & 32)
+ printf("-- FindMakroNode: len=%d temp=%p\n", len, (void*)temp);
+ makro = FindMakroNode(mlist, src, len);
+ if (DEBUG & 32)
+ printf("-- #ifndef found, ");
+ if (!makro) {
+/*vb: */
+ ifstatus[incnesting] = 1; /* Bedingung == TRUE (Makro not existing) */
+ if (DEBUG & 32)
+ printf(" condition not found (TRUE)\n\n");
+ } else {
+/*vb: */
+ ifstatus[incnesting] = 2; /* Bedingung == FALSE */
+ do_output = 0;
+ if (DEBUG & 32)
+ printf(" condition '%s' found (FALSE)\n\n", makro->name);
+ }
+ /* HIER: string[0]=0; */
+ } else {
+ if_cnt++;
+ if (DEBUG & 32)
+ printf("-- #ifndef found and if_cnt increased\n\n");
+ }
+ string[0] = 0; /*vb: */
+ return (1);
+ }
+ } /* EO IFNDEF */
+ /* IF */
+ if (!strncmp(src, "if", 2)) {
+ src += 2;
+ abs_if_cnt++; /*vb: */
+ if (isspace((unsigned char) *src)) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+ /* Bedingung auswerten */
+
+
+
+ printf("****** WARNING ******* #if is not yet implemented\n");
+
+
+ string[0] = 0; /*vb: */
+ return (1);
+ }
+ } /* EO IF */
+ /* ELIF */
+ if (!strncmp(src, "elif", 4)) {
+ src += 4;
+ if (isspace((unsigned char) *src)) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+ /* Bedingung auswerten */
+
+
+
+
+
+ printf("****** WARNING ******* #elif is not yet implemented\n");
+
+
+
+
+ string[0] = 0; /*vb: */
+ return (1);
+ }
+ } /* EO ELIF */
+ /* ELSE */
+ if (!strncmp(src, "else", 4)) {
+ src += 4;
+ if (isspace((unsigned char) *src) || *src == 0) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+
+ if (!if_cnt) {
+ switch (ifstatus[incnesting]) { /*vb: */
+ case 0:
+ error(188);
+ return (0);
+ break;
+ case 1:
+ do_output = 0;
+ /* HIER: auf #endif suchen SearchENDIF(); */
+ /* HIER: ifnesting--; do_output=1; */
+ break;
+ case 2:
+ ifstatus[incnesting] = 3; /*vb: */
+ do_output = 1;
+ break;
+ case 3:
+ error(189);
+ return (0);
+ break;
+ }
+ }
+ string[0] = 0; /*vb: */
+ return (1);
+ }
+ } /* EO ELSE */
+ /* ENDIF */
+ if (!strncmp(src, "endif", 5)) {
+ src += 5;
+ abs_if_cnt--; /*vb: */
+ if (isspace((unsigned char) *src) || *src == 0) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+ /* HIER: Auf Zeilenende testen */
+
+ if (DEBUG & 32)
+ printf("-- #endif found, ");
+
+ if (if_cnt) {
+ if_cnt--;
+ if (DEBUG & 32)
+ printf("if_cnt decreased (to %d)\n", if_cnt);
+ } else {
+ if (DEBUG & 32)
+ printf("ifnesting: %d ifstatus: %d\n", incnesting, ifstatus[incnesting]);
+ if (abs_if_cnt < 0 /*(incnesting==-1)||ifstatus[incnesting]==0 */ ) { /*vb: */
+ error(190);
+ return (0);
+ }
+ /* ifnesting--; *//*vb: */
+ /* HIER: evtl. do_output entsprechend ifstatus[] setzen */
+ /*vb: natuerlich */
+ do_output = 1;
+ ifstatus[incnesting] = abs_if_cnt > 0; /*vb: 1 oder 0 */
+ }
+ string[0] = 0; /*vb: ja */
+ return (1);
+ }
+ } /* EO ENDIF */
+ /*vb: andere Direktiven gegebenenfalls ueberspringen */
+ if (!do_output) {
+ if (DEBUG & 32)
+ printf("do_output==0 => skipping: %s\n", src);
+ string[0] = 0;
+ return (1);
+ }
+/* DEFINE */
+ if ( /*(do_output)&& */ (!strncmp(src, "define", 6))) { /*vb: */
+ if (DEBUG & 32)
+ printf("#define found\n");
+ src += 6;
+ if (isspace((unsigned char) *src)) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+ if (ParseIdentifier(src)) {
+ string[0] = 0;
+ return (1);
+ } else {
+ if (DEBUG & 32)
+ printf("ParseIdent returned 0\n");
+ return (0);
+ }
+ }
+ } /* EO DEFINE */
+ /* UNDEF */
+ if ( /*(do_output)&& */ (!strncmp(src, "undef", 5))) { /*vb: */
+ src += 5;
+ if (isspace((unsigned char) *src)) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+ temp = src;
+ len = 0;
+ while ((isalnum((unsigned char) *temp)) || (*temp == '_')) {
+ temp++;
+ len++;
+ }
+ makro = FindMakroNode(mlist, src, len);
+ if (makro->flags & NODELETE) {
+ error(199);
+ } else {
+ DelMakroNode(&mlist, makro);
+ }
+ while (isspace((unsigned char) *temp)) {
+ temp++;
+ }
+ if (*temp != 0 && *temp != '\n') {
+ error(200);
+ }
+ string[0] = 0;
+ return (1);
+ }
+ } /* EO UNDEF */
+ /* INCLUDE */
+ if ( /*(do_output)&& */ (!strncmp(src, "include", 7))) { /*vb: */
+ src += 7;
+ if (isspace((unsigned char) *src)) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+ if (*src != '<' && *src != '\"') {
+ /* Versuchen den Rest zu expandieren */
+ inclinelist = Str2List(src);
+ if (!ExpandList(&inclinelist)) {
+ if (List2Str(inclinelist, src, MAXINPUT - (src - string))) {
+ /* HIER exit ? */
+ }
+ } else {
+ error(191); /* HIER exit ? */
+ }
+ }
+/*vb: geaendert, so dass #include "..." auch noch im Standardpfad sucht */
+ if (DEBUG & 32)
+ printf("includename=%s\n", src);
+ if (*src == '<' || *src == '\"') {
+ char *m = src, c;
+ if (*src == '<')
+ c = '>';
+ else
+ c = '\"';
+ if (*src == '\"') {
+ /* im aktuellen Verzeichnis suchen und includen */
+ src++;
+ temp = src;
+ len = 0;
+ while (*temp != '\"') {
+ temp++;
+ len++;
+ }
+ temp++;
+ while (isspace((unsigned char) *temp))
+ temp++;
+ if (*temp) {
+ error(200);
+ }
+ temp = (char *) malloc(len + 1);
+ if (temp) {
+ strncpy(temp, src, len);
+ *(temp + len) = 0;
+ if (pp_include(temp)) {
+ AddStrNode(&strlist, NULL, temp);
+ string[0] = 0;
+ return (1);
+ } else {
+ if (temp)
+ free(temp);
+/*vb:
+ error("pp: cannot open file to include",0);
+ return(0); */
+ }
+ } else {
+ error(196);
+ } /* HIER: Exit? */
+ }
+ /* in den Standard-Verzeichnissen suchen und includen */
+ src = m;
+ src++;
+ temp = src;
+ len = 0;
+ while (*temp != c && *temp != 0) {
+ temp++;
+ len++;
+ } /*vb: sicherer */
+ temp++;
+ while (isspace((unsigned char) *temp))
+ temp++;
+ if (*temp) {
+ error(200);
+ }
+ temp = NULL;
+ for (i = 0; i < incpathc; i++) {
+ complete_len = strlen(incpath[i]) + len;
+ temp = (char *) malloc(complete_len + 1);
+ if (temp) {
+ strcpy(temp, incpath[i]);
+ strncat(temp, src, len);
+ *(temp + complete_len) = 0;
+ if (pp_include(temp)) {
+ AddStrNode(&strlist, NULL, temp);
+ if (DEBUG & 32)
+ printf("include <%s> found\n", temp);
+ string[0] = 0;
+ return (1);
+ } else {
+ if (temp)
+ free(temp);
+ }
+ } else {
+ error(196);
+ } /* HIER: Exit ? */
+ } /* of FOR i */
+ error(191);
+ return (0);
+ } else {
+ error(192);
+ return (0);
+ }
+ } else {
+ error(193);
+ return (0);
+ }
+ } /* EO INCLUDE */
+ /* LINE */
+ if (!strncmp(src, "line", 4)) {
+ src += 4;
+ if (isspace((unsigned char) *src)) {
+ return (1); /* Ignorieren und an Compiler weiterreichen */
+ }
+ } /* EO LINE */
+ /* ERROR */
+ if (!strncmp(src, "error", 5)) {
+ src += 5;
+ if (isspace((unsigned char) *src)) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+
+ return (1);
+ }
+ } /* EO ERROR */
+ /* PRAGMA */
+ if (!strncmp(src, "pragma", 6)) {
+ src += 6;
+ if (isspace((unsigned char) *src)) {
+ while (isspace((unsigned char) *src)) {
+ src++;
+ }
+
+ return (1);
+ }
+ } /* EO PRAGMA */
+ /* Unknown */
+ /* if(do_output){ */
+ /*vb: */
+ error(193);
+ return (0);
+ /* } *//*vb: */
+ } else if (do_output) {
+ /* Normale Anweisung. Komplette Zeile expandieren */
+
+/*vb: */
+
+ linelist = Str2List(string);
+
+ if (DEBUG & 32)
+ PrintTL(linelist);
+
+/*vb: */
+ did_expand = 0;
+
+ if (result = ExpandList(&linelist)) {
+ switch (result) {
+ case OUT_OF_MEM:
+ error(196);
+ break;
+ case NUM_OF_ARGS:
+ error(194);
+ break;
+ case ARG_EXPECTED:
+ error(195);
+ break;
+ default:
+ ierror(0);
+ break;
+ }
+ DelStrList(&linelist);
+ return (0);
+ }
+ if (DEBUG & 32)
+ PrintTL(linelist);
+
+/*vb: List2Str nur aufrufen, falls etwas expandiert wurde */
+ if (did_expand && !List2Str(linelist, string, MAXINPUT)) {
+ DelStrList(&linelist);
+ return (0);
+ }
+ DelStrList(&linelist);
+
+/*vb: */
+ } else
+ string[0] = 0;
+ return (1);
+}
diff --git a/range.c b/range.c
new file mode 100644
index 0000000..6696f95
--- /dev/null
+++ b/range.c
@@ -0,0 +1,322 @@
+/* $VER: vbcc (range.c) $Revision: 1.1 $ */
+/* range analysis and related optimizations */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+
+#define RANGESIZE (sizeof(range)*(vcount+1))
+
+range *rangebuf;
+
+static void clear_range(range *p,int i)
+{
+ Var *v;
+ int t;
+
+ v=vilist[i];
+ t=v->vtyp->flags;
+ if(ISINT(t)){
+ if(t&UNSIGNED){
+ p[i].min.vumax=Z0;
+ p[i].max.vumax=tu_max[t&NQ];
+ }else{
+ p[i].min.vmax=t_min[t&NQ];
+ p[i].max.vmax=t_max[t&NQ];
+ }
+ }
+}
+
+void print_ranges(FILE *f,range *p)
+{
+ int i,t;
+ Var *v;
+ for(i=0;i<vcount-rcount;i++){
+ v=vilist[i];
+ t=v->vtyp->flags;
+ if(ISINT(t)){
+ fprintf(f,"%03d %s (%p): ",i,v->identifier,v);
+ if(t&UNSIGNED){
+ printzum(f,p[i].min.vumax);
+ fprintf(f,"...");
+ printzum(f,p[i].max.vumax);
+ }else{
+ printzm(f,p[i].min.vmax);
+ fprintf(f,"...");
+ printzm(f,p[i].max.vmax);
+ }
+ fprintf(f,"\n");
+ }
+ }
+}
+
+static void combine_ranges(range *d,range *n)
+{
+ int i,t;
+ Var *v;
+ for(i=0;i<vcount-rcount;i++){
+ v=vilist[i];
+ t=v->vtyp->flags;
+ if(ISINT(t)){
+ if(t&UNSIGNED){
+ if(zumleq(n[i].min.vumax,d[i].min.vumax))
+ d[i].min.vumax=n[i].min.vumax;
+ if(zumleq(d[i].max.vumax,n[i].max.vumax))
+ d[i].max.vumax=n[i].max.vumax;
+ }else{
+ if(zmleq(n[i].min.vmax,d[i].min.vmax))
+ d[i].min.vmax=n[i].min.vmax;
+ if(zmleq(d[i].max.vmax,n[i].max.vmax))
+ d[i].max.vmax=n[i].max.vmax;
+ }
+ }
+ }
+}
+
+static int update_ranges(range *d,range *n)
+{
+ int i,t,change=0;
+ Var *v;
+ for(i=0;i<vcount-rcount;i++){
+ v=vilist[i];
+ t=v->vtyp->flags;
+ if(ISINT(t)){
+ if(t&UNSIGNED){
+ if(!zumeqto(n[i].min.vumax,d[i].min.vumax)){
+ d[i].min.vumax=n[i].min.vumax;
+ change=1;
+ }
+ if(!zumeqto(d[i].max.vumax,n[i].max.vumax)){
+ d[i].max.vumax=n[i].max.vumax;
+ change=1;
+ }
+ }else{
+ if(!zmeqto(n[i].min.vmax,d[i].min.vmax)){
+ d[i].min.vmax=n[i].min.vmax;
+ change=1;
+ }
+ if(!zmeqto(d[i].max.vmax,n[i].max.vmax)){
+ d[i].max.vmax=n[i].max.vmax;
+ change=1;
+ }
+ }
+ }
+ }
+ return change;
+}
+
+void do_ranges(range *d,IC *p)
+{
+ int i,j,t,c=p->code;
+ if((p->z.flags&(VAR|DREFOBJ))==VAR){
+ i=p->z.v->index;
+ t=p->z.v->vtyp->flags;
+ if(c==ASSIGN){
+ if((p->typf&NU)!=(t&NU)){
+ clear_range(d,i);
+ }else if((p->q1.flags&(KONST|DREFOBJ))==KONST){
+ eval_const(&p->q1.val,t);
+ if(t&UNSIGNED)
+ d[i].min.vumax=d[i].max.vumax=vumax;
+ else
+ d[i].min.vmax=d[i].max.vmax=vmax;
+ }else if((p->q1.flags&(VAR|DREFOBJ))==VAR&&(p->q1.v->vtyp->flags&NU)==(t&NU)){
+ j=p->q1.v->index;
+ d[i].min=d[j].min;
+ d[i].max=d[j].max;
+ }else
+ clear_range(d,i);
+ }else{
+ clear_range(d,i);
+ }
+ }else{
+ j=p->change_cnt;
+ for(i=0;i<j;i++){
+ if(!(p->change_list[i].flags&DREFOBJ))
+ clear_range(d,p->change_list[i].v->index);
+ }
+ }
+}
+
+static void insert_max(range *p,int t)
+{
+ if(t&UNSIGNED){
+ if(!zumleq(p->max.vumax,vumax))
+ p->max.vumax=vumax;
+ if(!zumleq(p->min.vumax,p->max.vumax))
+ p->min.vumax=vumax;
+ }else{
+ if(!zmleq(p->max.vmax,vmax))
+ p->max.vmax=vmax;
+ if(!zmleq(p->min.vmax,p->max.vmax))
+ p->min.vmax=vmax;
+ }
+}
+
+static void insert_min(range *p,int t)
+{
+ if(t&UNSIGNED){
+ if(!zumleq(vumax,p->min.vumax))
+ p->min.vumax=vumax;
+ if(!zumleq(p->min.vumax,p->max.vumax))
+ p->max.vumax=vumax;
+ }else{
+ if(!zmleq(vmax,p->min.vmax))
+ p->min.vmax=vmax;
+ if(!zmleq(p->min.vmax,p->max.vmax))
+ p->max.vmax=vmax;
+ }
+}
+
+static void inc_val(int t)
+{
+ if(t&UNSIGNED){
+ if(!zumeqto(vumax,tu_max[t&NU]))
+ vumax=zumadd(vumax,ZU1);
+ }else{
+ if(!zmeqto(vmax,t_max[t&NU]))
+ vmax=zmadd(vmax,Z1);
+ }
+}
+
+static void dec_val(int t)
+{
+ if(t&UNSIGNED){
+ if(!zumeqto(vumax,ZU0))
+ vumax=zumsub(vumax,ZU1);
+ }else{
+ if(!zmeqto(vmax,t_min[t&NU]))
+ vmax=zmsub(vmax,Z1);
+ }
+}
+
+void range_analysis(flowgraph *fg)
+{
+ flowgraph *g;
+ range *bp,*erange,*crange;
+ Var *v;
+ int i,t,done,pass;
+ rangebuf=mymalloc(RANGESIZE*(2*basic_blocks+3));
+ bp=rangebuf;
+ for(i=0;i<vcount-rcount;i++)
+ clear_range(bp,i);
+ erange=bp;
+ bp+=RANGESIZE;
+ for(g=fg;g;g=g->normalout){
+ g->ra_normalout=bp;
+ memcpy(bp,erange,RANGESIZE);
+ bp+=RANGESIZE;
+ g->ra_branchout=bp;
+ memcpy(bp,erange,RANGESIZE);
+ bp+=RANGESIZE;
+ }
+ crange=bp;
+
+ pass=1;
+ do{
+ if(DEBUG&1024) printf("range analysis pass %d\n",pass);
+ done=1;
+ for(g=fg;g;g=g->normalout){
+ flowlist *lp;
+ IC *p;
+ int c,first=1;
+ memcpy(crange,erange,RANGESIZE);
+ for(lp=g->in;lp;lp=lp->next){
+ if(lp->graph->normalout==g&&(!lp->graph->end||lp->graph->end->code!=BRA)){
+ if(first){
+ memcpy(crange,lp->graph->ra_normalout,RANGESIZE);
+ first=0;
+ }else
+ combine_ranges(crange,lp->graph->ra_normalout);
+ }
+ if(lp->graph->branchout==g){
+ if(first) {
+ memcpy(crange,lp->graph->ra_branchout,RANGESIZE);
+ first=0;
+ }else
+ combine_ranges(crange,lp->graph->ra_branchout);
+ }
+ }
+ if(DEBUG&131072){
+ printf("block %d, input:\n",g->index);
+ print_ranges(stdout,crange);
+ }
+ for(p=g->start;p;p=p->next){
+ do_ranges(crange,p);
+ if(p==g->end||p->code==TEST||p->code==COMPARE) break;
+ }
+ if(p) c=p->code; else c=0;
+ if(c==COMPARE||c==TEST){
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&(c==TEST||(p->q2.flags&(KONST|DREFOBJ))==KONST)){
+ IC *b=p->next;
+ range tmp;
+ while(b&&b->code<BEQ||b->code>BGT) b=b->next;
+ if(!b) ierror(0);
+ if(c==TEST){
+ vmax=Z0;
+ vumax=ZU0;
+ }else
+ eval_const(&p->q2.val,p->typf);
+ i=p->q1.v->index;
+ t=p->q1.v->vtyp->flags;
+ if(b->code==BEQ){
+ if(update_ranges(g->ra_normalout,crange)) done=0;
+ if(t&UNSIGNED)
+ crange[i].min.vumax=crange[i].max.vumax=vumax;
+ else
+ crange[i].min.vmax=crange[i].max.vmax=vmax;
+ if(update_ranges(g->ra_branchout,crange)) done=0;
+ }else if(b->code==BNE){
+ if(update_ranges(g->ra_branchout,crange)) done=0;
+ if(t&UNSIGNED)
+ crange[i].min.vumax=crange[i].min.vumax=vumax;
+ else
+ crange[i].max.vumax=crange[i].max.vumax=vumax;
+ if(update_ranges(g->ra_normalout,crange)) done=0;
+ }else if(b->code==BLT||b->code==BLE){
+ tmp=crange[i];
+ if(b->code==BLT) dec_val(t);
+ insert_max(&crange[i],t);
+ if(update_ranges(g->ra_branchout,crange)) done=0;
+ crange[i]=tmp;
+ inc_val(t);
+ insert_min(&crange[i],t);
+ if(update_ranges(g->ra_normalout,crange)) done=0;
+ }else if(b->code==BGE||b->code==BGT){
+ tmp=crange[i];
+ if(b->code==BGT) inc_val(t);
+ insert_min(&crange[i],t);
+ if(update_ranges(g->ra_branchout,crange)) done=0;
+ crange[i]=tmp;
+ dec_val(t);
+ insert_max(&crange[i],t);
+ if(update_ranges(g->ra_normalout,crange)) done=0;
+ }else
+ ierror(0);
+ }else{
+ if(update_ranges(g->ra_branchout,crange)) done=0;
+ if(update_ranges(g->ra_normalout,crange)) done=0;
+ }
+ }else{
+ if(g->branchout){
+ /* must be BRA as we checked for COMPARE/TEST above */
+ if(update_ranges(g->ra_branchout,crange))
+ done=0;
+ }else{
+ if(update_ranges(g->ra_normalout,crange))
+ done=0;
+ }
+ }
+ if(DEBUG&131072){
+ printf("ra_branchout:\n");
+ print_ranges(stdout,g->ra_branchout);
+ printf("ra_normalout:\n");
+ print_ranges(stdout,g->ra_normalout);
+ }
+ }
+ pass++;
+ }while(!done);
+
+
+}
diff --git a/rd.c b/rd.c
new file mode 100644
index 0000000..79ad513
--- /dev/null
+++ b/rd.c
@@ -0,0 +1,645 @@
+/* $VER: vbcc (rd.c) $Revision: 1.16 $ */
+/* reaching definitions and constant propagation */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+unsigned int dcount;
+size_t dsize;
+IC **dlist;
+bvtype *rd_defs;
+bvtype **defs_kill; /* definitions killed */
+bvtype **defs_gen; /* definitions undefined */
+bvtype **var_defs; /* definitions of a variable */
+bvtype **var_undefs; /* definitions which are undefined by writing to this var */
+bvtype *rd_matrix;
+
+int def_overwrites(IC *new,IC *old);
+#define NO_OVERWRITE 0
+#define FULL_OVERWRITE 1
+#define PARTIAL_OVERWRITE 2
+#define EXACT_OVERWRITE 3
+
+/* compares two constants; -1, if q1<q2; 0, if q1==q1; 1 otherwise */
+int compare_const(union atyps *q1,union atyps *q2,int t)
+{
+ zldouble d1,d2;zmax l1,l2;zumax u1,u2;
+ t&=NU;
+ eval_const(q1,t);d1=vldouble;l1=vmax;u1=vumax;
+ eval_const(q2,t);d2=vldouble;l2=vmax;u2=vumax;
+ if(ISFLOAT(t)) return(zldleq(d2,d1)?!zldeqto(d1,d2):-1);
+ if(ISPOINTER(t)||(t&UNSIGNED)) return(zumleq(u2,u1)?!zumeqto(u1,u2):-1);
+ return(zmleq(l2,l1)?!zmeqto(l1,l2):-1);
+}
+
+/* prints definitions in a bitvector */
+void print_rd(bvtype *bitvector)
+{
+ unsigned int i;
+ if(!bitvector) {printf("reaching definitions not available\n");return;}
+ for(i=1;i<=dcount;i++){
+ if(BTST(bitvector,i)) {printf("%3u:",i);pric2(stdout,dlist[i]);}
+ if(BTST(bitvector,UNDEF(i))) {printf("%3u(ud):",i);pric2(stdout,dlist[i]);}
+ }
+}
+
+/* numbers all definitions and creates some bitvectors */
+void num_defs(void)
+{
+ int i,j;IC *p;
+ size_t matrix_size;
+ bvtype *bp;
+ unsigned long heapsize=0;
+ if(DEBUG&1024) printf("numerating definitions\n");
+ i=0;
+ for(p=first_ic;p;p=p->next){
+ if(!(p->z.flags&(VAR|DREFOBJ))&&p->code!=CALL){p->defindex=0;continue;}
+ p->defindex=++i;
+ }
+ dcount=i;
+ /*dsize=(2*dcount+1+CHAR_BIT)/CHAR_BIT; /* +1, da bei 1 anfaengt */
+ dsize=BVSIZE(2*(dcount+1));
+ if(DEBUG&(16384|1024)) printf("%lu definitions, dsize=%lu\n",(unsigned long)dcount,(unsigned long)dsize);
+
+ /* get big memory block to store defs_kill, defs_gen, vars, var_defs and var_undefs */
+ matrix_size=(2*(dcount+vcount)*dsize);
+ rd_matrix=bp=mymalloc(matrix_size);
+ memset(bp,0,matrix_size);
+ heapsize+=matrix_size;
+
+ /* calculate bit-vector which contains all definitions killed or */
+ /* undefined (=partially overwritten) by this definition */
+ defs_kill=mymalloc(sizeof(*defs_kill)*(dcount+1));
+ defs_gen=mymalloc(sizeof(*defs_gen)*(dcount+1));
+ heapsize+=2*sizeof(*defs_kill)*(dcount+1);
+
+ for(i=1;i<=dcount;i++){
+ defs_kill[i]=bp;
+ bp+=dsize/sizeof(bvtype);
+ defs_gen[i]=bp;
+ bp+=dsize/sizeof(bvtype);
+ }
+
+ /* calculate bit vector with all undefined definitions of each variable */
+ var_defs=mymalloc(sizeof(*var_defs)*vcount);
+ heapsize+=sizeof(*var_defs)*vcount;
+ var_undefs=mymalloc(sizeof(*var_undefs)*vcount);
+ heapsize+=sizeof(*var_undefs)*vcount;
+ for(i=0;i<vcount;i++){
+ var_defs[i]=bp;
+ bp+=dsize/sizeof(bvtype);
+ var_undefs[i]=bp;
+ bp+=dsize/sizeof(bvtype);
+ }
+
+ /* calculate pointers to IC for every definition */
+ dlist=mymalloc((dcount+1)*sizeof(*dlist));
+ heapsize+=(dcount+1)*sizeof(*dlist);
+
+ for(p=first_ic;p;p=p->next){
+ if(p->defindex){
+ dlist[p->defindex]=p;
+ if(p->z.flags&VAR){
+ Var *v=p->z.v;
+ i=v->index;
+ if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+ BSET(var_defs[i],p->defindex);
+ BSET(var_defs[i],UNDEF(p->defindex));
+ if(i<rcount){
+ BSET(var_defs[i+vcount-rcount],p->defindex);
+ BSET(var_defs[i+vcount-rcount],UNDEF(p->defindex));
+ }
+ BSET(var_undefs[i],UNDEF(p->defindex));
+ }
+ }
+ }
+
+ for(i=1;i<=dcount;i++){
+ p=dlist[i];
+ for(j=0;j<p->change_cnt;j++){
+ int idx;
+ idx=p->change_list[j].v->index;
+ if(p->change_list[j].flags&DREFOBJ) idx+=vcount-rcount;
+ if(idx>=vcount) continue;
+ BSET(var_defs[idx],i);
+ bvunite(defs_gen[i],var_undefs[idx],dsize);
+ }
+ if(p->z.flags&VAR){
+ for(j=1;j<=dcount;j++){
+ int ow;
+ IC *p2;
+ if(i==j) continue;
+ p2=dlist[j];
+ if(!(p2->z.flags&VAR)||p->z.v!=p2->z.v||p->z.flags!=p2->z.flags)
+ continue;
+ ow=def_overwrites(p,p2);
+ if(ow==FULL_OVERWRITE||ow==EXACT_OVERWRITE){
+ BSET(defs_kill[i],j);
+ BSET(defs_kill[i],UNDEF(j));
+ }
+ if(ow==EXACT_OVERWRITE||ow==NO_OVERWRITE){
+ BCLR(defs_gen[i],j);
+ BCLR(defs_gen[i],UNDEF(j));
+ }
+ }
+ }
+ /* every definition defines itself) */
+ BSET(defs_gen[i],i);
+ BCLR(defs_gen[i],UNDEF(i));
+ BSET(defs_kill[i],UNDEF(i));
+ }
+
+ if(DEBUG&2048){
+ for(i=0;i<vcount;i++){
+ printf("var_defs for var %i %s(%p):\n",i,vilist[i]->identifier,vilist[i]);
+ print_rd(var_defs[i]);
+ }
+
+ for(i=1;i<=dcount;i++){
+ printf("Def%3d: ",i);pric2(stdout,dlist[i]);
+ printf(" kills:\n");
+ for(j=1;j<=dcount;j++){
+ if(BTST(defs_kill[i],j)) {printf(" ");pric2(stdout,dlist[j]);}
+ if(BTST(defs_kill[i],UNDEF(j))) {printf(" (ud)");pric2(stdout,dlist[j]);}
+ }
+ printf(" gens:\n");
+ for(j=1;j<=dcount;j++){
+ if(BTST(defs_gen[i],j)) {printf(" ");pric2(stdout,dlist[j]);}
+ if(BTST(defs_gen[i],UNDEF(j))) {printf(" (ud)");pric2(stdout,dlist[j]);}
+ }
+ }
+ }
+
+ if(DEBUG&16384) printf("num_defs heapsize=%lu\n",heapsize);
+
+ free(var_undefs);
+}
+
+/* returns whether n overwrites the definition p */
+int def_overwrites(IC *n,IC *o)
+{
+ zmax nstart,nend,ostart,oend,nsize,osize;
+ if(!(n->z.flags&VAR)) ierror(0);
+ if(!(o->z.flags&VAR)) ierror(0);
+ if((n->z.flags&DREFOBJ)!=(o->z.flags&DREFOBJ)) ierror(0);
+ if(n->code==ASSIGN){
+ nsize=n->q2.val.vmax;
+ }else{
+ nsize=sizetab[ztyp(n)&NQ];
+ }
+ if(o->code==ASSIGN){
+ osize=o->q2.val.vmax;
+ }else{
+ osize=sizetab[ztyp(o)&NQ];
+ }
+ if(n->z.flags&DREFOBJ)
+ return zmleq(osize,nsize);
+
+ nstart=n->z.val.vmax;
+ nend=zmsub(zmadd(nstart,nsize),l2zm(1L));
+ ostart=o->z.val.vmax;
+ oend=zmsub(zmadd(ostart,osize),l2zm(1L));
+
+ if(zmeqto(nstart,ostart)&&zmeqto(nend,oend))
+ return EXACT_OVERWRITE;
+
+ if(zmleq(nstart,ostart)&&zmleq(oend,nend))
+ return FULL_OVERWRITE;
+
+ if(zmleq(ostart,nstart)&&zmleq(nstart,oend))
+ return PARTIAL_OVERWRITE;
+ if(zmleq(ostart,nend)&&zmleq(nend,oend))
+ return PARTIAL_OVERWRITE;
+
+ return NO_OVERWRITE;
+}
+
+/* performs data flow analysis for reaching definitions */
+void reaching_definitions(flowgraph *fg)
+{
+ flowgraph *g;IC *p;bvtype *tmp,*init;
+ int changed,pass,i,j;
+ unsigned long heapsize=0;
+ /* rd_gen und rd_kill fuer jeden Block berechnen */
+ if(DEBUG&1024) printf("analysing reaching definitions\n");
+ tmp=mymalloc(dsize);
+ init=mymalloc(dsize);
+ heapsize+=2*dsize;
+ memset(init,0,dsize);
+ for(i=1;i<=dcount;i++){
+ p=dlist[i];
+ if(p->z.flags&VAR){
+ Var *v=p->z.v;
+ if(v->storage_class==EXTERN||v->storage_class==STATIC||v->reg!=0||!zmleq(l2zm(0L),v->offset)){
+ BSET(init,UNDEF(i));
+ }
+ }
+ }
+ g=fg;
+ while(g){
+ g->rd_in=mymalloc(dsize);
+ memset(g->rd_in,0,dsize);
+ g->rd_out=mymalloc(dsize);
+ memset(g->rd_out,0,dsize);
+ g->rd_gen=mymalloc(dsize);
+ memset(g->rd_gen,0,dsize);
+ g->rd_kill=mymalloc(dsize);
+ memset(g->rd_kill,0,dsize);
+ heapsize+=4*dsize;
+ p=g->end;
+ while(p){
+ if(p->defindex){
+ bvunite(g->rd_gen,defs_gen[p->defindex],dsize);
+ bvdiff(g->rd_gen,g->rd_kill,dsize);
+ bvunite(g->rd_kill,defs_kill[p->defindex],dsize);
+ bvdiff(g->rd_kill,g->rd_gen,dsize);
+ }
+ if(p==g->start) break;
+ p=p->prev;
+ }
+ memcpy(g->rd_out,g->rd_gen,dsize);
+ g=g->normalout;
+ }
+
+ /* rd_in und rd_out fuer jeden Block berechnen */
+ /* out(b)=gen(B) vorinitialisiert */
+ if(DEBUG&1024) {printf("pass:");pass=0;}
+ do{
+ if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
+ changed=0;
+ g=fg;
+ while(g){
+ flowlist *lp;
+ /* in(B)=U out(C) : C Vorgaenger von B */
+ if(g==fg)
+ memcpy(g->rd_in,init,dsize);
+ else
+ memset(g->rd_in,0,dsize);
+ lp=g->in;
+ while(lp){
+ if(!lp->graph) ierror(0);
+ if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA)
+ bvunite(g->rd_in,lp->graph->rd_out,dsize);
+ lp=lp->next;
+ }
+ /* out(b)=gen(B) U (in(B)-kill(B) */
+ memcpy(tmp,g->rd_in,dsize);
+ bvdiff(tmp,g->rd_kill,dsize);
+ bvunite(tmp,g->rd_gen,dsize);
+ if(!bvcmp(tmp,g->rd_out,dsize)){changed=1;memcpy(g->rd_out,tmp,dsize);}
+ g=g->normalout;
+ }
+ }while(changed);
+ if(DEBUG&1024) printf("\n");
+ if(DEBUG&16384) printf("reaching_defs heapsize=%lu\n",heapsize);
+ free(tmp);
+ free(init);
+}
+
+/* calculates z:=q1 op q2 with constants */
+/* if p is non-zero q1typ,q2typ from p will be used */
+void calc(int c,int t,union atyps *q1,union atyps *q2,union atyps *z,IC *p)
+{
+ zldouble d1,d2;zmax l1,l2;zumax u1,u2;
+ if(p) t=q1typ(p);
+ eval_const(q1,t);
+ d1=vldouble;l1=vmax;u1=vumax;
+ if(c!=MINUS&&c!=KOMPLEMENT){
+ if(p)
+ eval_const(q2,q2typ(p));
+ else
+ eval_const(q2,t);
+ d2=vldouble;l2=vmax;u2=vumax;
+ }
+ if(c==ADD){ vldouble=zldadd(d1,d2);vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);}
+ if(c==SUB){ vldouble=zldsub(d1,d2);vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);}
+ if(c==ADDI2P){ vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);}
+ if(c==SUBIFP){ vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);}
+ if(c==MULT){ vldouble=zldmult(d1,d2);vmax=zmmult(l1,l2);vumax=zummult(u1,u2);}
+ if(c==DIV||c==MOD){
+ if(zldeqto(d2,d2zld(0.0))&&zmeqto(l2,l2zm(0L))&&zumeqto(u2,ul2zum(0UL))){
+ err_ic=p;error(210);err_ic=0;
+ vmax=l2zm(0L);vumax=ul2zum(0L);vldouble=d2zld(0.0);
+ }else{
+ if(c==DIV){
+ vldouble=zlddiv(d1,d2);
+ if(!zmeqto(l2,l2zm(0L))) vmax=zmdiv(l1,l2);
+ if(!zumeqto(u2,ul2zum(0UL))) vumax=zumdiv(u1,u2);
+ }else{
+ if(!zmeqto(l2,l2zm(0L))) vmax=zmmod(l1,l2);
+ if(!zumeqto(u2,ul2zum(0UL))) vumax=zummod(u1,u2);
+ }
+ }
+ }
+ if(c==AND){ vmax=zmand(l1,l2);vumax=zumand(u1,u2);}
+ if(c==OR){ vmax=zmor(l1,l2);vumax=zumor(u1,u2);}
+ if(c==XOR){ vmax=zmxor(l1,l2);vumax=zumxor(u1,u2);}
+ if(c==LSHIFT){ vmax=zmlshift(l1,l2);vumax=zumlshift(u1,l2);}
+ if(c==RSHIFT){ vmax=zmrshift(l1,l2);vumax=zumrshift(u1,l2);}
+ if(c==MINUS){ vldouble=zldsub(d2zld(0.0),d1);vmax=zmsub(l2zm(0L),l1);vumax=zumsub(ul2zum(0UL),u1);}
+ if(c==KOMPLEMENT){ vmax=zmkompl(l1);vumax=zumkompl(u1);}
+
+ if(ISFLOAT(t)){
+ gval.vldouble=vldouble;
+ eval_const(&gval,LDOUBLE);
+ }else if(t&UNSIGNED){
+ gval.vumax=vumax;
+ eval_const(&gval,(UNSIGNED|MAXINT));
+ }else{
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ }
+ if(p) t=ztyp(p);
+ insert_const(z,t);
+}
+
+/* folds constant ICs */
+int fold(IC *p)
+{
+ int c;
+ if(!p) ierror(0);
+ c=p->code;
+ if(c==SUBPFP||c==ASSIGN||c==PUSH||c==SETRETURN) return 0;
+ if(DEBUG&1024) {printf("folding IC:\n");pric2(stdout,p);}
+ if(c==TEST||c==COMPARE){
+ union atyps val;int cc; /* condition codes */
+ IC *bp;
+ if(c==TEST){
+ eval_const(&p->q1.val,p->typf);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+ cc=0;
+ else
+ cc=1;
+ }else{
+ if(p->q1.flags&VARADR)
+ cc=compare_const(&p->q1.val,&p->q2.val,UNSIGNED|MAXINT);
+ else
+ cc=compare_const(&p->q1.val,&p->q2.val,p->typf);
+ }
+ bp=p->next;
+ if(bp->code>=BEQ&&bp->code<=BGT&&(!p->z.flags||p->z.v==bp->q1.v)){
+ if(DEBUG&1024) printf("(cc=%d; comparison eliminated)\n",cc);
+ if(have_alias){ free(p->use_list);free(p->change_list);}
+ remove_IC(p);
+ while(1){ /* zugehoerigen Branch suchen */
+ if(!bp||bp->code==LABEL||bp->code==BRA) ierror(0);
+ c=bp->code;
+ if(c>=BEQ&&c<=BGT) break;
+ bp=bp->next;
+ }
+ if((c==BEQ&&cc==0)||(c==BNE&&cc!=0)||(c==BLT&&cc<0)||(c==BGT&&cc>0)||(c==BLE&&cc<=0)||(c==BGE&&cc>=0)){
+ if(DEBUG&1024){ printf("changed following branch to BRA:\n");pric2(stdout,bp);}
+ bp->code=BRA;bp->q1.flags=0;
+ }else{
+ if(DEBUG&1024){ printf("removed following branch:\n");pric2(stdout,bp);}
+ if(have_alias){ free(bp->use_list);free(bp->change_list);}
+ remove_IC(bp);
+ }
+ return 1;
+ }
+ if(p->z.flags==0){
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ return 1;
+ }else
+ return 0;
+ }
+ if(c==CONVERT){
+ eval_const(&p->q1.val,p->typf2);
+ insert_const(&p->q1.val,p->typf);
+ }else
+ calc(c,p->typf,&p->q1.val,&p->q2.val,&p->q1.val,p);
+ p->q2.flags=0;
+ if(p->code==ADDI2P||p->code==SUBIFP)
+ p->typf=p->typf2;
+ p->q2.val.vmax=sizetab[p->typf&NQ];
+ p->code=ASSIGN;
+ if(DEBUG&1024){printf("becomes\n");pric2(stdout,p);}
+ return 1;
+}
+
+/* tries to replace objects by constants and detects some uninitialized */
+/* variables; if cponly==0, address-constants will be replaced, */
+/* otherwise only real constants are replaced, sic points to the IC */
+/* containing the object pointed to by o */
+int propagate(IC *sic,obj *o,int cponly,int global)
+{
+ unsigned int i,j,t,found;union atyps *val=0;
+ Var *v,*vaddr=0;IC *p;
+ zmax voff;
+ if(!o||!o->v) ierror(0);
+ if(cponly){
+ if(is_volatile_obj(o))
+ return 0;
+ }else{
+ if((o->flags&VAR)&&(o->v->vtyp->flags&VOLATILE))
+ return 0;
+ }
+ if(disable&8) return 0;
+ v=o->v;
+ i=v->index;
+ /* do not replace in ICs of the form move char with size!=1,
+ because these are builtin memcpy */
+ if(cponly&&sic->code==ASSIGN&&(sic->typf&NQ)==CHAR&&!zmeqto(sic->q2.val.vmax,l2zm(1L)))
+ return 0;
+ if(cponly&&(o->flags&DREFOBJ)) i+=vcount-rcount;
+ if(DEBUG&2048){
+ printf("propagate(cponly=%d) <%s>(%p)\n",cponly,o->v->identifier,(void *)v);
+ if(o->flags&DREFOBJ) printf("(DREFOBJ)");
+ printf("\nall reaching definitions:\n");print_rd(rd_defs);
+ printf("defs for var:\n");
+ print_rd(var_defs[i]);
+ }
+ if(v->nesting==0||v->storage_class==STATIC||v->storage_class==EXTERN){
+ /* Wenn moeglich bei statischen Variablen den Wert bei der */
+ /* Initialisierung ermitteln. */
+ /*if(cponly&&ISARITH(v->vtyp->flags)&&((v->vtyp->flags&CONST)||(v->nesting>0&&!(v->flags&(USEDASADR|USEDASDEST))))){*/
+ if(cponly&&is_const(v->vtyp)){
+ /* Variable hat noch den Wert der Initialisierung. */
+ if(v->clist){
+ int t;
+ if(o==&sic->q1) t=q1typ(sic);
+ else if(o==&sic->q2) t=q2typ(sic);
+ else if(o==&sic->z) t=ztyp(sic);
+ else ierror(0);
+ if(ISARITH(v->vtyp->flags)){
+ /* Der Wert der Initialisierung ist noch gespeichert. */
+ if(DEBUG&1024) printf("using static initializer\n");
+ o->val=v->clist->val;
+ o->flags=KONST;
+ return 1;
+ }else if(ISINT(t&NQ)){
+ int state;
+ if(DEBUG&1024) printf("using static initializer (new version)\n");
+ gval.vumax=get_clist_int(v->vtyp,v->clist,o->val.vmax,sizetab[t&NQ],&state);
+ if(state){
+ if(DEBUG&1024) printf("using static initializer (new version)\n");
+ eval_const(&gval,UNSIGNED|MAXINT);
+ insert_const(&o->val,t);
+ o->flags=KONST;
+ return 1;
+ }
+ }
+ }else{
+ /* Hier evtl. eine implizite 0 erkennen. */
+ }
+ }
+ }
+ found=0;
+ for(j=1;j<=dcount;j++){
+ if((!BTST(rd_defs,UNDEF(j))||!BTST(var_defs[i],UNDEF(j)))&&
+ (!BTST(rd_defs,j)||!BTST(var_defs[i],j))) continue;
+ found=1;
+ p=dlist[j];
+ if(!(p->z.flags&VAR)) return 0;
+ if(p->z.v!=o->v) continue;
+ t=ztyp(p)&NU;
+ if(cponly&&!ISSCALAR(t)) continue;
+ if(!zmeqto(p->z.val.vmax,o->val.vmax)) continue;
+ if(cponly){
+ if(p->z.flags!=o->flags) continue;
+ }else{
+ if((p->z.flags|DREFOBJ)!=o->flags) continue;
+ if(p->z.flags&DREFOBJ) continue;
+ }
+ if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],UNDEF(j))) return 0;
+ if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],j)) return 0;
+
+ if((p->code!=ASSIGN||((p->q1.flags&(KONST|DREFOBJ))!=KONST&&(p->q1.flags&(VARADR|DREFOBJ))!=VARADR))
+ &&(p->code!=ADDRESS||!(o->flags&DREFOBJ))) return 0;
+ if(p->q1.flags&KONST){
+ if(vaddr) return 0;
+ if(val){
+ if((p->typf&NQ)!=(t&NQ)) return 0;
+ if(compare_const(&p->q1.val,val,t)) return 0;
+ }else{
+ val=&p->q1.val;t=p->typf&NU;
+ }
+ }
+ if(p->code==ADDRESS||(p->q1.flags&VARADR)){
+ if(val) return 0;
+ if(vaddr){
+ if(p->q1.v!=vaddr||!zmeqto(p->q1.val.vmax,voff)) return 0;
+ }
+ vaddr=p->q1.v;
+ voff=p->q1.val.vmax;
+ }
+ }
+
+ /* found constant */
+ if(val){
+ if(cponly){
+ if(o==&sic->q1&&(q1typ(sic)&NQ)!=(t&NQ)) return 0;
+ if(o==&sic->q2&&(q2typ(sic)&NQ)!=(t&NQ)) return 0;
+ if(o==&sic->z&&(ztyp(sic)&NQ)!=(t&NQ)) return 0;
+
+ if(DEBUG&1024) printf("can replace %ld+<%s>(%p) by constant\n",zm2l(o->val.vmax),o->v->identifier,o->v);
+ /* TODO: do we need eval_const/insert_const (if representation of unsigned is different? */
+ o->val=*val;
+ o->flags=KONST;
+ }else{
+ if(DEBUG&1024) printf("can replace <%s> by constant address\n",o->v->identifier);
+ o->val=*val;
+ o->flags|=KONST;
+ o->flags&=~VAR;
+ o->v=0;
+ }
+ return 1;
+ }
+ if(vaddr&&(vaddr->storage_class==EXTERN||vaddr->storage_class==STATIC)){
+ if(DEBUG&1024) printf("can replace <%s> by varadr\n",o->v->identifier);
+ o->v=vaddr;
+ o->val.vmax=voff;
+ if((o->flags&DREFOBJ)&&!cponly)
+ o->flags=VAR;
+ else
+ o->flags=VAR|VARADR;
+ return 2;
+ }
+ if(vaddr&&(o->flags&DREFOBJ)){
+ t=vaddr->vtyp->flags&NU;
+ if(o==&sic->q1&&(q1typ(sic)&NU)!=t) return 0;
+ if(o==&sic->q2&&(q2typ(sic)&NU)!=t) return 0;
+ if(o==&sic->z&&(ztyp(sic)&NU)!=t) return 0;
+ if(DEBUG&1024) printf("can replace *<%s> by address\n",o->v->identifier);
+ o->v=vaddr;
+ o->val.vmax=voff;
+ o->flags&=~DREFOBJ;
+ return 2;
+ }
+ /* no definition found */
+ if(!found&&global&&v->storage_class!=EXTERN&&v->storage_class!=STATIC&&!(v->flags&USEDBEFORE)&&v->reg==0&&zmleq(l2zm(0L),v->offset)){
+ if(*v->identifier||!(optflags&4096)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ error(171,v->identifier);v->flags|=USEDBEFORE;
+ if(!*v->identifier) {printf("<%p>\n",(void *)v);ierror(0);}
+ }
+ }
+ return 0;
+}
+
+/* searches for constant objects and uninitialized variables; if */
+/* global!=0, reaching definitions are used, otherwise only local */
+/* constant propagation will be done */
+int constant_propagation(flowgraph *fg,int global)
+{
+ IC *p;int changed=0,i,t;flowgraph *g;
+ rd_defs=mymalloc(dsize);
+ g=fg;
+ while(g){
+ if(global)
+ memcpy(rd_defs,g->rd_in,dsize);
+ else
+ memset(rd_defs,0,dsize);
+ p=g->start;
+ while(p){
+ int c=p->code;
+ /* if(DEBUG&1024){print_rd(rd_defs);pric2(stdout,p);}*/
+ if(c!=ADDRESS&&c!=NOP&&ISSCALAR(p->typf)&&(c<LABEL||c>BRA)){
+ if((p->q1.flags&(VAR|VARADR))==VAR){
+ if(!(q1typ(p)&VOLATILE)&&!is_volatile_obj(&p->q1))
+ changed|=propagate(p,&p->q1,1,global);
+ if((p->q1.flags&DREFOBJ)&&!(p->q1.v->vtyp->flags&VOLATILE))
+ changed|=propagate(p,&p->q1,0,global);
+ }
+ if((p->q2.flags&(VAR|VARADR))==VAR){
+ if(!(q2typ(p)&VOLATILE)&&!is_volatile_obj(&p->q2))
+ changed|=propagate(p,&p->q2,1,global);
+ if((p->q2.flags&DREFOBJ)&&!(p->q2.v->vtyp->flags&VOLATILE))
+ changed|=propagate(p,&p->q2,0,global);
+ }
+ }
+ /* only there to detect uninitialized variables */
+ if(((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ))){
+ if(!(p->z.v->vtyp->flags&VOLATILE))
+ changed|=propagate(p,&p->z,0,global);
+ }
+ rd_change(p);
+
+ if(p==g->end) break;
+ p=p->next;
+ }
+ break;
+ g=g->normalout;
+ }
+
+ gchanged|=changed;
+
+ free(rd_defs);
+ return changed;
+}
+
+/* performs changes to rd_defs which are caused by IC p */
+void rd_change(IC *p)
+{
+ if(DEBUG&4096) print_rd(rd_defs);
+ if(p->defindex){
+ bvdiff(rd_defs,defs_kill[p->defindex],dsize);
+ bvunite(rd_defs,defs_gen[p->defindex],dsize);
+ }
+ if(DEBUG&4096) pric2(stdout,p);
+}
+
diff --git a/rd_tst.c b/rd_tst.c
new file mode 100644
index 0000000..d64de4f
--- /dev/null
+++ b/rd_tst.c
@@ -0,0 +1,647 @@
+/* $VER: vbcc (rd.c) $Revision: 1.16 $ */
+/* reaching definitions and constant propagation */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+unsigned int dcount;
+size_t dsize;
+IC **dlist;
+bvtype *rd_defs;
+bvtype **defs_kill; /* definitions killed */
+bvtype **defs_gen; /* definitions undefined */
+bvtype **var_defs; /* definitions of a variable */
+bvtype **var_undefs; /* definitions which are undefined by writing to this var */
+bvtype *rd_matrix;
+
+int def_overwrites(IC *new,IC *old);
+#define NO_OVERWRITE 0
+#define FULL_OVERWRITE 1
+#define PARTIAL_OVERWRITE 2
+#define EXACT_OVERWRITE 3
+
+/* compares two constants; -1, if q1<q2; 0, if q1==q1; 1 otherwise */
+int compare_const(union atyps *q1,union atyps *q2,int t)
+{
+ zldouble d1,d2;zmax l1,l2;zumax u1,u2;
+ t&=NU;
+ eval_const(q1,t);d1=vldouble;l1=vmax;u1=vumax;
+ eval_const(q2,t);d2=vldouble;l2=vmax;u2=vumax;
+ if(ISFLOAT(t)) return(zldleq(d2,d1)?!zldeqto(d1,d2):-1);
+ if(ISPOINTER(t)||(t&UNSIGNED)) return(zumleq(u2,u1)?!zumeqto(u1,u2):-1);
+ return(zmleq(l2,l1)?!zmeqto(l1,l2):-1);
+}
+
+/* prints definitions in a bitvector */
+void print_rd(bvtype *bitvector)
+{
+ unsigned int i;
+ if(!bitvector) {printf("reaching definitions not available\n");return;}
+ for(i=1;i<=dcount;i++){
+ if(BTST(bitvector,i)) {printf("%3u:",i);pric2(stdout,dlist[i]);}
+ if(BTST(bitvector,UNDEF(i))) {printf("%3u(ud):",i);pric2(stdout,dlist[i]);}
+ }
+}
+
+/* numbers all definitions and creates some bitvectors */
+void num_defs(void)
+{
+ int i,j;IC *p;
+ size_t matrix_size;
+ bvtype *bp;
+ unsigned long heapsize=0;
+ if(DEBUG&1024) printf("numerating definitions\n");
+ i=0;
+ for(p=first_ic;p;p=p->next){
+ if(!(p->z.flags&(VAR|DREFOBJ))&&p->code!=CALL){p->defindex=0;continue;}
+ p->defindex=++i;
+ }
+ dcount=i;
+ /*dsize=(2*dcount+1+CHAR_BIT)/CHAR_BIT; /* +1, da bei 1 anfaengt */
+ dsize=BVSIZE(2*(dcount+1));
+ if(DEBUG&(16384|1024)) printf("%lu definitions, dsize=%lu\n",(unsigned long)dcount,(unsigned long)dsize);
+
+ /* get big memory block to store defs_kill, defs_gen, vars, var_defs and var_undefs */
+ matrix_size=(2*(dcount+vcount)*dsize);
+ rd_matrix=bp=mymalloc(matrix_size);
+ memset(bp,0,matrix_size);
+ heapsize+=matrix_size;
+
+ /* calculate bit-vector which contains all definitions killed or */
+ /* undefined (=partially overwritten) by this definition */
+ defs_kill=mymalloc(sizeof(*defs_kill)*(dcount+1));
+ defs_gen=mymalloc(sizeof(*defs_gen)*(dcount+1));
+ heapsize+=2*sizeof(*defs_kill)*(dcount+1);
+
+ for(i=1;i<=dcount;i++){
+ defs_kill[i]=bp;
+ bp+=dsize/sizeof(bvtype);
+ defs_gen[i]=bp;
+ bp+=dsize/sizeof(bvtype);
+ }
+
+ /* calculate bit vector with all undefined definitions of each variable */
+ var_defs=mymalloc(sizeof(*var_defs)*vcount);
+ heapsize+=sizeof(*var_defs)*vcount;
+ var_undefs=mymalloc(sizeof(*var_undefs)*vcount);
+ heapsize+=sizeof(*var_undefs)*vcount;
+ for(i=0;i<vcount;i++){
+ var_defs[i]=bp;
+ bp+=dsize/sizeof(bvtype);
+ var_undefs[i]=bp;
+ bp+=dsize/sizeof(bvtype);
+ }
+
+ /* calculate pointers to IC for every definition */
+ dlist=mymalloc((dcount+1)*sizeof(*dlist));
+ heapsize+=(dcount+1)*sizeof(*dlist);
+
+ for(p=first_ic;p;p=p->next){
+ if(p->defindex){
+ dlist[p->defindex]=p;
+ if(p->z.flags&VAR){
+ Var *v=p->z.v;
+ i=v->index;
+ if(p->z.flags&DREFOBJ) i+=vcount-rcount;
+ BSET(var_defs[i],p->defindex);
+ BSET(var_defs[i],UNDEF(p->defindex));
+ if(i<rcount){
+ BSET(var_defs[i+vcount-rcount],p->defindex);
+ BSET(var_defs[i+vcount-rcount],UNDEF(p->defindex));
+ }
+ BSET(var_undefs[i],UNDEF(p->defindex));
+ }
+ }
+ }
+
+ for(i=1;i<=dcount;i++){
+ p=dlist[i];
+ for(j=0;j<p->change_cnt;j++){
+ int idx;
+ idx=p->change_list[j].v->index;
+ if(p->change_list[j].flags&DREFOBJ) idx+=vcount-rcount;
+ if(idx>=vcount) continue;
+ BSET(var_defs[idx],i);
+ bvunite(defs_gen[i],var_undefs[idx],dsize);
+ }
+ if(p->z.flags&VAR){
+ for(j=1;j<=dcount;j++){
+ int ow;
+ IC *p2;
+ if(i==j) continue;
+ p2=dlist[j];
+ if(!(p2->z.flags&VAR)||p->z.v!=p2->z.v||p->z.flags!=p2->z.flags)
+ continue;
+ ow=def_overwrites(p,p2);
+ if(ow==FULL_OVERWRITE||ow==EXACT_OVERWRITE){
+ BSET(defs_kill[i],j);
+ BSET(defs_kill[i],UNDEF(j));
+ }
+ if(ow==EXACT_OVERWRITE||ow==NO_OVERWRITE){
+ BCLR(defs_gen[i],j);
+ BCLR(defs_gen[i],UNDEF(j));
+ }
+ }
+ }
+ /* every definition defines itself) */
+ BSET(defs_gen[i],i);
+ BCLR(defs_gen[i],UNDEF(i));
+ BSET(defs_kill[i],UNDEF(i));
+ }
+
+ if(DEBUG&2048){
+ for(i=0;i<vcount;i++){
+ printf("var_defs for var %i %s(%p):\n",i,vilist[i]->identifier,vilist[i]);
+ print_rd(var_defs[i]);
+ }
+
+ for(i=1;i<=dcount;i++){
+ printf("Def%3d: ",i);pric2(stdout,dlist[i]);
+ printf(" kills:\n");
+ for(j=1;j<=dcount;j++){
+ if(BTST(defs_kill[i],j)) {printf(" ");pric2(stdout,dlist[j]);}
+ if(BTST(defs_kill[i],UNDEF(j))) {printf(" (ud)");pric2(stdout,dlist[j]);}
+ }
+ printf(" gens:\n");
+ for(j=1;j<=dcount;j++){
+ if(BTST(defs_gen[i],j)) {printf(" ");pric2(stdout,dlist[j]);}
+ if(BTST(defs_gen[i],UNDEF(j))) {printf(" (ud)");pric2(stdout,dlist[j]);}
+ }
+ }
+ }
+
+ if(DEBUG&16384) printf("num_defs heapsize=%lu\n",heapsize);
+
+ free(var_undefs);
+}
+
+/* returns whether n overwrites the definition p */
+int def_overwrites(IC *n,IC *o)
+{
+ zmax nstart,nend,ostart,oend,nsize,osize;
+ if(!(n->z.flags&VAR)) ierror(0);
+ if(!(o->z.flags&VAR)) ierror(0);
+ if((n->z.flags&DREFOBJ)!=(o->z.flags&DREFOBJ)) ierror(0);
+ if(n->code==ASSIGN){
+ nsize=n->q2.val.vmax;
+ }else{
+ nsize=sizetab[ztyp(n)&NQ];
+ }
+ if(o->code==ASSIGN){
+ osize=o->q2.val.vmax;
+ }else{
+ osize=sizetab[ztyp(o)&NQ];
+ }
+ if(n->z.flags&DREFOBJ)
+ return zmleq(osize,nsize);
+
+ nstart=n->z.val.vmax;
+ nend=zmsub(zmadd(nstart,nsize),l2zm(1L));
+ ostart=o->z.val.vmax;
+ oend=zmsub(zmadd(ostart,osize),l2zm(1L));
+
+ if(zmeqto(nstart,ostart)&&zmeqto(nend,oend))
+ return EXACT_OVERWRITE;
+
+ if(zmleq(nstart,ostart)&&zmleq(oend,nend))
+ return FULL_OVERWRITE;
+
+ if(zmleq(ostart,nstart)&&zmleq(nstart,oend))
+ return PARTIAL_OVERWRITE;
+ if(zmleq(ostart,nend)&&zmleq(nend,oend))
+ return PARTIAL_OVERWRITE;
+
+ return NO_OVERWRITE;
+}
+
+/* performs data flow analysis for reaching definitions */
+void reaching_definitions(flowgraph *fg)
+{
+ flowgraph *g;IC *p;bvtype *tmp,*init;
+ int changed,pass,i,j;
+ unsigned long heapsize=0;
+ /* rd_gen und rd_kill fuer jeden Block berechnen */
+ if(DEBUG&1024) printf("analysing reaching definitions\n");
+ tmp=mymalloc(dsize);
+ init=mymalloc(dsize);
+ heapsize+=2*dsize;
+ memset(init,0,dsize);
+ for(i=1;i<=dcount;i++){
+ p=dlist[i];
+ if(p->z.flags&VAR){
+ Var *v=p->z.v;
+ if(v->storage_class==EXTERN||v->storage_class==STATIC||v->reg!=0||!zmleq(l2zm(0L),v->offset)){
+ BSET(init,UNDEF(i));
+ }
+ }
+ }
+ g=fg;
+ while(g){
+ g->rd_in=mymalloc(dsize);
+ memset(g->rd_in,0,dsize);
+ g->rd_out=mymalloc(dsize);
+ memset(g->rd_out,0,dsize);
+ g->rd_gen=mymalloc(dsize);
+ memset(g->rd_gen,0,dsize);
+ g->rd_kill=mymalloc(dsize);
+ memset(g->rd_kill,0,dsize);
+ heapsize+=4*dsize;
+ p=g->end;
+ while(p){
+ if(p->defindex){
+ bvunite(g->rd_gen,defs_gen[p->defindex],dsize);
+ bvdiff(g->rd_gen,g->rd_kill,dsize);
+ bvunite(g->rd_kill,defs_kill[p->defindex],dsize);
+ bvdiff(g->rd_kill,g->rd_gen,dsize);
+ }
+ if(p==g->start) break;
+ p=p->prev;
+ }
+ memcpy(g->rd_out,g->rd_gen,dsize);
+ g=g->normalout;
+ }
+
+ /* rd_in und rd_out fuer jeden Block berechnen */
+ /* out(b)=gen(B) vorinitialisiert */
+ if(DEBUG&1024) {printf("pass:");pass=0;}
+ do{
+ if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
+ changed=0;
+ g=fg;
+ while(g){
+ flowlist *lp;
+ /* in(B)=U out(C) : C Vorgaenger von B */
+ if(g==fg)
+ memcpy(g->rd_in,init,dsize);
+ else
+ memset(g->rd_in,0,dsize);
+ lp=g->in;
+ while(lp){
+ if(!lp->graph) ierror(0);
+ if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA)
+ bvunite(g->rd_in,lp->graph->rd_out,dsize);
+ lp=lp->next;
+ }
+ /* out(b)=gen(B) U (in(B)-kill(B) */
+ memcpy(tmp,g->rd_in,dsize);
+ bvdiff(tmp,g->rd_kill,dsize);
+ bvunite(tmp,g->rd_gen,dsize);
+ if(!bvcmp(tmp,g->rd_out,dsize)){changed=1;memcpy(g->rd_out,tmp,dsize);}
+ g=g->normalout;
+ }
+ }while(changed);
+ if(DEBUG&1024) printf("\n");
+ if(DEBUG&16384) printf("reaching_defs heapsize=%lu\n",heapsize);
+ free(tmp);
+ free(init);
+}
+
+/* calculates z:=q1 op q2 with constants */
+/* if p is non-zero q1typ,q2typ from p will be used */
+void calc(int c,int t,union atyps *q1,union atyps *q2,union atyps *z,IC *p)
+{
+ zldouble d1,d2;zmax l1,l2;zumax u1,u2;
+ if(p) t=q1typ(p);
+ eval_const(q1,t);
+ d1=vldouble;l1=vmax;u1=vumax;
+ if(c!=MINUS&&c!=KOMPLEMENT){
+ if(p)
+ eval_const(q2,q2typ(p));
+ else
+ eval_const(q2,t);
+ d2=vldouble;l2=vmax;u2=vumax;
+ }
+ if(c==ADD){ vldouble=zldadd(d1,d2);vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);}
+ if(c==SUB){ vldouble=zldsub(d1,d2);vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);}
+ if(c==ADDI2P){ vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);}
+ if(c==SUBIFP){ vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);}
+ if(c==MULT){ vldouble=zldmult(d1,d2);vmax=zmmult(l1,l2);vumax=zummult(u1,u2);}
+ if(c==DIV||c==MOD){
+ if(zldeqto(d2,d2zld(0.0))&&zmeqto(l2,l2zm(0L))&&zumeqto(u2,ul2zum(0UL))){
+ err_ic=p;error(210);err_ic=0;
+ vmax=l2zm(0L);vumax=ul2zum(0L);vldouble=d2zld(0.0);
+ }else{
+ if(c==DIV){
+ vldouble=zlddiv(d1,d2);
+ if(!zmeqto(l2,l2zm(0L))) vmax=zmdiv(l1,l2);
+ if(!zumeqto(u2,ul2zum(0UL))) vumax=zumdiv(u1,u2);
+ }else{
+ if(!zmeqto(l2,l2zm(0L))) vmax=zmmod(l1,l2);
+ if(!zumeqto(u2,ul2zum(0UL))) vumax=zummod(u1,u2);
+ }
+ }
+ }
+ if(c==AND){ vmax=zmand(l1,l2);vumax=zumand(u1,u2);}
+ if(c==OR){ vmax=zmor(l1,l2);vumax=zumor(u1,u2);}
+ if(c==XOR){ vmax=zmxor(l1,l2);vumax=zumxor(u1,u2);}
+ if(c==LSHIFT){ vmax=zmlshift(l1,l2);vumax=zumlshift(u1,l2);}
+ if(c==RSHIFT){ vmax=zmrshift(l1,l2);vumax=zumrshift(u1,l2);}
+ if(c==MINUS){ vldouble=zldsub(d2zld(0.0),d1);vmax=zmsub(l2zm(0L),l1);vumax=zumsub(ul2zum(0UL),u1);}
+ if(c==KOMPLEMENT){ vmax=zmkompl(l1);vumax=zumkompl(u1);}
+
+ if(ISFLOAT(t)){
+ gval.vldouble=vldouble;
+ eval_const(&gval,LDOUBLE);
+ }else if(t&UNSIGNED){
+ gval.vumax=vumax;
+ eval_const(&gval,(UNSIGNED|MAXINT));
+ }else{
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ }
+ if(p) t=ztyp(p);
+ insert_const(z,t);
+}
+
+/* folds constant ICs */
+int fold(IC *p)
+{
+ int c;
+ if(!p) ierror(0);
+ c=p->code;
+ if(c==SUBPFP||c==ASSIGN||c==PUSH||c==SETRETURN) return 0;
+ if(DEBUG&1024) {printf("folding IC:\n");pric2(stdout,p);}
+ if(c==TEST||c==COMPARE){
+ union atyps val;int cc; /* condition codes */
+ IC *bp;
+ if(c==TEST){
+ eval_const(&p->q1.val,p->typf);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+ cc=0;
+ else
+ cc=1;
+ }else{
+ if(p->q1.flags&VARADR)
+ cc=compare_const(&p->q1.val,&p->q2.val,UNSIGNED|MAXINT);
+ else
+ cc=compare_const(&p->q1.val,&p->q2.val,p->typf);
+ }
+ bp=p->next;
+ if(bp->code>=BEQ&&bp->code<=BGT&&(!p->z.flags||p->z.v==bp->q1.v)){
+ if(DEBUG&1024) printf("(cc=%d; comparison eliminated)\n",cc);
+ if(have_alias){ free(p->use_list);free(p->change_list);}
+ remove_IC(p);
+ while(1){ /* zugehoerigen Branch suchen */
+ if(!bp||bp->code==LABEL||bp->code==BRA) ierror(0);
+ c=bp->code;
+ if(c>=BEQ&&c<=BGT) break;
+ bp=bp->next;
+ }
+ if((c==BEQ&&cc==0)||(c==BNE&&cc!=0)||(c==BLT&&cc<0)||(c==BGT&&cc>0)||(c==BLE&&cc<=0)||(c==BGE&&cc>=0)){
+ if(DEBUG&1024){ printf("changed following branch to BRA:\n");pric2(stdout,bp);}
+ bp->code=BRA;bp->q1.flags=0;
+ }else{
+ if(DEBUG&1024){ printf("removed following branch:\n");pric2(stdout,bp);}
+ if(have_alias){ free(bp->use_list);free(bp->change_list);}
+ remove_IC(bp);
+ }
+ return 1;
+ }
+ if(p->z.flags==0){
+ p->code=NOP;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ return 1;
+ }else
+ return 0;
+ }
+ if(c==CONVERT){
+ eval_const(&p->q1.val,p->typf2);
+ insert_const(&p->q1.val,p->typf);
+ }else
+ calc(c,p->typf,&p->q1.val,&p->q2.val,&p->q1.val,p);
+ p->q2.flags=0;
+ if(p->code==ADDI2P||p->code==SUBIFP)
+ p->typf=p->typf2;
+ p->q2.val.vmax=sizetab[p->typf&NQ];
+ p->code=ASSIGN;
+ if(DEBUG&1024){printf("becomes\n");pric2(stdout,p);}
+ return 1;
+}
+
+/* tries to replace objects by constants and detects some uninitialized */
+/* variables; if cponly==0, address-constants will be replaced, */
+/* otherwise only real constants are replaced, sic points to the IC */
+/* containing the object pointed to by o */
+int propagate(IC *sic,obj *o,int cponly,int global)
+{
+ unsigned int i,j,t,found;union atyps *val=0;
+ Var *v,*vaddr=0;IC *p;
+ zmax voff;
+ if(!o||!o->v) ierror(0);
+ if(cponly){
+ if(is_volatile_obj(o))
+ return 0;
+ }else{
+ if((o->flags&VAR)&&(o->v->vtyp->flags&VOLATILE))
+ return 0;
+ }
+ if(disable&8) return 0;
+ v=o->v;
+ i=v->index;
+ /* do not replace in ICs of the form move char with size!=1,
+ because these are builtin memcpy */
+ if(cponly&&sic->code==ASSIGN&&(sic->typf&NQ)==CHAR&&!zmeqto(sic->q2.val.vmax,l2zm(1L)))
+ return 0;
+ if(cponly&&(o->flags&DREFOBJ)) i+=vcount-rcount;
+ if(DEBUG&2048){
+ printf("propagate(cponly=%d) <%s>(%p)\n",cponly,o->v->identifier,(void *)v);
+ if(o->flags&DREFOBJ) printf("(DREFOBJ)");
+ printf("\nall reaching definitions:\n");print_rd(rd_defs);
+ printf("defs for var:\n");
+ print_rd(var_defs[i]);
+ }
+ if(v->nesting==0||v->storage_class==STATIC||v->storage_class==EXTERN){
+ /* Wenn moeglich bei statischen Variablen den Wert bei der */
+ /* Initialisierung ermitteln. */
+ /*if(cponly&&ISARITH(v->vtyp->flags)&&((v->vtyp->flags&CONST)||(v->nesting>0&&!(v->flags&(USEDASADR|USEDASDEST))))){*/
+ printf("var1(%s) %d\n",v->identifier,cponly);
+ if(cponly&&is_const(v->vtyp)){
+ /* Variable hat noch den Wert der Initialisierung. */
+ if(v->clist){
+ int t;
+ if(o==&sic->q1) t=q1typ(sic);
+ else if(o==&sic->q2) t=q2typ(sic);
+ else if(o==&sic->z) t=ztyp(sic);
+ else ierror(0);
+ printf("var2(%s)\n",v->identifier);
+ if(ISARITH(v->vtyp->flags)||ISPOINTER(v->vtyp->flags)){
+ /* Der Wert der Initialisierung ist noch gespeichert. */
+ if(DEBUG&1024) printf("using static initializer\n");
+ o->val=v->clist->val;
+ o->flags=KONST;
+ return 1;
+ }else if(ISINT(t&NQ)){
+ int state;
+ if(DEBUG&1024) printf("using static initializer (new version)\n");
+ gval.vumax=get_clist_int(v->vtyp,v->clist,o->val.vmax,sizetab[t&NQ],&state);
+ if(state){
+ if(DEBUG&1024) printf("using static initializer (new version)\n");
+ eval_const(&gval,UNSIGNED|MAXINT);
+ insert_const(&o->val,t);
+ o->flags=KONST;
+ return 1;
+ }
+ }
+ }else{
+ /* Hier evtl. eine implizite 0 erkennen. */
+ }
+ }
+ }
+ found=0;
+ for(j=1;j<=dcount;j++){
+ if((!BTST(rd_defs,UNDEF(j))||!BTST(var_defs[i],UNDEF(j)))&&
+ (!BTST(rd_defs,j)||!BTST(var_defs[i],j))) continue;
+ found=1;
+ p=dlist[j];
+ if(!(p->z.flags&VAR)) return 0;
+ if(p->z.v!=o->v) continue;
+ t=ztyp(p)&NU;
+ if(cponly&&!ISSCALAR(t)) continue;
+ if(!zmeqto(p->z.val.vmax,o->val.vmax)) continue;
+ if(cponly){
+ if(p->z.flags!=o->flags) continue;
+ }else{
+ if((p->z.flags|DREFOBJ)!=o->flags) continue;
+ if(p->z.flags&DREFOBJ) continue;
+ }
+ if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],UNDEF(j))) return 0;
+ if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],j)) return 0;
+
+ if((p->code!=ASSIGN||((p->q1.flags&(KONST|DREFOBJ))!=KONST&&(p->q1.flags&(VARADR|DREFOBJ))!=VARADR))
+ &&(p->code!=ADDRESS||!(o->flags&DREFOBJ))) return 0;
+ if(p->q1.flags&KONST){
+ if(vaddr) return 0;
+ if(val){
+ if((p->typf&NQ)!=(t&NQ)) return 0;
+ if(compare_const(&p->q1.val,val,t)) return 0;
+ }else{
+ val=&p->q1.val;t=p->typf&NU;
+ }
+ }
+ if(p->code==ADDRESS||(p->q1.flags&VARADR)){
+ if(val) return 0;
+ if(vaddr){
+ if(p->q1.v!=vaddr||!zmeqto(p->q1.val.vmax,voff)) return 0;
+ }
+ vaddr=p->q1.v;
+ voff=p->q1.val.vmax;
+ }
+ }
+
+ /* found constant */
+ if(val){
+ if(cponly){
+ if(o==&sic->q1&&(q1typ(sic)&NQ)!=(t&NQ)) return 0;
+ if(o==&sic->q2&&(q2typ(sic)&NQ)!=(t&NQ)) return 0;
+ if(o==&sic->z&&(ztyp(sic)&NQ)!=(t&NQ)) return 0;
+
+ if(DEBUG&1024) printf("can replace %ld+<%s>(%p) by constant\n",zm2l(o->val.vmax),o->v->identifier,o->v);
+ /* TODO: do we need eval_const/insert_const (if representation of unsigned is different? */
+ o->val=*val;
+ o->flags=KONST;
+ }else{
+ if(DEBUG&1024) printf("can replace <%s> by constant address\n",o->v->identifier);
+ o->val=*val;
+ o->flags|=KONST;
+ o->flags&=~VAR;
+ o->v=0;
+ }
+ return 1;
+ }
+ if(vaddr&&(vaddr->storage_class==EXTERN||vaddr->storage_class==STATIC)){
+ if(DEBUG&1024) printf("can replace <%s> by varadr\n",o->v->identifier);
+ o->v=vaddr;
+ o->val.vmax=voff;
+ if((o->flags&DREFOBJ)&&!cponly)
+ o->flags=VAR;
+ else
+ o->flags=VAR|VARADR;
+ return 2;
+ }
+ if(vaddr&&(o->flags&DREFOBJ)){
+ t=vaddr->vtyp->flags&NU;
+ if(o==&sic->q1&&(q1typ(sic)&NU)!=t) return 0;
+ if(o==&sic->q2&&(q2typ(sic)&NU)!=t) return 0;
+ if(o==&sic->z&&(ztyp(sic)&NU)!=t) return 0;
+ if(DEBUG&1024) printf("can replace *<%s> by address\n",o->v->identifier);
+ o->v=vaddr;
+ o->val.vmax=voff;
+ o->flags&=~DREFOBJ;
+ return 2;
+ }
+ /* no definition found */
+ if(!found&&global&&v->storage_class!=EXTERN&&v->storage_class!=STATIC&&!(v->flags&USEDBEFORE)&&v->reg==0&&zmleq(l2zm(0L),v->offset)){
+ if(*v->identifier||!(optflags&4096)){
+#ifdef HAVE_MISRA
+ misra_neu(30,9,1,0,v->identifier);
+#endif
+ error(171,v->identifier);v->flags|=USEDBEFORE;
+ if(!*v->identifier) {printf("<%p>\n",(void *)v);ierror(0);}
+ }
+ }
+ return 0;
+}
+
+/* searches for constant objects and uninitialized variables; if */
+/* global!=0, reaching definitions are used, otherwise only local */
+/* constant propagation will be done */
+int constant_propagation(flowgraph *fg,int global)
+{
+ IC *p;int changed=0,i,t;flowgraph *g;
+ rd_defs=mymalloc(dsize);
+ g=fg;
+ while(g){
+ if(global)
+ memcpy(rd_defs,g->rd_in,dsize);
+ else
+ memset(rd_defs,0,dsize);
+ p=g->start;
+ while(p){
+ int c=p->code;
+ /* if(DEBUG&1024){print_rd(rd_defs);pric2(stdout,p);}*/
+ if(c!=ADDRESS&&c!=NOP&&ISSCALAR(p->typf)&&(c<LABEL||c>BRA)){
+ if((p->q1.flags&(VAR|VARADR))==VAR){
+ if(!(q1typ(p)&VOLATILE)&&!is_volatile_obj(&p->q1))
+ changed|=propagate(p,&p->q1,1,global);
+ if((p->q1.flags&DREFOBJ)&&!(p->q1.v->vtyp->flags&VOLATILE))
+ changed|=propagate(p,&p->q1,0,global);
+ }
+ if((p->q2.flags&(VAR|VARADR))==VAR){
+ if(!(q2typ(p)&VOLATILE)&&!is_volatile_obj(&p->q2))
+ changed|=propagate(p,&p->q2,1,global);
+ if((p->q2.flags&DREFOBJ)&&!(p->q2.v->vtyp->flags&VOLATILE))
+ changed|=propagate(p,&p->q2,0,global);
+ }
+ }
+ /* only there to detect uninitialized variables */
+ if(((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ))){
+ if(!(p->z.v->vtyp->flags&VOLATILE))
+ changed|=propagate(p,&p->z,0,global);
+ }
+ rd_change(p);
+
+ if(p==g->end) break;
+ p=p->next;
+ }
+ break;
+ g=g->normalout;
+ }
+
+ gchanged|=changed;
+
+ free(rd_defs);
+ return changed;
+}
+
+/* performs changes to rd_defs which are caused by IC p */
+void rd_change(IC *p)
+{
+ if(DEBUG&4096) print_rd(rd_defs);
+ if(p->defindex){
+ bvdiff(rd_defs,defs_kill[p->defindex],dsize);
+ bvunite(rd_defs,defs_gen[p->defindex],dsize);
+ }
+ if(DEBUG&4096) pric2(stdout,p);
+}
+
diff --git a/regs.c b/regs.c
new file mode 100644
index 0000000..e1eddcd
--- /dev/null
+++ b/regs.c
@@ -0,0 +1,2102 @@
+/* $VER: vbcc (regs.c) $Revision: 1.31 $ */
+/* Registerzuteilung */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+typedef struct regp {int treg;Var *tvar,*tmp;} regp;
+int sregsa[MAXR+1];
+
+void do_load_parms(regp [],flowgraph *);
+void load_one_parm(int,int,Var *,Var *,flowgraph *);
+
+#ifndef NO_OPTIMIZER
+
+int (*savings)[MAXR+1],regu[MAXR+1];
+int *rvlist;
+
+static int const_vars;
+
+static bvtype bregs[BVSIZE(MAXR+1)/sizeof(bvtype)];
+static bvtype bregsm[BVSIZE(MAXR+1)/sizeof(bvtype)];
+
+Var *lparms[MAXR+1];
+
+static void insert_cobj(obj *o,obj *co);
+
+#ifndef HAVE_TARGET_RALLOC
+int reg_prio[MAXR+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) 4
+
+int cost_savings(IC *p,int r,obj *o)
+{
+ int c=p->code;
+ if(o->flags&VKONST) return 0;
+ if(o->flags&DREFOBJ){
+ int t;
+ if(o==&p->q1){
+ t=q1typ(p);
+ }else if(o==&p->q2){
+ t=q2typ(p);
+ }else{
+ t=ztyp(p);
+ }
+ if(regok(r,o->v->vtyp->flags,t)) 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;
+}
+#endif
+
+int cmp_savings(const void *v1,const void *v2)
+/* Vergleichsfkt, um rvlist nach savings zu sortieren */
+{
+ return savings[*(int *)v2][0]-savings[*(int *)v1][0];
+}
+int entry_load(flowgraph *fg,int i)
+/* Testet, ob die Variable in Register i am Anfang von Block fg geladen */
+/* werden muss, d.h. ein Vorgaenger sie nicht im selben Register hat. */
+{
+ flowlist *lp;
+ Var *v=fg->regv[i];
+ int vi=v->index;
+ lp=fg->in;
+
+ while(lp){
+ if(lp->graph&&lp->graph->regv[i]!=v&&(vi>=vcount-rcount||BTST(lp->graph->av_out,vi))) return 1;
+ lp=lp->next;
+ }
+ return 0;
+}
+
+/* checks if variable i can be held in a register in loop start-end */
+/* currently we check whether an IC uses/modifies the variable and */
+/* has a corresponding drefobj which might alias the variable */
+int check_cacheable(int i,flowgraph *start,flowgraph *end)
+{
+ int j,k;
+ IC *p;Var *v;
+ flowgraph *g;
+ /* constants are always cacheable */
+ if(vilist[i]->identifier[0]==' ')
+ return 1;
+ if(i<vcount-rcount){
+ /* simple local variables are also easy */
+ v=vilist[i];
+ if(v->storage_class!=STATIC&&v->storage_class!=EXTERN&&!(v->flags&USEDASADR))
+ return 1;
+ }
+ if(disable&16384) return 0;
+ for(g=start;g;g=g->normalout){
+ for(p=g->start;p;p=p->next){
+ for(j=0;j<p->use_cnt;j++){
+ k=p->use_list[j].v->index;
+ if(p->use_list[j].flags&DREFOBJ)
+ k+=vcount-rcount;
+ if(k==i&&(p->code==CALL||(p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)))
+ return 0;
+ }
+ for(j=0;j<p->change_cnt;j++){
+ k=p->change_list[j].v->index;
+ if(p->change_list[j].flags&DREFOBJ)
+ k+=vcount-rcount;
+ if(k==i&&(p->code==CALL||(p->z.flags&DREFOBJ)))
+ return 0;
+ }
+ if(p==g->end) break;
+ }
+ if(g==end) break;
+ }
+ /*printf("assigned static %s to reg\n",vilist[i]->identifier);*/
+ return 1;
+}
+int exit_save(flowgraph *fg,int i)
+/* Testet, ob die Variable in Register i am Ende von Block fg gespeichert */
+/* werden muss, d.h. der Vorgaenger eines Nachfolgers nicht dieselbe */
+/* Variable im selben Register hat. */
+{
+ flowlist *lp;
+ /* Konstanten muessen nie gespeichert werden */
+ if(fg->regv[i]->index>=vcount-rcount) return 0;
+ if(!fg->normalout){
+ /* letzter Block, statische Variablen und drefobjs aktiv */
+ int sc=fg->regv[i]->storage_class;
+ return sc==STATIC||sc==EXTERN;
+ }
+ if((fg->normalout&&(!fg->end||fg->end->code!=BRA))&&BTST(fg->normalout->av_in,fg->regv[i]->index)){
+ if(fg->normalout->regv[i]!=fg->regv[i]) return 1;
+ lp=fg->normalout->in;
+ while(lp){
+ if(lp->graph&&lp->graph->regv[i]!=fg->regv[i]) return 1;
+ lp=lp->next;
+ }
+ }
+ if(fg->branchout&&BTST(fg->branchout->av_in,fg->regv[i]->index)){
+ if(fg->branchout->regv[i]!=fg->regv[i]) return 1;
+ lp=fg->branchout->in;
+ while(lp){
+ if(lp->graph&&lp->graph->regv[i]!=fg->regv[i]) return 1;
+ lp=lp->next;
+ }
+ }
+ return 0;
+}
+void load_reg_parms(flowgraph *fg)
+/* Laedt Registerparameter, falls noetig. */
+{
+ int i,j; Var *v;
+ regp regp[MAXR+1]={0};
+/* for(i=1;i<=MAXR;i++){ regp[i].treg=0;regp[i].tvar=0;} */
+ for(i=0;i<vcount-rcount;i++){
+ v=vilist[i];
+ if((v->flags®PARM)&&(fg->regv[abs(v->reg)]!=v||(v->flags&CONVPARAMETER))&&(BTST(fg->av_in,i)||(v->flags&USEDASADR))){
+ regp[abs(v->reg)].tvar=v;
+ for(j=1;j<=MAXR;j++)
+ if(fg->regv[j]==v||lparms[j]==v) regp[abs(v->reg)].treg=j;
+ }
+ }
+ do_load_parms(regp,fg);
+}
+
+static int check_retreg(flowgraph *fg)
+{
+ IC *p;int retreg=0;
+ for(p=fg->start;p;p=p->next){
+ if(p->code==SETRETURN&&p->z.reg>=0){
+ retreg=p->z.reg;
+ break;
+ }
+ }
+ for(p=last_ic;retreg&&p;p=p->prev){
+ if(p->code==FREEREG){
+ if(p->q1.reg==retreg)
+ retreg=0;
+ }else
+ break;
+ }
+ if(DEBUG&1024) printf("check_retreg: %s\n",regnames[retreg]);
+ return retreg;
+}
+void insert_regs(flowgraph *fg1)
+/* Fuegt Registervariablen in die ICs ein. */
+{
+ int i,exit_block;IC *p,*lic=0,*new;flowgraph *lfg=0,*fg;
+ if(DEBUG&9216) printf("inserting register variables\n");
+ fg=fg1;
+ while(fg){
+ if(DEBUG&8192) printf("block %d:\n",fg->index);
+ if(fg!=fg1&&!fg->branchout&&!fg->normalout&&fg->start==fg->end)
+ exit_block=1;
+ else
+ exit_block=0;
+ p=fg->start;
+ while(p){
+ for(i=1;i<=MAXR;i++){
+ if(!fg->regv[i]) continue;
+ if(p->code==ALLOCREG&&p->q1.reg==i) ierror(0);
+ if((p->q1.flags&(VAR|REG|DONTREGISTERIZE))==VAR&&p->q1.v==fg->regv[i]&&(p->q1.v->index<vcount-rcount||cost_savings(p,i,&p->q1)>0)){
+ if(p->q1.v->index>=vcount-rcount)
+ p->q1.flags&=~(KONST|VAR|VARADR);
+ p->q1.flags|=REG;
+ p->q1.reg=i;
+ }
+ if((p->q2.flags&(VAR|REG|DONTREGISTERIZE))==VAR&&p->q2.v==fg->regv[i]&&(p->q2.v->index<vcount-rcount||cost_savings(p,i,&p->q2)>0)){
+ if(p->q2.v->index>=vcount-rcount)
+ p->q2.flags&=~(KONST|VAR|VARADR);
+ p->q2.flags|=REG;
+ p->q2.reg=i;
+ }
+ if((p->z.flags&(VAR|REG|DONTREGISTERIZE))==VAR&&p->z.v==fg->regv[i]&&(p->z.v->index<vcount-rcount||cost_savings(p,i,&p->z)>0)){
+ if(p->z.v->index>=vcount-rcount)
+ p->z.flags&=~(KONST|VAR|VARADR);
+ p->z.flags|=REG;
+ p->z.reg=i;
+ }
+ }
+ /* evtl. const-Variablen ruecksubstituieren */
+ if((p->q1.flags&VAR)&&p->q1.v->index>=vcount-rcount){
+ insert_cobj(&p->q1,&p->q1.v->cobj);
+ }
+ if((p->q2.flags&VAR)&&p->q2.v->index>=vcount-rcount){
+ insert_cobj(&p->q2,&p->q2.v->cobj);
+ }
+ if((p->z.flags&VAR)&&p->z.v->index>=vcount-rcount){
+ insert_cobj(&p->z,&p->z.v->cobj);
+ }
+ if(DEBUG&8192) pric2(stdout,p);
+ if(p==fg->end) break;
+ p=p->next;
+ }
+ if(fg->start&&fg->start->code==LABEL&&fg!=fg1) lic=fg->start;
+ for(i=1;i<=MAXR;i++){
+ if(fg->regv[i]){
+ if(DEBUG&8192){
+ printf("(%s),%ld(%p) assigned to %s\n",fg->regv[i]->identifier,zm2l(fg->regv[i]->offset),(void *)fg->regv[i],regnames[i]);
+ if(fg->regv[i]->index>=vcount-rcount||BTST(fg->av_in,fg->regv[i]->index)) printf("active at the start of block\n");
+ if(fg->regv[i]->index<vcount-rcount&&BTST(fg->av_out,fg->regv[i]->index)) printf("active at the end of block\n");
+ }
+
+ if(fg->regv[i]->index<vcount-rcount&&BTST(fg->av_out,fg->regv[i]->index)){
+ /* Variable beim Austritt aktiv? */
+ if(exit_save(fg,i)){
+ IC *tp;int mark_retreg=0;
+ if(DEBUG&8192) printf("\thave to save it at end of block\n");
+ new=new_IC();
+ new->line=0;
+ new->file=0;
+ new->code=ASSIGN;
+ new->typf=fg->regv[i]->vtyp->flags;
+ /* vla */
+ if(ISARRAY(new->typf))
+ new->typf=POINTER_TYPE(fg->regv[i]->vtyp->next);
+ /* cc */
+ if(new->typf==0) ierror(0);
+ new->q1.flags=VAR|REG;
+ new->q1.val.vmax=l2zm(0L);
+ new->q1.v=fg->regv[i];
+ new->q1.reg=i;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(fg->regv[i]->vtyp);
+ new->z.flags=VAR|DONTREGISTERIZE;
+ new->z.val.vmax=l2zm(0L);
+ new->z.v=fg->regv[i];
+ new->q1.am=new->q2.am=new->z.am=0;
+ new->use_cnt=new->change_cnt=0;
+ new->use_list=new->change_list=0;
+ /* Vor FREEREGs und evtl. Branch+COMPARE/TEST setzen */
+ if(fg->end){
+ tp=fg->end;
+ if(!tp->next){
+ mark_retreg=check_retreg(fg1);
+ if(DEBUG&1024) printf("save at end, markretreg=%s\n",regnames[mark_retreg]);
+ }
+ while(tp!=fg->start&&(tp->code==FREEREG||tp->code==SETRETURN||tp->code==NOP)){
+ if(tp->code==SETRETURN) mark_retreg=0;
+ tp=tp->prev;
+ }
+ if(tp&&tp->code>=BEQ&&tp->code<=BRA){
+ if(tp->code<BRA){
+ int c;
+ do{
+ tp=tp->prev;
+ c=tp->code;
+ if(c!=FREEREG&&c!=COMPARE&&c!=TEST) ierror(0);
+ }while(c!=COMPARE&&c!=TEST);
+ }
+ tp=tp->prev;
+ }
+ }else tp=lic;
+ insert_IC_fg(fg,tp,new);
+ if(mark_retreg){
+ IC *nop;
+ insert_allocreg(fg,tp,ALLOCREG,mark_retreg);
+ insert_allocreg(fg,new,FREEREG,mark_retreg);
+ nop=new_IC();
+ nop->code=NOP;
+ nop->q1.flags=REG;
+ nop->q1.reg=mark_retreg;
+ insert_IC_fg(fg,new,nop);
+ }
+ }
+ }
+ if(fg->regv[i]->index>=vcount-rcount||BTST(fg->av_in,fg->regv[i]->index)){
+ if(!exit_block&&(fg==fg1||entry_load(fg,i))&&(fg!=fg1||!(fg->regv[i]->flags®PARM))){
+ if(DEBUG&8192) printf("\thave to load it at start of block\n");
+ new=new_IC();
+ new->line=0;
+ new->file=0;
+ new->code=ASSIGN;
+ new->typf=fg->regv[i]->vtyp->flags;
+ /* vla */
+ if(ISARRAY(new->typf))
+ new->typf=POINTER_TYPE(fg->regv[i]->vtyp->next);
+ /* cc */
+ if(new->typf==0) ierror(0);
+ if(fg->regv[i]->index>=vcount-rcount){
+ insert_cobj(&new->q1,&fg->regv[i]->cobj);
+ }else{
+ new->q1.flags=VAR|DONTREGISTERIZE;
+ new->q1.val.vmax=l2zm(0L);
+ new->q1.v=fg->regv[i];
+ }
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(fg->regv[i]->vtyp);
+ if(fg->regv[i]->index>=vcount-rcount)
+ new->z.flags=REG;
+ else
+ new->z.flags=VAR|REG;
+ new->z.val.vmax=l2zm(0L);
+ new->z.v=fg->regv[i];
+ new->z.reg=i;
+ new->q1.am=new->q2.am=new->z.am=0;
+ new->use_cnt=new->change_cnt=0;
+ new->use_list=new->change_list=0;
+ insert_IC_fg(fg,lic,new);
+ }
+ }
+ if(!lfg||!lfg->regv[i]) insert_allocreg(fg,lic,ALLOCREG,i);
+ if(!fg->normalout||!fg->normalout->regv[i])
+ insert_allocreg(fg,fg->end?fg->end:lic,FREEREG,i);
+ }
+ }
+ if(fg->end) lic=fg->end;
+ lfg=fg;
+ fg=fg->normalout;
+ }
+ load_reg_parms(fg1);
+}
+
+void do_loop_regs(flowgraph *start,flowgraph *end,int intask)
+/* Macht die Variablenzuweisung in Schleife start-end. */
+/* Wenn end==0 Registerzuweisung fuer die ganze Funktion, ansonsten */
+/* fuer die Schleife, die zum Header start gehoert. */
+{
+ flowgraph *g,*lend;
+ int i,r,iterations;
+ Var *lregs[MAXR+1]={0};
+ unsigned char regu[MAXR+1]={0};
+ bvtype *isused=mymalloc(vsize);
+ /* Berechnen, wieviel ungefaehr eingespart wird, wenn eine Variable */
+ /* fuer diese Schleife in einem best. Register gehalten wird. */
+ /* Die savings in einer Schleife werden multipliziert, um das */
+ /* Laden/Speichern ausserhalb der Schleife geringer zu wichten. */
+ /* if(end&&(!g->normalout||!g->normalout->loopend||g->normalout->loopend->normalout->index!=-2)) ierror(0);*/
+ /* alle auf 0 */
+
+ for(i=0;i<vcount-rcount+const_vars;i++){
+ if(i<vcount-rcount&&(vilist[i]->vtyp->flags&VOLATILE)){
+ for(r=1;r<=MAXR;r++){
+ savings[i][r]=INT_MIN;
+ }
+ }else{
+ for(r=1;r<=MAXR;r++){
+ savings[i][r]=0;
+ }
+ }
+ }
+ if(end){
+ Var *v;
+ /* estimated number of iterations, avoid too big values */
+ if(optsize)
+ iterations=1;
+ else
+ iterations=4;
+ /* Evtl. Kosten fuers Laden/Speichern beim Ein-/Austritt in die */
+ /* Schleife. */
+ end=start->normalout->loopend;
+ g=end->normalout;
+ if(DEBUG&9216) printf("assigning regs to blocks %d to %d\n",start->normalout->index,end->index);
+ /* Werte modifizieren, falls Variable am Anfang/Ende der Schleife */
+ /* geladen/gespeichert werden muss. */
+ /* FIXME: Evtl. noetige stores/loads in anderen Bloecken! */
+ for(i=0;i<vcount-rcount+const_vars;i++){
+ v=vilist[i];
+ if(i>=vcount-rcount||BTST(start->av_in,i)){
+ for(r=1;r<=MAXR;r++)
+ if(start->regv[r]!=v&&savings[i][r]!=INT_MIN)
+ savings[i][r]-=cost_load_reg(r,v);
+ }
+ if(i<vcount-rcount&&BTST(g->av_out,i)){
+ for(r=1;r<=MAXR;r++)
+ if(g->regv[r]!=v&&savings[i][r]!=INT_MIN)
+ savings[i][r]-=cost_save_reg(r,v);
+ }
+ }
+ /* Werte modifizieren, falls eine andere Variable gespeichert oder */
+ /* geladen werden muss. Hmm..stimmt das so? */
+ for(r=1;r<=MAXR;r++){
+ v=start->regv[r];
+ if(v&&v->index<vcount-rcount&&BTST(start->av_in,v->index)){
+ for(i=0;i<vcount-rcount;i++)
+ if(v->index!=i&&savings[i][r]!=INT_MIN)
+ savings[i][r]-=cost_load_reg(r,vilist[i]);
+ }
+ if(v&&v->index<vcount-rcount&&BTST(g->av_out,v->index)){
+ for(i=0;i<vcount-rcount;i++)
+ if(v->index!=i&&savings[i][r]!=INT_MIN)
+ savings[i][r]-=cost_save_reg(r,vilist[i]);
+ }
+ }
+ g=start->normalout;
+ }else{
+ iterations=1;
+ /* Bei Registervergabe fuer die ganze Funktion muessen alle beim */
+ /* Eintritt der Funktion aktiven Variablen geladen werden. */
+ /* statics have to be saved at the end */
+ if(DEBUG&9216) printf("assigning regs to whole function\n");
+ for(i=0;i<vcount-rcount+const_vars;i++){
+ if(i<vcount-rcount&&(vilist[i]->storage_class==STATIC||vilist[i]->storage_class==EXTERN)){
+ for(r=1;r<=MAXR;r++)
+ if(savings[i][r]!=INT_MIN)
+ savings[i][r]-=cost_save_reg(r,vilist[i]);
+ }
+ if(i>=vcount-rcount||BTST(start->av_in,i)){
+ int pr=abs(vilist[i]->reg);
+ for(r=1;r<=MAXR;r++){
+ if(savings[i][r]!=INT_MIN){
+ if(pr==0){
+ savings[i][r]-=cost_load_reg(r,vilist[i]);
+ }else if(!regsa[r]){
+ if(r==pr)
+ savings[i][r]+=cost_save_reg(r,vilist[i]);
+ else
+ /* factor of 2, because load_parms is not always optimal */
+ savings[i][r]+=(cost_save_reg(r,vilist[i])-cost_move_reg(pr,r))/2;
+ }
+ }
+ }
+ }
+ }
+ /* Nonscratchregister muessen geladen/gesichert werden. */
+ /*FIXME: einige unschoene Effekte(?) */
+ if(!intask){
+ for(r=1;r<=MAXR;r++){
+ if(!regscratch[r]&&!regsa[r]){
+ for(i=0;i<vcount-rcount+const_vars;i++)
+ if(savings[i][r]!=INT_MIN)
+ savings[i][r]-=cost_pushpop_reg(r);
+ }
+ }
+ }
+ g=start;
+ }
+ if(DEBUG&9216) printf("calculating approximate savings\n");
+
+ lend=0;
+ for(;g;g=g->normalout){
+ IC *p;Var *v;
+ int t,vt;
+ if(!end&&!lend){
+ lend=g->loopend;
+ if(lend&&iterations==1&&!optsize) iterations=4;
+ }
+
+ /* Wenn das Register in dem Block benutzt wird, muss man es retten */
+ for(r=1;r<=MAXR;r++){
+ if(BTST(g->regused,r)||(reg_pair(r,&rp)&&(BTST(g->regused,rp.r1)||BTST(g->regused,rp.r2)))){
+ int vi;
+ if(g->regv[r]) vi=g->regv[r]->index; else vi=-1;
+ for(i=0;i<vcount-rcount+const_vars;i++){
+ if(i>=vcount-rcount||BTST(g->av_out,i)||BTST(g->av_gen,i))
+ if(vi!=i&&savings[i][r]!=INT_MIN)
+ savings[i][r]-=iterations*(cost_load_reg(r,vilist[i])+cost_save_reg(r,vilist[i]));
+ }
+ }
+ }
+ memcpy(isused,g->av_out,vsize);
+ p=g->end;
+ while(p){
+ if((p->q1.flags&(VAR|VARADR|REG))==VAR){
+ v=p->q1.v;vt=v->vtyp->flags;
+ /* vla */
+ if(ISARRAY(vt)&&is_vlength(v->vtyp))
+ vt=POINTER_TYPE(v->vtyp->next);
+ if((optflags&1024)||((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR))){
+ i=v->index;
+ if(p->code==ADDRESS||((p->code==ASSIGN||p->code==PUSH)&&(q1typ(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L)))){
+ for(r=1;r<=MAXR;r++)
+ savings[i][r]=INT_MIN;
+ }else{
+ for(r=1;r<=MAXR;r++){
+ if(!regsa[r]&&!BTST(g->regused,r)&&savings[i][r]!=INT_MIN&®ok(r,vt,-1)&&(!reg_pair(r,&rp)||(!regsa[rp.r1]&&!regsa[rp.r2]&&!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){
+ int s=cost_savings(p,r,&p->q1);
+ if(s==INT_MIN||savings[i][r]==INT_MIN)
+ savings[i][r]=INT_MIN;
+ else
+ savings[i][r]+=iterations*s;
+ }
+ }
+ }
+ }
+ }
+ if((p->q2.flags&(VAR|VARADR|REG))==VAR){
+ v=p->q2.v;vt=v->vtyp->flags;
+ /* vla */
+ if(ISARRAY(vt)&&is_vlength(v->vtyp))
+ vt=POINTER_TYPE(v->vtyp->next);
+ if((optflags&1024)||((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR))){
+ i=v->index;
+ for(r=1;r<=MAXR;r++){
+ if(!regsa[r]&&!BTST(g->regused,r)&&savings[i][r]!=INT_MIN&®ok(r,vt,-1)&&(!reg_pair(r,&rp)||(!regsa[rp.r1]&&!regsa[rp.r2]&&!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){
+ int s=cost_savings(p,r,&p->q2);
+ if(s==INT_MIN||savings[i][r]==INT_MIN)
+ savings[i][r]=INT_MIN;
+ else
+ savings[i][r]+=iterations*s;
+ }
+ }
+ }
+ }
+ if((p->z.flags&(VAR|VARADR|REG))==VAR){
+ v=p->z.v;vt=v->vtyp->flags;
+ if(ISARRAY(vt)&&is_vlength(v->vtyp))
+ vt=POINTER_TYPE(v->vtyp->next);
+ if((optflags&1024)||((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR))){
+ i=v->index;
+ if(p->code==ASSIGN&&(ztyp(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L))){
+ for(r=1;r<=MAXR;r++)
+ savings[i][r]=INT_MIN;
+ }
+ for(r=1;r<=MAXR;r++){
+ if(!regsa[r]&&!BTST(g->regused,r)&&savings[i][r]!=INT_MIN&®ok(r,vt,-1)&&(!reg_pair(r,&rp)||(!regsa[rp.r1]&&!regsa[rp.r2]&&!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){
+ int s=cost_savings(p,r,&p->z);
+ if(s==INT_MIN||savings[i][r]==INT_MIN)
+ savings[i][r]=INT_MIN;
+ else
+ savings[i][r]+=iterations*s;
+ }
+ }
+ }
+ }
+ /* bei Funktionsaufruf zerstoert... */
+ if(p->code==CALL){
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)&&!(disable&2048)){
+ for(i=0;i<vcount-rcount+const_vars;i++){
+ if(i>=vcount-rcount||BTST(isused,i)){
+ for(r=1;r<=MAXR;r++){
+ if(regscratch[r]&&savings[i][r]!=INT_MIN&&BTST(p->q1.v->fi->regs_modified,r))
+ savings[i][r]-=iterations*(cost_load_reg(r,vilist[i])+cost_save_reg(r,vilist[i]));
+ }
+ }
+ }
+ }else{
+ for(i=0;i<vcount-rcount+const_vars;i++){
+ if(i>=vcount-rcount||BTST(isused,i)){
+ for(r=1;r<=MAXR;r++){
+ if(regscratch[r]&&savings[i][r]!=INT_MIN)
+ savings[i][r]-=iterations*(cost_load_reg(r,vilist[i])+cost_save_reg(r,vilist[i]));
+ }
+ }
+ }
+ }
+ }
+ if(p==g->start) break;
+ if(p->change_cnt!=0||p->use_cnt!=0)
+ av_update(p,isused);
+ p=p->prev;
+ }
+ if(g==end) break;
+ if(!end){
+ if(g==lend) {lend=0;iterations=1;}
+ }
+ }
+ /* Maximum ermitteln */
+ memset(bregs,0,sizeof(bregs));
+ for(i=0;i<vcount-rcount+const_vars;i++){
+ int m=0,t;Var *v;
+ v=vilist[i];t=v->vtyp->flags;
+ if(ISARRAY(t)&&is_vlength(v->vtyp))
+ t=POINTER_TYPE(v->vtyp->next);
+ if(!(optflags&1024)&&((v->storage_class!=AUTO&&v->storage_class!=REGISTER)||(v->flags&USEDASADR))){
+ for(r=0;r<=MAXR;r++)
+ savings[i][r]=INT_MIN;
+ }else{
+ int one=0;
+ for(r=1;r<=MAXR;r++){
+ /* Variables should have been put to argument registers by local_regs() */
+ /*if(r==abs(v->reg)&&!(v->flags®PARM)) savings[i][r]=INT_MAX;*/
+ if(regsa[r]||!regok(r,t,-1)) savings[i][r]=INT_MIN;
+ if(savings[i][r]>m){
+ m=savings[i][r];
+ one=r;
+ }else if(savings[i][r]==m){
+ one=0;
+ }
+ }
+ savings[i][0]=m;
+ if(one) BSET(bregs,one); /* mark one register has unique value */
+ }
+ }
+ if(DEBUG&8192){
+ for(i=0;i<vcount-rcount+const_vars;i++){
+ printf("(%s),%ld(best=%d):\n",vilist[i]->identifier,zm2l(vilist[i]->offset),savings[i][0]);
+ for(r=1;r<=MAXR;r++)
+ printf("%s=%d ",regnames[r],savings[i][r]);
+ printf("\n");
+ }
+ for(r=0;r<=MAXR;r++)
+ if(BTST(bregs,r))
+ printf("reg %s unique\n",regnames[r]);
+ }
+ /* Suchen, welche Variablen/Registerkombination das beste Ergebnis */
+ /* liefert. Nur angenaehert, da sonst wohl zu aufwendig. Simplex? */
+ for(i=0;i<vcount-rcount+const_vars;i++) rvlist[i]=i;
+ vqsort(rvlist,vcount-rcount+const_vars,sizeof(*rvlist),cmp_savings);
+ for(i=0;i<vcount-rcount+const_vars;i++){
+ int use=0,m=0,prio=0,vi;
+ vi=rvlist[i];
+ /*if(vilist[vi]->flags&USEDASADR) continue;*/
+ if(DEBUG&8192) printf("%d: (%s),%ld(best=%d)\n",i,vilist[vi]->identifier,zm2l(vilist[vi]->offset),savings[vi][0]);
+ for(r=1;r<=MAXR;r++){
+ if(!lregs[r]&&!regu[r]&&savings[vi][r]>=m&&(!reg_pair(r,&rp)||(!regu[rp.r1]&&!regu[rp.r2]))){
+ int better=0;
+ if(savings[vi][r]>m){
+ better=1;
+ }else if(savings[vi][r]==m){
+ if(reg_prio[r]>prio){
+ better=1;
+ }else if(BTST(bregs,use)&&!BTST(bregs,r)){
+ better=1;
+ }
+ }
+ if(better){
+ m=savings[vi][r];prio=reg_prio[r];
+ use=r;
+ }
+ }
+ }
+ if(m>0&&check_cacheable(vi,start,end)){
+ if(DEBUG&9216) printf("assigned (%s),%ld(%p) to %s, saving=%d\n",vilist[vi]->identifier,zm2l(vilist[vi]->offset),(void *)vilist[vi],regnames[use],m);
+ lregs[use]=vilist[vi];
+ regu[use]=1;
+ if(reg_pair(use,&rp))
+ regu[rp.r1]=regu[rp.r2]=1;
+ }
+ }
+ /* Registervariablen in alle Bloecke der Schleife eintragen */
+ /* dabei beruecksichtigen, dass sie in manchen Bloecken nicht */
+ /* in Register kommen koennen, wenn das Register da schon von */
+ /* local_regs benutzt wird */
+ /* Gegebenenfalls auch in Header/Footer einer Schleife */
+ /* eintragen. */
+ if(DEBUG&9216) printf("propagate register vars\n");
+ for(g=start;g;g=g->normalout){
+ for(r=1;r<=MAXR;r++){
+ if(lregs[r]&&!BTST(g->regused,r)&&(!reg_pair(r,&rp)||(!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){
+ /* Falls Variable schon in anderem Register, loeschen */
+ for(i=1;i<=MAXR;i++){
+ if(g->regv[i]==lregs[r]) g->regv[i]=0;
+ if(reg_pair(i,&rp)){
+ if(rp.r1==r||rp.r2==r) g->regv[i]=0;
+ }
+ }
+ g->regv[r]=lregs[r];
+ if(reg_pair(r,&rp)) g->regv[rp.r1]=g->regv[rp.r2]=0;
+ }
+ }
+ if(end&&g==end->normalout) break;
+ }
+}
+void block_regs(flowgraph *fg)
+/* macht die Variablenzuweisung fuer einzelne Bloecke */
+{
+ flowgraph *g,**fgp;
+ int i,r,changed,fgz;
+ if(DEBUG&9216) printf("block_regs\n");
+
+ savings=mymalloc((vcount-rcount)*sizeof(*savings));
+ rvlist=mymalloc((vcount-rcount)*sizeof(*rvlist));
+
+ /* Array auf Bloecke im Flussgraphen mangels doppelter Verkettung */
+ fgp=mymalloc(basic_blocks*sizeof(*fgp));
+ g=fg;fgz=0;
+ while(g){
+ fgp[fgz]=g;fgz++;
+ g=g->normalout;
+ }
+ if(fgz>basic_blocks) ierror(0); else basic_blocks=fgz;
+ /* alle auf 0 */
+ do{
+ changed=0;
+ if(DEBUG&9216) printf("block_regs pass\n");
+ for(fgz=basic_blocks-1;fgz>=0;fgz--){
+ IC *p;Var *v;flowlist *lp;
+ int t,vt;
+ g=fgp[fgz];
+ if(DEBUG&8192) printf("assigning regs to block %d\n",g->index);
+ /* berechnen, wieviel ungefaehr eingespart wird, wenn eine Variable */
+ /* fuer diesen Block in einem best. Register gehalten wird */
+ if(DEBUG&8192) printf("calculating approximate savings\n");
+
+ for(i=0;i<vcount-rcount;i++){
+ for(r=1;r<=MAXR;r++){
+ if(!g->regv[r]||g->regv[r]->index!=i){
+ int w=0;
+ /* Variable muss evtl. geladen/gespeichert werden */
+ if(BTST(g->av_in,i)) w--;
+ if(BTST(g->av_out,i)) w--;
+ savings[i][r]=w;
+ }
+ }
+ }
+ if(g->calls>0){
+ /* bei Funktionsaufrufen muessen Scratchregister gespeichert werden */
+ for(r=1;r<=MAXR;r++)
+ if(regscratch[r])
+ for(i=0;i<vcount-rcount;i++) savings[i][r]-=g->calls*2;
+ }
+ /* Wenn Vorgaenger/Nachfolger selbe Variable im selben */
+ /* Register hat, entfaellt Laden/Speichern in diesem */
+ /* Block und vermutlich auch im Vorgaenger/Nachfolger */
+ /* nicht immer, aber naeherungsweise... */
+ lp=g->in;
+ while(lp){
+ if(lp->graph){
+ for(r=1;r<=MAXR;r++){
+ if(lp->graph->regv[r]&&BTST(g->av_in,lp->graph->regv[r]->index)) savings[lp->graph->regv[r]->index][r]+=2;
+ }
+ }
+ lp=lp->next;
+ }
+ if(g->branchout){
+ for(r=1;r<=MAXR;r++){
+ if(g->branchout->regv[r]&&BTST(g->av_out,g->branchout->regv[r]->index)) savings[g->branchout->regv[r]->index][r]+=2;
+ }
+ }
+ if(g->normalout&&(!g->normalout->end||g->normalout->end->code!=BRA)){
+ for(r=1;r<=MAXR;r++){
+ if(g->normalout->regv[r]&&BTST(g->av_out,g->normalout->regv[r]->index)) savings[g->normalout->regv[r]->index][r]+=2;
+ }
+ }
+
+ p=g->start;
+ while(p){
+ if((p->q1.flags&(VAR|VARADR|REG))==VAR){
+ v=p->q1.v;
+ if((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR)){
+ vt=v->vtyp->flags&NU;
+ i=v->index;
+ if(p->q1.flags&DREFOBJ) t=p->typf&NU; else t=0;
+ for(r=1;r<=MAXR;r++){
+ if(!regsa[r]&&!BTST(g->regused,r)){
+ /* extra saving, falls passendes Reg fuer DREF */
+ if(t&®ok(r,vt,t)) savings[i][r]++;
+ if(regok(r,vt,0)) savings[i][r]++;
+ }
+ }
+ }
+ }
+ if((p->q2.flags&(VAR|VARADR|REG))==VAR){
+ v=p->q2.v;
+ if((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR)){
+ vt=v->vtyp->flags&NU;
+ i=v->index;
+ if(p->q2.flags&DREFOBJ) t=p->typf&NU; else t=0;
+ for(r=1;r<=MAXR;r++){
+ if(!regsa[r]&&!BTST(g->regused,r)){
+ /* extra saving, falls passendes Reg fuer DREF */
+ if(t&®ok(r,vt,t)) savings[i][r]++;
+ if(regok(r,vt,0)) savings[i][r]++;
+ }
+ }
+ }
+ }
+ if((p->z.flags&(VAR|VARADR|REG))==VAR){
+ v=p->z.v;
+ if((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR)){
+ vt=v->vtyp->flags&NU;
+ i=v->index;
+ if(p->z.flags&DREFOBJ) t=p->typf&NU; else t=0;
+ for(r=1;r<=MAXR;r++){
+ if(!regsa[r]&&!BTST(g->regused,r)){
+ /* extra saving, falls passendes Reg fuer DREF */
+ if(t&®ok(r,vt,t)) savings[i][r]++;
+ if(regok(r,vt,0)) savings[i][r]++;
+ }
+ }
+ }
+ }
+ if(p==g->end) break;
+ p=p->next;
+ }
+ /* moegliche Kandidaten suchen; muss nicht immer die beste */
+ /* Kombination finden, sollte aber bei lokaler Vergabe */
+ /* selten einen Unterschied machen */
+ for(r=1;r<=MAXR;r++){
+ if(g->regv[r]||BTST(g->regused,r)) continue;
+ for(i=0;i<vcount-rcount;i++){
+ if(savings[i][r]>0){
+ int flag;Var *v=vilist[i];
+ /* Variable schon in anderem Register? */
+ for(flag=1;flag<=MAXR;flag++)
+ if(g->regv[flag]==v){flag=-1;break;}
+ if(flag>0){
+ if(DEBUG&9216) printf("assigned (%s),%ld(%p) to %s; saving=%d\n",vilist[i]->identifier,zm2l(vilist[i]->offset),(void *)vilist[i],regnames[r],savings[i][r]);
+ if(vilist[i]&&!vilist[i]->vtyp->flags) ierror(0);
+ g->regv[r]=vilist[i];
+ changed=1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }while(changed);
+ /* jetzt nochmal globale Register vergeben */
+/* do_loop_regs(fgp[0],fgp[basic_blocks-1]);*/
+
+ free(fgp);
+ free(rvlist);
+ free(savings);
+}
+
+void loop_regs(flowgraph *fg,int intask)
+/* weist Variablen in Schleifen Register zu */
+{
+ flowgraph *g;
+ if(disable&4096) return;
+ if(DEBUG&9216) printf("assigning regs to function\n");
+ savings=mymalloc((vcount-rcount+const_vars)*sizeof(*savings));
+ rvlist=mymalloc((vcount-rcount+const_vars)*sizeof(*rvlist));
+ do_loop_regs(fg,0,intask);
+ if(DEBUG&9216) printf("assigning regs in loops\n");
+ for(g=fg;g;g=g->normalout){
+ if(g->index==-1&&!(disable&32768)) do_loop_regs(g,g,0);
+ }
+ free(rvlist);
+ free(savings);
+}
+void insert_allocreg(flowgraph *fg,IC *p,int code,int reg)
+/* Fuegt ein ALLOCREG/FREEREG (in code) hinter p ein - bei p==0 in */
+/* first_ic. */
+{
+ IC *new=new_IC();
+ /* printf("%s %s",code==FREEREG?"freereg":"allocreg",regnames[reg]);pric2(stdout,p);*/
+ new->line=0;
+ new->file=0;
+ BSET(fg->regused,reg);
+ if(reg_pair(reg,&rp)){
+ BSET(fg->regused,rp.r1);
+ BSET(fg->regused,rp.r2);
+ regused[rp.r1]=regused[rp.r2]=1;
+ }
+ regused[reg]=1;
+ new->code=code;
+ new->typf=0;
+ new->q1.am=new->q2.am=new->z.am=0;
+ new->q1.flags=REG;
+ new->q1.reg=reg;
+ new->q2.flags=new->z.flags=0;
+ new->use_cnt=new->change_cnt=0;
+ new->use_list=new->change_list=0;
+ insert_IC_fg(fg,p,new);
+}
+
+Var *lregv[MAXR+1],*first_const,*last_const;
+flowgraph *lfg;
+static int is_header;
+
+/* re-inserts a cobj into an obj */
+static void insert_cobj(obj *o,obj *co)
+{
+ int dt=o->dtyp,df=o->flags&DREFOBJ;
+ *o=*co;
+ o->flags|=df;
+ o->dtyp=dt;
+}
+
+static Var *find_const_var(obj *o,int t)
+{
+ Var *v;
+ for(v=first_const;v;v=v->next){
+ if((v->ctyp&NQ)==(t&NQ)&&!compare_objs(o,&v->cobj,t))
+ return v;
+ }
+ return 0;
+}
+
+static long cidx;
+
+static Var *add_const_var(obj *o,int t)
+{
+ Var *v;
+ static type vt={VOID},tt;
+ int m=o->flags;
+ if(o->flags&DREFOBJ){
+ t=o->dtyp;
+ o->flags&=~DREFOBJ;
+ }
+ if(v=find_const_var(o,t)){
+ o->flags=m;
+ return v;
+ }
+ v=mymalloc(sizeof(*v));
+ v->storage_class=AUTO;
+ v->cobj=*o;
+ v->ctyp=t;
+ tt.flags=t;
+ if(ISPOINTER(t)) tt.next=&vt;
+ v->vtyp=clone_typ(&tt);
+ v->next=0;
+ v->identifier=" constant";
+ v->flags=0;
+ v->reg=0;
+#ifdef HAVE_TARGET_ATTRIBUTES
+ v->tattr=0;
+#endif
+ cidx++;
+ v->offset=l2zm(cidx);
+ if(last_const){
+ last_const->next=v;
+ }else{
+ first_const=v;
+ const_vars=0;
+ }
+ last_const=v;
+ v->index=vcount-rcount+const_vars;
+ const_vars++;
+ /* Wir ueberschreiben die Eintraege von vcount-rcount bis vcount. */
+ /* Da sie nicht mehr benutzt werden, sollte das ok sein. */
+ vilist=myrealloc(vilist,sizeof(*vilist)*(vcount-rcount+const_vars));
+ vilist[vcount-rcount+const_vars-1]=v;
+ o->flags=m;
+ return v;
+}
+
+void create_const_vars(flowgraph *fg)
+{
+ IC *p;int t;
+ Var *v;
+ if(DEBUG&1024) printf("creating const-vars\n");
+ cidx=0;
+ const_vars=0;
+ first_const=last_const=0;
+ for(;fg;fg=fg->normalout){
+ for(p=fg->start;p;p=p->next){
+ if(p->q1.flags&(KONST|VARADR)){
+ t=q1typ(p);
+ v=add_const_var(&p->q1,t);
+ p->q1.flags&=~(KONST|VARADR);
+ p->q1.flags|=(VAR|VKONST);
+ p->q1.v=v;
+ p->q1.val.vmax=l2zm(0L);
+ }
+ if(p->q2.flags&(KONST|VARADR)){
+ t=q2typ(p);
+ v=add_const_var(&p->q2,t);
+ p->q2.flags&=~(KONST|VARADR);
+ p->q2.flags|=(VAR|VKONST);
+ p->q2.v=v;
+ p->q2.val.vmax=l2zm(0L);
+ }
+ if(p->z.flags&(KONST|VARADR)){
+ t=ztyp(p);
+ v=add_const_var(&p->z,t);
+ p->z.flags&=~(KONST|VARADR);
+ p->z.flags|=(VAR|VKONST);
+ p->z.v=v;
+ p->z.val.vmax=l2zm(0L);
+ }
+ if(p==fg->end) break;
+ }
+ }
+ if(DEBUG&1024){
+ Var *v;
+ printf("const-vars:\n");
+ for(v=first_const;v;v=v->next){
+ printf("%d: ",v->index);
+ probj(stdout,&v->cobj,v->ctyp);
+ printf(" (t=%d)\n",v->ctyp);
+ }
+ }
+}
+
+void free_const_vars(void)
+{
+ Var *v,*m;
+ if(DEBUG&1024) printf("free_const_vars()\n");
+ for(v=first_const;v;){
+ m=v->next;
+ free(v);
+ v=m;
+ }
+}
+
+#if 0
+int free_hreg(flowgraph *fg,IC *p,int reg,int mustr)
+/* Macht das Register reg frei, damit es als lokale Variable im IC p */
+/* zur Verfuegung steht. Wenn mustr!=0, muss das Register unbedingt */
+/* freigemacht werden, ansonsten kann davon abgesehen werden. */
+{
+ IC *m,*first;Var *v;
+ int preg[MAXR+1]={0},calls[MAXR+1]={0},rreg,i;
+ first=0;
+ v=lregv[reg];
+ if(!v)
+ ierror(0);
+ if(DEBUG&8192) printf("free_hreg %s,%s,%d\n",regnames[reg],v->identifier,mustr);
+ if(v->reg&&!*v->identifier) ierror(0);
+ for(m=p;m;m=m->next){
+ if(m->code==CALL){
+ if((m->q1.flags&(VAR|DREFOBJ))==VAR&&m->q1.v->fi&&(m->q1.v->fi->flags&ALL_REGS)){
+ for(i=1;i<=MAXR;i++)
+ if(BTST(m->q1.v->fi->regs_modified,i)) calls[i]++;
+ }else{
+ for(i=1;i<=MAXR;i++)
+ if(regscratch[i]) calls[i]++;
+ }
+ }
+ if(m->code==ALLOCREG){
+ preg[m->q1.reg]=1;
+ if(m->q1.reg==reg) ierror(0);
+ }
+ if(m->code==FREEREG){
+ preg[m->q1.reg]=1;
+ if(m->q1.reg==reg) break;
+ }
+ if(!USEQ2ASZ){
+ if((m->q2.flags&VAR)&&m->q2.v==v&&(m->z.flags&(REG|DREFOBJ))==REG&&
+ (!(m->z.flags&VAR)||m->z.v!=v))
+ preg[m->z.reg]=1;
+ }
+ if(((m->q1.flags&VAR)&&m->q1.v==v)||
+ ((m->q2.flags&VAR)&&m->q2.v==v)||
+ ((m->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&m->z.v==v))
+ first=m;
+ /* if((m->z.flags&(REG|DREFOBJ))==REG&&m->z.reg==reg) break;*/
+ }
+ if(!first) {pric(stdout,p);ierror(0);}
+ rp.r1=rp.r2=0;
+ for(rreg=0,i=1;i<=MAXR;i++){
+ if(preg[i]||regu[i]||regsa[i]||!regok(i,v->vtyp->flags,0)) continue;
+ if(reg_pair(i,&rp)&&(preg[rp.r1]||preg[rp.r2]||regu[rp.r1]||regu[rp.r2]||regsa[rp.r1]||regsa[rp.r2])) continue;
+ if(calls[i]==0&®scratch[i]){rreg=i;break;}
+ if(calls[i]==0) rreg=i;
+ }
+ if(!rreg&&!mustr) return 0;
+ for(m=p;m!=first->next;m=m->next){
+ if((m->q1.flags&VAR)&&m->q1.v==v)
+ {if(!rreg) m->q1.flags&=~REG; else m->q1.reg=rreg;}
+ if((m->q2.flags&VAR)&&m->q2.v==v)
+ {if(!rreg) m->q2.flags&=~REG; else m->q2.reg=rreg;}
+ if((m->z.flags&VAR)&&m->z.v==v)
+ {if(!rreg) m->z.flags&=~REG; else m->z.reg=rreg;}
+#if 0
+ if((m->z.flags&(VAR|DREFOBJ))==VAR&&m->z.v==v)
+ break;
+#endif
+ }
+ if(rreg){
+ lregv[rreg]=lregv[reg];
+ regused[rreg]=1;regu[rreg]=1;BSET(fg->regused,rreg);
+ if(reg_pair(rreg,&rp)){
+ regused[rp.r1]=1;regu[rp.r1]=1;BSET(fg->regused,rp.r1);
+ regused[rp.r2]=1;regu[rp.r2]=1;BSET(fg->regused,rp.r2);
+ }
+ }
+ lregv[reg]=0;regu[reg]=0;
+ if(reg_pair(reg,&rp))
+ regu[rp.r1]=regu[rp.r2]=0;
+
+ for(m=first->next;m&&m->code==FREEREG;m=m->next){
+ if(m->q1.reg==reg){
+ if(!rreg) remove_IC_fg(fg,m); else m->q1.reg=rreg;
+/* if(rreg) insert_allocreg(fg,first,FREEREG,rreg);*/
+ return rreg;
+ }
+ }
+ insert_allocreg(fg,first->prev,ALLOCREG,reg);
+ if(rreg)
+ insert_allocreg(fg,first,FREEREG,rreg);
+ return rreg;
+}
+#endif
+int replace_local_reg(obj *o)
+/* tested, ob o eine Scratch-Variable ist und ersetzt sie gegebenenfalls */
+{
+ int i;Var *v;
+ if((o->flags&(VAR|REG|VARADR))==VAR){
+ v=o->v;i=v->index;
+ if((BTST(lfg->av_kill,i)||is_header)&&!BTST(lfg->av_out,i)){
+ for(i=1;i<=MAXR;i++){
+ if(lregv[i]==v){
+ o->flags|=(REG|SCRATCH);
+/* o->flags&=~VAR;*/
+ o->reg=i;
+ return i;
+ }
+ }
+ }
+ }
+ return 0;
+}
+void local_combine(flowgraph *fg)
+/* Versucht, Zuweisungen der Form (x)->tmp in ein direkt folgendes IC */
+/* einzugliedern. Nur einfache Tests, da nur loads eliminiert werden */
+/* sollen, die zum leichten Erkennen per cse explizit wurden. */
+{
+ IC *p,*pprev;int i,cl;
+ bvtype *used=mymalloc(vsize);
+ if(DEBUG&1024) printf("local combining\n");
+ for(;fg;fg=fg->normalout){
+ memcpy(used,fg->av_out,vsize);
+ for(p=fg->end;p;){
+ if(p->code==NOP||(!p->q1.flags&&!p->q2.flags)){
+ if(p==fg->start) break;
+ if(p->z.flags&VAR) BSET(used,p->z.v->index);
+ p=p->prev;
+ continue;
+ }
+ pprev=p->prev;
+ while(pprev&&pprev->code==NOP) pprev=pprev->prev;
+ if(pprev&&p->code==ASSIGN&&zmeqto(p->q2.val.vmax,sizetab[p->typf&NQ])&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&pprev->z.flags==p->q1.flags&&p->q1.v==pprev->z.v&&(!(p->z.flags&VAR)||p->z.v!=p->q1.v)&&ztyp(pprev)==q1typ(p)&&!BTST(used,p->q1.v->index)&&(pprev->code!=ASSIGN||zmeqto(pprev->q2.val.vmax,sizetab[pprev->typf&NQ]))){
+ /* x op y ->tmp; move tmp->*p => x op y ->*p */
+ if(DEBUG&1024){
+ printf("local combine(3):\n");
+ pric2(stdout,pprev);pric2(stdout,p);
+ }
+ pprev->z=p->z;
+ pprev->change_cnt=p->change_cnt;
+ pprev->change_list=p->change_list;
+ p->change_cnt=0;
+ p->change_list=0;
+ pprev->use_list=myrealloc(pprev->use_list,(pprev->use_cnt+p->use_cnt)*VLS);
+ memcpy(&pprev->use_list[pprev->use_cnt],p->use_list,p->use_cnt*VLS);
+ pprev->use_cnt+=p->use_cnt;
+ p->q1.flags=p->z.flags=0;
+ p->code=NOP;
+ /* restart */
+ memcpy(used,fg->av_out,vsize);
+ p=fg->end;
+ continue;
+ }
+ if((pprev)&&pprev->code==ASSIGN&&zmeqto(pprev->q2.val.vmax,sizetab[pprev->typf&NQ])
+ &&zmeqto(pprev->q2.val.vmax,sizetab[p->typf&NQ])
+ &&((pprev->q1.flags&DREFOBJ)||(static_cse&&(pprev->q1.flags&(VAR|VARADR))==VAR&&(pprev->q1.v->storage_class==EXTERN||pprev->q1.v->storage_class==STATIC)))&&(pprev->z.flags&(VAR|DREFOBJ))==VAR
+ &&!BTST(used,pprev->z.v->index)&&pprev->z.v->storage_class==AUTO
+ &&!(pprev->z.v->flags&USEDASADR)
+ &&((p->code!=ASSIGN&&p->code!=PUSH)||zmeqto(p->q2.val.vmax,sizetab[p->typf&NQ]))){
+ cl=0;
+ i=pprev->z.v->index;
+ if((p->z.flags&VAR)&&p->z.v->index==i) cl=4;
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR){
+ if(p->q1.v->index==i&&zmeqto(p->q1.val.vmax,pprev->z.val.vmax))
+ cl|=1;
+ }
+ if((p->q2.flags&(VAR|DREFOBJ))==VAR){
+ if(p->q2.v->index==i&&zmeqto(p->q2.val.vmax,pprev->z.val.vmax))
+ cl|=2;
+ }
+ if(cl==1||cl==2){
+ if(cl!=2||USEQ2ASZ||compare_objs(&pprev->q1,&p->z,p->typf)){
+ if(DEBUG&1024){printf("local combine:\n");pric2(stdout,pprev);pric2(stdout,p);}
+ if(cl==1)
+ p->q1=pprev->q1;
+ else
+ p->q2=pprev->q1;
+ p->use_list=myrealloc(p->use_list,(p->use_cnt+pprev->use_cnt)*VLS);
+ memcpy(&p->use_list[p->use_cnt],pprev->use_list,pprev->use_cnt*VLS);
+ p->use_cnt+=pprev->use_cnt;
+ pprev->code=NOP;
+ pprev->q1.flags=pprev->z.flags=0;
+ pprev->typf=0;
+ /* restart */
+ memcpy(used,fg->av_out,vsize);
+ p=fg->end;
+ continue;
+ }
+ }
+ }
+ if(p==fg->start) break;
+ if(p->q1.flags&VAR) BSET(used,p->q1.v->index);
+ if(p->q2.flags&VAR) BSET(used,p->q2.v->index);
+ if(p->z.flags&VAR) BSET(used,p->z.v->index);
+ p=p->prev;
+ }
+ }
+ free(used);
+}
+
+/* Fuegt evtl. noetige allocreg/freereg nach local_regs in Block ein. */
+/* Kann durch free_hreg noetig werden. */
+void fix_local_allocreg(flowgraph *fg)
+{
+ char regs[MAXR+1]={0};
+ IC *p=fg->end;
+ while(p){
+ if(p->code==ALLOCREG){
+ if(!regs[p->q1.reg]) ierror(0);
+ regs[p->q1.reg]=0;
+ }else if(p->code==FREEREG){
+ if(regs[p->q1.reg]){
+ ierror(0);
+ }
+ regs[p->q1.reg]=1;
+ }else{
+ if((p->q1.flags®)&&!regs[p->q1.reg]){
+ insert_allocreg(fg,p,FREEREG,p->q1.reg);
+ regs[p->q1.reg]=1;
+ }
+ if((p->q2.flags®)&&!regs[p->q2.reg]){
+ insert_allocreg(fg,p,FREEREG,p->q2.reg);
+ regs[p->q2.reg]=1;
+ }
+ if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&!regs[p->z.reg]){
+ insert_allocreg(fg,p,FREEREG,p->z.reg);
+ regs[p->z.reg]=1;
+ }
+ if((p->z.flags&(REG|DREFOBJ))==REG){
+ if(!(p->q1.flags®)||p->q1.reg!=p->z.reg){
+ if(!(p->q2.flags®)||p->q2.reg!=p->z.reg){
+ IC *p2;
+ for(p2=p->prev;p2;p2=p2->prev){
+ if(p2->code==ALLOCREG&&p2->q1.reg==p->z.reg) break;
+ if(p2->code!=ALLOCREG&&p2->code!=FREEREG) break;
+ }
+ if(p2->code!=ALLOCREG||p2->q1.reg!=p->z.reg){
+ insert_allocreg(fg,p->prev,ALLOCREG,p->z.reg);
+ }
+ }
+ }
+ }
+ }
+ if(p==fg->start) return;
+ p=p->prev;
+ }
+}
+
+/* searches back to determine the best local register for v
+ register-pairs must not be alive in the same instruction as
+ one of the halves */
+int find_best_local_reg(IC *fp,Var *v,int preferred)
+{
+ int r,used,tmp,savings[MAXR+1]={0};
+ IC *p=fp;
+
+ if(v->reg&&!*v->identifier)
+ return abs(v->reg);
+ if(v->vtyp->flags&VOLATILE)
+ return 0;
+ if(!USEQ2ASZ&&(p->q2.flags&VAR)&&p->q2.v==v)
+ savings[preferred]=INT_MIN;
+ else
+ savings[preferred]=1;
+ if(reg_pair(preferred,&rp)){
+ savings[rp.r1]=INT_MIN;
+ savings[rp.r2]=INT_MIN;
+ }
+ for(r=1;r<=MAXR;r++){
+ if(regu[r]||regsa[r]==REGSA_NEVER){
+ savings[r]=INT_MIN;
+ if(reg_pair(r,&rp)){
+ savings[rp.r1]=INT_MIN;
+ savings[rp.r2]=INT_MIN;
+ }
+ }else if(reg_pair(r,&rp)){
+ if(rp.r1==preferred||rp.r2==preferred||regu[rp.r1]||regsa[rp.r1]==REGSA_NEVER||regu[rp.r2]||regsa[rp.r2]==REGSA_NEVER)
+ savings[r]=INT_MIN;
+ }
+ if(savings[r]!=INT_MIN&&!regok(r,v->vtyp->flags,-1))
+ savings[r]=INT_MIN;
+ }
+ for(r=1;r<=MAXR;r++){
+ if(savings[r]!=INT_MIN&®_pair(r,&rp)){
+ if(regu[rp.r1]||regu[rp.r2]||regsa[rp.r1]==REGSA_NEVER||regsa[rp.r2]==REGSA_NEVER)
+ savings[r]=INT_MIN;
+ }
+ }
+ while(1){
+ if(!p){
+ if(!is_header)
+ ierror(0);
+ break;
+ }
+ if(!p||(p!=fp&&p->code>=LABEL&&p->code<=BRA)) return 0;
+ if(p!=fp){
+ if((p->z.flags&VAR)&&p->z.v->reg&&!*p->z.v->identifier){
+ if(p->z.v==v)
+ return abs(p->z.v->reg);
+ else
+ savings[abs(p->z.v->reg)]=INT_MIN;
+ }
+ }
+ used=0;
+ if((p->q1.flags&VAR)&&p->q1.v==v){
+ if(p->code==ADDRESS) return 0;
+ if((p->code==ASSIGN||p->code==PUSH)&&(q1typ(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L)))
+ return 0;
+ used=1;
+ for(r=1;r<=MAXR;r++){
+ if(savings[r]!=INT_MIN){
+ tmp=cost_savings(p,r,&p->q1);
+ if(tmp==INT_MIN)
+ savings[r]=INT_MIN;
+ else
+ savings[r]+=tmp;
+ }
+ }
+ }
+ if((p->q2.flags&VAR)&&p->q2.v==v){
+ used=1;
+ for(r=1;r<=MAXR;r++){
+ if(savings[r]!=INT_MIN){
+ tmp=cost_savings(p,r,&p->q2);
+ if(tmp==INT_MIN)
+ savings[r]=INT_MIN;
+ else
+ savings[r]+=tmp;
+ }
+ }
+ }
+ if((p->z.flags&VAR)&&p->z.v==v){
+ if(p->code==ASSIGN&&(ztyp(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L)))
+ return 0;
+ for(r=1;r<=MAXR;r++){
+ if(savings[r]!=INT_MIN){
+ tmp=cost_savings(p,r,&p->z);
+ if(tmp==INT_MIN)
+ savings[r]=INT_MIN;
+ else
+ savings[r]+=tmp;
+ }
+ }
+ if(used==0&&!(p->z.flags&DREFOBJ))
+ break;
+ }
+ if(p->code==CALL){
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)&&!(disable&2048)){
+ for(r=1;r<=MAXR;r++){
+ if(regscratch[r]&&BTST(p->q1.v->fi->regs_modified,r))
+ savings[r]=INT_MIN;
+ }
+ }else{
+ for(r=1;r<=MAXR;r++){
+ if(regscratch[r])
+ savings[r]=INT_MIN;
+ }
+ }
+ }
+
+ /* check for register arguments */
+ if((p->z.flags&(VAR|DREFOBJ))==VAR&&!*p->z.v->identifier&&p->z.v->reg){
+ if(p->code==ASSIGN&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v==v){
+ savings[abs(p->z.v->reg)]++;
+ }else{
+ savings[abs(p->z.v->reg)]=INT_MIN;
+ if(reg_pair(abs(p->z.v->reg),&rp)){
+ savings[rp.r1]=INT_MIN;
+ savings[rp.r2]=INT_MIN;
+ }
+ }
+ }
+
+ p=p->prev;
+ }
+ r=0;
+ savings[0]=0;
+ for(tmp=1;tmp<=MAXR;tmp++){
+ if(savings[tmp]>savings[r]){
+ r=tmp;
+ }else if(savings[tmp]==savings[r]){
+ if(reg_prio[tmp]>reg_prio[r])
+ r=tmp;
+ else if(reg_prio[tmp]==reg_prio[r]){
+ if(regscratch[tmp]&&!regscratch[r])
+ r=tmp;
+ else if(regscratch[tmp]==regscratch[r]&&BTST(bregs,r)&&!BTST(bregs,tmp))
+ /* if equal, prefer to leave registers used by parameters */
+ r=tmp;
+ }
+ }
+ }
+ return r;
+}
+
+static bvtype *late_changes;
+
+void search_late_opt(flowgraph *fg,IC *n,obj *o)
+{
+ Var *v=o->v;
+ IC *p=n->prev,*cp;
+ if(!zmeqto(o->val.vmax,Z0)) return;
+ if(o->v->reg!=0) return;
+ while(1){
+ if(!p) ierror(0);
+ if(p->code==LABEL) ierror(0);
+ if((p->q1.flags&VAR)&&p->q1.v==v) return;
+ if((p->q2.flags&VAR)&&p->q2.v==v) return;
+ if((p->z.flags&VAR)&&p->z.v==v){
+ if(p->z.flags&DREFOBJ) return;
+ if(p->code==CONVERT&&!must_convert(p->typf,p->typf2,0)){
+ int ucnt=0;
+ if((p->q1.flags&DREFOBJ)&&(o->flags&DREFOBJ)) return;
+ if(p->q1.flags&VARADR) return;
+ if((n->q1.flags&VAR)&&n->q1.v==o->v) ucnt++;
+ if((n->q2.flags&VAR)&&n->q2.v==o->v) ucnt++;
+ if((n->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&n->q1.v==o->v) ucnt++;
+ if(ucnt!=1) return;
+ memset(late_changes,vsize,0);
+ if((p->q1.flags&(VAR|VARADR))==VAR){
+ int i=p->q1.v->index;
+ if(p->q1.flags&DREFOBJ) i+=vcount-rcount;
+ for(cp=p;cp&&cp!=n;cp=cp->next){
+ ic_changes(cp,late_changes);
+ if(BTST(late_changes,i)) return;
+ }
+ }
+ if(DEBUG&1024){printf("removing CONVERT (!must_convert)\n");pric2(stdout,p);pric2(stdout,n);}
+ o->v=p->q1.v;
+ o->val.vmax=p->q1.val.vmax;
+ if(p->q1.flags&DREFOBJ){
+ o->flags|=DREFOBJ;
+ o->dtyp=p->q1.dtyp;
+ }
+ n->use_list=myrealloc(n->use_list,VLS*(n->use_cnt+p->use_cnt));
+ memcpy(&n->use_list[n->use_cnt],&p->use_list[0],p->use_cnt*VLS);
+ n->use_cnt+=p->use_cnt;
+ remove_IC_fg(fg,p);
+ }
+#if 0/* BIGENDIAN||LITTLEENDIAN*/
+ if(p->code==CONVERT&&ISINT(p->typf)&&ISINT(p->typf2)&&(p->typf&NQ)<=(p->typf2&NQ)){
+ if((p->q1.flags&DREFOBJ)&&(o->flags&DREFOBJ)) return;
+ if(DEBUG&1024){printf("removing CONVERT (int=>smallint)\n");pric2(stdout,p);pric2(stdout,n);}
+ o->v=p->q1.v;
+ o->val.vmax=p->q1.val.vmax;
+ if(p->q1.flags&DREFOBJ){
+ o->flags|=DREFOBJ;
+ o->dtyp=p->q1.dtyp;
+ }
+#if BIGENDIAN
+ o->val.vmax=zmadd(o->val.vmax,zmsub(sizetab[p->typf2&NQ],sizetab[p->typf&NQ]));
+#endif
+ remove_IC_fg(fg,p);
+ }
+#endif
+ return;
+ }
+ if(p==fg->start) {pric2(stdout,n);ierror(0);}
+ p=p->prev;
+ }
+}
+
+
+void late_opt(flowgraph *fg)
+{
+ IC *p;int j;bvtype *isused;
+ isused=mymalloc(vsize);
+ late_changes=mymalloc(vsize);
+ while(fg){
+ if(DEBUG&1024) printf("late opt pass block %d\n",fg->index);
+ memcpy(isused,fg->av_out,vsize);
+ for(p=fg->end;p;p=p->prev){
+ if(p->code!=NOP&&p->code!=ADDRESS&&(p->q1.flags&(VAR|VARADR))==VAR){
+ j=p->q1.v->index;
+ if(BTST(fg->av_kill,j)&&!BTST(fg->av_out,j)&&!BTST(isused,j))
+ search_late_opt(fg,p,&p->q1);
+ }
+ if(p->code!=NOP&&(p->q2.flags&(VAR|VARADR))==VAR){
+ j=p->q2.v->index;
+ if(BTST(fg->av_kill,j)&&!BTST(fg->av_out,j)&&!BTST(isused,j))
+ search_late_opt(fg,p,&p->q2);
+ }
+ if((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+ j=p->z.v->index;
+ if(BTST(fg->av_kill,j)&&!BTST(fg->av_out,j)&&!BTST(isused,j))
+ search_late_opt(fg,p,&p->z);
+ }
+ if(p==fg->start) break;
+ if(p->change_cnt||p->use_cnt)
+ av_update(p,isused);
+ }
+ fg=fg->normalout;
+ }
+ free(isused);
+ free(late_changes);
+}
+
+void local_regs(flowgraph *fg)
+/* versucht Variablen, die nur innerhalb eines Basic Blocks benutzt */
+/* werden (kill==true und out==false), Register zuzuweisen. */
+{
+ IC *p;
+ int i,j,t,r,nr,mustalloc,savings,prio,nr1,nr2;
+ late_opt(fg);
+ if(DEBUG&1024) print_flowgraph(fg);
+ bvtype *inmem=mymalloc(vsize);
+ if(DEBUG&9216) printf("assigning temporary variables to registers\n");
+ memset(inmem,0,vsize);
+ memset(bregs,0,sizeof(bregs));
+ for(i=0;i<=MAXR;i++) lparms[i]=0;
+ /* mark registers used by parameters */
+ for(p=first_ic;p;p=p->next){
+ if((p->q1.flags&VAR)&&p->q1.v->reg) BSET(bregs,abs(p->q1.v->reg));
+ if((p->q2.flags&VAR)&&p->q2.v->reg) BSET(bregs,abs(p->q2.v->reg));
+ if((p->z.flags&VAR)&&p->z.v->reg) BSET(bregs,abs(p->z.v->reg));
+ }
+ memcpy(bregsm,bregs,sizeof(bregs));
+ lfg=fg;
+ while(lfg){
+ if(DEBUG&1024) printf("block %d\n",lfg->index);
+ for(i=1;i<=MAXR;i++){lregv[i]=0; regu[i]=(regsa[i]==REGSA_NEVER); lfg->regv[i]=0;}
+ memset(&lfg->regused,0,RSIZE);
+ lfg->calls=0;
+ // if(lfg==fg&&!lfg->in) is_header=1; else is_header=0;
+ /* unmark registers used as register arguments */
+ memcpy(bregs,bregsm,sizeof(bregs));
+ for(p=lfg->start;p;p=p->next){
+ if((p->z.flags&VAR)&&!*p->z.v->identifier&&p->z.v->reg!=0) BCLR(bregs,abs(p->z.v->reg));
+ if(p==lfg->end) break;
+ }
+ p=lfg->end;
+ while(p){
+ nr=nr1=nr2=0;
+ i=replace_local_reg(&p->z);
+ if((p->z.flags&(VAR|DREFOBJ))==VAR){
+ if(i){
+ lregv[i]=0;regu[i]=0;
+ if(reg_pair(i,&rp)){
+ nr1=rp.r1;
+ nr2=rp.r2;
+ regu[nr1]=regu[nr2]=0;
+ }
+ nr=i;mustalloc=1;
+ if(DEBUG&8192) printf("regu[%s] decremented to %d\n",regnames[i],regu[i]);
+ }else{
+ BCLR(inmem,p->z.v->index);
+ }
+ }
+ if(p->code!=ADDRESS){
+ if(replace_local_reg(&p->q1)==nr) mustalloc=0;
+ if(replace_local_reg(&p->q2)==nr) mustalloc=0;
+ }
+ if((p->q1.flags&(VAR|REG|VARADR))==VAR&&!(p->q1.v->flags&USEDASADR)&&(!(p->q1.v->vtyp->flags&VOLATILE)||p->q1.v->reg)&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)){
+ j=p->q1.v->index;
+ if((BTST(lfg->av_kill,j)||is_header)&&!BTST(lfg->av_out,j)&&!BTST(inmem,j)){
+ r=find_best_local_reg(p,p->q1.v,nr);
+ if(r){
+ if(r!=nr)
+ insert_allocreg(lfg,p,FREEREG,r);
+ else
+ mustalloc=0;
+ lregv[r]=p->q1.v;regused[r]=regu[r]=1;
+ if(reg_pair(r,&rp)){
+ regu[rp.r1]=regu[rp.r2]=1;
+ regused[rp.r1]=regused[rp.r2]=1;
+ }
+ if(replace_local_reg(&p->q1)!=r) ierror(0);
+ replace_local_reg(&p->q2);
+ replace_local_reg(&p->z);
+ if((DEBUG&9216)&&*p->q1.v->identifier) printf("temporary <%s> assigned to %s (v3)\n",p->q1.v->identifier,regnames[r]);
+ if(DEBUG&8192) printf("temporary <%s>(%p) assigned to %s (v3)\n",p->q1.v->identifier,(void *)p->q1.v,regnames[r]);
+ }else BSET(inmem,j);
+ }
+ }
+ /* hier wegen USEQ2ASZ aufpassen; kommutative ICs sollten so */
+ /* angeordnet werden, dass ein evtl. Register rechts steht */
+ if((p->q2.flags&(VAR|REG|VARADR))==VAR&&!(p->q2.v->flags&USEDASADR)&&!(p->q2.v->vtyp->flags&VOLATILE)&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)){
+ j=p->q2.v->index;
+ if((BTST(lfg->av_kill,j)||is_header)&&!BTST(lfg->av_out,j)&&!BTST(inmem,j)){
+ r=find_best_local_reg(p,p->q2.v,nr);
+ if(r){
+ if(r!=nr) insert_allocreg(lfg,p,FREEREG,r);
+ else mustalloc=0;
+ lregv[r]=p->q2.v;regused[r]=regu[r]=1;
+ if(reg_pair(r,&rp)){
+ regu[rp.r1]=regu[rp.r2]=1;
+ regused[rp.r1]=regused[rp.r2]=1;
+ }
+ if(replace_local_reg(&p->q2)!=r) ierror(0);
+ replace_local_reg(&p->z);
+ if((DEBUG&9216)&&*p->q2.v->identifier) printf("temporary <%s> assigned to %s (v1)\n",p->q2.v->identifier,regnames[r]);
+ if(DEBUG&8192) printf("temporary <%s>(%p) assigned to %s (v1)\n",p->q2.v->identifier,(void *)p->q2.v,regnames[r]);
+ }else BSET(inmem,j);
+ }
+ }
+ if((p->z.flags&(VAR|REG|DREFOBJ))==(VAR|DREFOBJ)&&!(p->z.v->flags&USEDASADR)&&!(p->z.v->vtyp->flags&VOLATILE)&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)){
+ j=p->z.v->index;
+ if((BTST(lfg->av_kill,j)||is_header)&&!BTST(lfg->av_out,j)&&!BTST(inmem,j)){
+ r=find_best_local_reg(p,p->z.v,nr);
+ if(r){
+ insert_allocreg(lfg,p,FREEREG,r);
+ lregv[r]=p->z.v;regused[r]=regu[r]=1;
+ if(reg_pair(r,&rp)){
+ regu[rp.r1]=regu[rp.r2]=1;
+ regused[rp.r1]=regused[rp.r2]=1;
+ }
+ if(replace_local_reg(&p->z)!=r){
+ for(i=1;i<=MAXR;i++) if(lregv[i]) printf("%d:%s=%s(%p)\n",i,regnames[i],lregv[i]->identifier,(void*)lregv[i]);
+ ierror(r);}
+ if((DEBUG&9216)&&*p->z.v->identifier) printf("temporary <%s> assigned to %s (v2)\n",p->z.v->identifier,regnames[r]);
+ if(DEBUG&8192) printf("temporary <%s>(%p) assigned to %s (v2)\n",p->z.v->identifier,(void *)p->z.v,regnames[r]);
+ }else BSET(inmem,j);
+ }
+ }
+ if(p->code==CALL){
+ lfg->calls++;
+#if 0
+ /* falls Scratchregister bei Funktionsaufruf benutzt */
+ /* wird, moeglichst auf ein anderes ausweichen */
+ for(i=1;i<=MAXR;i++){
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
+ if(lregv[i]&®scratch[i]&&BTST(p->q1.v->fi->regs_modified,i)){
+ int j=lregv[i]->index;
+ if(lregv[i]->reg&&!*lregv[i]->identifier) ierror(0);
+ if(free_hreg(lfg,p,i,1/*0*/)==0) BSET(inmem,j);
+ }
+ }else{
+ if(lregv[i]&®scratch[i]){
+ int j=lregv[i]->index;
+ if(lregv[i]->reg&&!*lregv[i]->identifier) ierror(0);
+ if(free_hreg(lfg,p,i,1/*0*/)==0) BSET(inmem,j);
+ }
+ }
+ }
+#endif
+ }
+ /* die Faelle beachten, wenn schon im IC ein Register */
+ /* angesprochen wird (sollte nur bei CALL und return auftreten */
+ if(p->code==FREEREG){
+ ierror(0);
+ }
+ if(p->code==ALLOCREG){
+ ierror(0);
+ }
+ if(p==lfg->start) i=1; else i=0;
+ p=p->prev;
+ if(nr&&mustalloc) insert_allocreg(lfg,p,ALLOCREG,nr);
+ if(i) break;
+ }
+ fix_local_allocreg(lfg);
+ lfg=lfg->normalout;
+ if(is_header){
+ for(i=1;i<=MAXR;i++)
+ lparms[i]=lregv[i];
+ }
+ }
+ free(inmem);
+}
+void insert_saves(flowgraph *fg)
+/* fuegt speichern von Registern bei Funktionsaufrufen ein */
+{
+ int r,c,i;IC *p,*new,*n,*before,*after;Var *v;
+ bvtype *isused=mymalloc(vsize);
+ if(DEBUG&9216) printf("insert_saves\n");
+ for(;fg;fg=fg->normalout){
+ memcpy(isused,fg->av_out,vsize);
+ p=fg->end;
+ while(p){
+ c=p->code;
+ if(c==CALL){
+ if(p==fg->start) n=0; else n=p->prev;
+ for(r=1;r<=MAXR;r++){
+ i=0;
+ if((v=fg->regv[r])&&(v->index>=vcount-rcount||BTST(isused,v->index))){
+ if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)&&!(disable&2048)){
+ if(regscratch[r]&&BTST(p->q1.v->fi->regs_modified,r)) i=1;
+ }else{
+ if(regscratch[r]) i=1;
+ }
+ }
+ if(i){
+ if(!n) before=fg->start->prev; else before=n;
+ after=p->next;
+ while(after&&(after->code==FREEREG||after->code==ALLOCREG||after->code==NOP))
+ after=after->next;
+ if(!after||after->code!=GETRETURN){
+ after=p;
+ }else{
+ if((after->z.flags®)&&after->z.reg==r) after->z.flags&=~REG;
+ }
+ if(v->index>=vcount-rcount){
+ /* it is a const_var; reload instead of store */
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=v->vtyp->flags;
+ insert_cobj(&new->q1,&v->cobj);
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(v->vtyp);
+ new->z.flags=REG;
+ new->z.reg=r;
+ new->z.val.vmax=l2zm(0L);
+ new->z.v=v;
+ new->file=p->file;
+ new->line=p->line;
+ /* fake, we do nothing with this afterwards */
+ new->use_cnt=new->change_cnt=0;
+ new->change_list=new->use_list=0;
+ insert_IC_fg(fg,after,new);
+ }else{
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=v->vtyp->flags;
+ /* vla */
+ if(ISARRAY(new->typf))
+ new->typf=POINTER_TYPE(v->vtyp->next);
+ new->q1.flags=VAR|REG;
+ new->q1.v=v;
+ new->q1.val.vmax=l2zm(0L);
+ new->q1.reg=r;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(v->vtyp);
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ new->z.v=v;
+ new->file=p->file;
+ new->line=p->line;
+ /* fake, we do nothing with this afterwards */
+ new->use_cnt=new->change_cnt=0;
+ new->change_list=new->use_list=0;
+ insert_IC_fg(fg,before,new);
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=v->vtyp->flags;
+ /* vla */
+ if(ISARRAY(new->typf))
+ new->typf=POINTER_TYPE(v->vtyp->next);
+ new->q1.flags=VAR;
+ new->q1.v=v;
+ new->q1.val.vmax=l2zm(0L);
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(v->vtyp);
+ new->z.flags=VAR|REG;
+ new->z.v=v;
+ new->z.val.vmax=l2zm(0L);
+ new->z.reg=r;
+ new->file=p->file;
+ new->line=p->line;
+ /* fake, we do nothing with this afterwards */
+ new->use_cnt=new->change_cnt=0;
+ new->change_list=new->use_list=0;
+ insert_IC_fg(fg,after,new);
+ }
+ }
+ }
+ if(p->change_cnt!=0||p->use_cnt!=0)
+ av_update(p,isused);
+ p=n;
+ continue;
+ }
+ if(p==fg->start) break;
+ if(p->change_cnt!=0||p->use_cnt!=0)
+ av_update(p,isused);
+ p=p->prev;
+ }
+ }
+ free(isused);
+}
+
+
+#endif
+
+void insert_simple_allocreg(IC *p,int code,int reg)
+/* Fuegt ein ALLOCREG/FREEREG (in code) hinter p ein - bei p==0 in */
+/* first_ic. */
+{
+ IC *new=new_IC();
+ new->line=0;
+ new->file=0;
+ regused[reg]=1;
+ if(reg_pair(reg,&rp))
+ regused[rp.r1]=regused[rp.r2]=1;
+ new->code=code;
+ new->typf=0;
+ new->q1.am=new->q2.am=new->z.am=0;
+ new->q1.flags=REG;
+ new->q1.reg=reg;
+ new->q2.flags=new->z.flags=0;
+ new->use_cnt=new->change_cnt=0;
+ new->use_list=new->change_list=0;
+ insert_IC(p,new);
+}
+
+void load_simple_reg_parms(void)
+/* Laedt Registerparameter, falls noetig. Nicht-optimierende Version. */
+{
+ int i,j; Var *v;
+ regp regp[MAXR+1]={0};
+/* for(i=1;i<=MAXR;i++) {regp[i].treg=0;regp[i].tvar=0;} */
+ for(i=0;i<=1;i++){
+ if(i==0) v=vl3; else v=vl2;
+ for(;v;v=v->next){
+ if((v->flags®PARM)&&(regsv[abs(v->reg)]!=v||(v->flags&CONVPARAMETER))){
+ regp[abs(v->reg)].tvar=v;
+ for(j=1;j<=MAXR;j++)
+ if(regsv[j]==v) regp[abs(v->reg)].treg=j;
+ }
+ }
+ }
+ do_load_parms(regp,0);
+}
+
+extern zmax recalc_start_offset;
+
+void do_load_parms(regp regp[],flowgraph *fg)
+{
+ int i,i1,i2,j,j1,j2,c,k,notdone;
+ struct {int freg,treg;Var *tvar,*tmp;} order[MAXR]={0};
+ if(DEBUG&1){
+ printf("do_load_parms:\n");
+ for(i=1;i<=MAXR;i++)
+ if(regp[i].tvar)
+ printf("%s->%s(%s)\n",regnames[i],regnames[regp[i].treg],regp[i].tvar->identifier);
+ }
+ do{
+ c=0;
+ do{
+ notdone=0;
+ for(i=1;i<=MAXR;i++){
+ int notfree;
+ if(reg_pair(i,&rp)){
+ i1=rp.r1;
+ i2=rp.r2;
+ }else
+ i1=i2=0;
+ if(!regp[i].tvar) continue;
+ j=regp[i].treg;
+ if(j&®_pair(j,&rp)){
+ j1=rp.r1;
+ j2=rp.r2;
+ }else
+ j1=j2=0;
+ notfree=0;
+ for(k=1;k<=MAXR;k++){
+ if(regp[k].tvar&®_pair(k,&rp)&&(rp.r1==j||rp.r1==j1||rp.r1==j2||rp.r2==j||rp.r2==j1||rp.r2==j2)){
+ notfree=1;
+ break;
+ }
+ }
+ if(j==0||(!notfree&&!regp[j].tvar&&(!j1||!regp[j1].tvar)&&(!j2||!regp[j2].tvar))||i==j||regp[i].tmp){
+ order[c].freg=i;
+ order[c].treg=j;
+ order[c].tvar=regp[i].tvar;
+ if(regp[i].tmp){order[c].treg=0;order[c].tvar=regp[i].tmp;}
+ c++; notdone=1;
+ regp[i].treg=0;
+ regp[i].tvar=0;
+ }
+ }
+ }while(notdone);
+ for(i=c-1;i>=0;i--)
+ load_one_parm(order[i].freg,order[i].treg,0,order[i].tvar,fg);
+ notdone=0;
+ /* first try to spill register-pair (probably suboptimal, but should
+ avoid a deadlock) */
+ for(i=1;i<=MAXR;i++){
+ if(regp[i].tvar&®_pair(i,&rp))
+ break;
+ }
+ if(i>MAXR){
+ for(i=1;i<=MAXR;i++){
+ if(regp[i].tvar)
+ break;
+ }
+ }
+ if(i<=MAXR){
+ static type dtyp={DOUBLE};
+ if(!regp[i].tvar) ierror(0);
+ if(regp[i].tvar->flags&CONVPARAMETER)
+ regp[i].tmp=add_tmp_var(clone_typ(&dtyp));
+ else
+ regp[i].tmp=add_tmp_var(clone_typ(regp[i].tvar->vtyp));
+ /* num_vars is already done, so mark it by -1 */
+ regp[i].tmp->index=-1;
+ /* allocate memory for recalc_offsets */
+#ifndef NO_OPTIMIZER
+ if(fg){
+ regp[i].tmp->offset=l2zm(0L);
+ if(zmleq(recalc_start_offset,regsize[i]))
+ recalc_start_offset=regsize[i];
+ }
+#endif
+ load_one_parm(0,regp[i].treg,regp[i].tmp,regp[i].tvar,fg);
+ notdone=1;
+ }
+ }while(notdone);
+}
+void load_one_parm(int freg,int treg,Var *fvar,Var *tvar,flowgraph *fg)
+{
+ IC *new;
+ if(DEBUG&1) printf("lop: %s(%s)->%s(%s)\n",regnames[freg],fvar?fvar->identifier:empty,regnames[treg],tvar?tvar->identifier:empty);
+ if(freg&&freg!=treg){
+ if(fg){
+#ifndef NO_OPTIMIZER
+ insert_allocreg(fg,0,FREEREG,freg);
+#endif
+ }else
+ insert_simple_allocreg(0,FREEREG,freg);
+ }
+ new=new_IC();
+ new->line=0;
+ new->file=0;
+ if(tvar->flags&CONVPARAMETER){
+ new->code=CONVERT;
+ new->typf=tvar->vtyp->flags;
+ new->typf2=DOUBLE;
+ }else{
+ new->code=ASSIGN;
+ new->typf=tvar->vtyp->flags;
+ }
+ if(ISFLOAT(new->typf)) float_used=1;
+ if(fvar){
+ new->q1.flags=VAR;
+ new->q1.v=fvar;
+ new->q1.val.vmax=l2zm(0L);
+ }else{
+ new->q1.flags=REG;
+ new->q1.reg=freg;
+ }
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(tvar->vtyp);
+ if(treg)
+ new->z.flags=REG|VAR;
+ else
+ new->z.flags=VAR;
+ new->z.val.vmax=l2zm(0L);
+ new->z.v=tvar;
+ new->z.reg=treg;
+ new->q1.am=new->q2.am=new->z.am=0;
+ new->use_cnt=new->change_cnt=0;
+ new->use_list=new->change_list=0;
+ if((new->typf&NQ)==CHAR&&!regok(new->q1.reg,new->typf,0)){
+ new->code=CONVERT;
+ new->typf2=INT;
+ }
+ if(fg){
+#ifndef NO_OPTIMIZER
+ insert_IC_fg(fg,0,new);
+ if(freg&&freg!=treg) insert_allocreg(fg,0,ALLOCREG,freg);
+#endif
+ }else{
+ insert_IC(0,new);
+ if(freg&&freg!=treg) insert_simple_allocreg(0,ALLOCREG,freg);
+ }
+ if(new->z.flags®){
+ /* ALLOCREG verschieben */
+ IC *p;
+ if(fg){
+#ifndef NO_OPTIMIZER
+ insert_allocreg(fg,0,ALLOCREG,treg);
+#endif
+ }else
+ insert_simple_allocreg(0,ALLOCREG,treg);
+ for(p=new->next;p;p=p->next){
+ if(p->code==ALLOCREG&&p->q1.reg==treg){
+ if(fg){
+#ifndef NO_OPTIMIZER
+ remove_IC_fg(fg,p);
+#endif
+ }else
+ remove_IC(p);
+ break;
+ }
+ }
+ if(!p) ierror(0);
+ }
+}
+
+void simple_regs(void)
+/* haelt Variablen in Registern, simple Version */
+{
+ int i2,i,j;int pri;Var *v;
+ IC *icp,*start=first_ic;
+ if(!first_ic) return;
+ for(i=1;i<=MAXR;i++) regsv[i]=0;
+ for(i2=0;i2<=MAXR*4;i2++){
+ int only_best,pointertype=0;
+ if(i2<=MAXR*2){i=i2;only_best=1;} else {i=i2/2;pointertype=only_best=0;}
+ if(i<=MAXR&®sv[i]) continue;
+ if(i>MAXR&®sv[i-MAXR]) continue;
+ if(i>MAXR||!regsv[i]){
+ if(i>MAXR){
+ i-=MAXR;
+ if(regsv[i]) continue;
+ }else{
+ /* Ziehe Scratchregister vor, wenn kein Funktionsaufruf */
+ /* erfolgt, sonst erst andere */
+ if(!regscratch[i]) continue;
+ }
+ if(regused[i]) continue;
+ if(sregsa[i]==REGSA_TEMPS) continue;
+ if(reg_pair(i,&rp)){
+ if(regused[rp.r1]||regused[rp.r2]) continue;
+ }
+ if(simple_scratch[i]) continue;
+ /*pri=2;*/ pri=0;
+ for(j=0;j<=1;j++){
+ if(j==0) v=vl3; else v=vl2;
+ while(v){
+ if(v->storage_class==AUTO||v->storage_class==REGISTER){
+ if(!(v->flags&USEDASADR)&&!(v->vtyp->flags&VOLATILE)){
+ int vt=v->vtyp->flags&NU;
+ /* vla */
+ if(ISARRAY(vt)&&is_vlength(v->vtyp))
+ vt=POINTER_TYPE(v->vtyp->next);
+ if(only_best&&v->vtyp->next) pointertype=v->vtyp->next->flags;
+ if(v->priority>pri&®ok(i,vt,pointertype)){
+ regsv[i]=v;pri=v->priority;
+ }
+ }
+ }
+ v=v->next;
+ }
+ }
+ }
+ if(regsv[i]){
+ if(DEBUG&1) printf("Assigned <%s>(%p) to %s,%d\n",regsv[i]->identifier,(void *)regsv[i],regnames[i],i);
+ regsv[i]->priority=0;regused[i]=1;
+ if(reg_pair(i,&rp)) {regused[rp.r1]=regused[rp.r2]=1;}
+ if(!zmleq(l2zm(0L),regsv[i]->offset)&&!(regsv[i]->flags&(CONVPARAMETER|REGPARM))){
+ icp=new_IC();
+ icp->line=0;
+ icp->file=0;
+ icp->q1.am=icp->q2.am=icp->z.am=0;
+ icp->code=ASSIGN;
+ icp->typf=regsv[i]->vtyp->flags&NU;
+ icp->q1.flags=VAR;
+ icp->q1.v=regsv[i];
+ icp->q1.val.vmax=l2zm(0L);
+ icp->q2.flags=0;
+ icp->q2.val.vmax=szof(regsv[i]->vtyp);
+ icp->z.flags=REG;
+ icp->z.reg=i;
+ icp->next=first_ic;
+ icp->prev=0;
+ first_ic->prev=icp;
+ first_ic=icp;
+ }
+ icp=new_IC();
+ icp->line=0;
+ icp->file=0;
+ icp->q1.am=icp->q2.am=icp->z.am=0;
+ icp->code=ALLOCREG;
+ icp->q1.flags=REG;
+ icp->q1.reg=i;
+ icp->q2.flags=icp->z.flags=icp->typf=0;
+ icp->next=first_ic;
+ icp->prev=0;
+ first_ic->prev=icp;
+ first_ic=icp;
+ icp=new_IC();
+ icp->q1.am=icp->q2.am=icp->z.am=0;
+ icp->code=FREEREG;
+ icp->q1.flags=REG;
+ icp->q1.reg=i;
+ icp->q2.flags=icp->z.flags=icp->typf=0;
+ icp->next=0;
+ add_IC(icp);
+ }
+ }
+ icp=start;
+ while(icp){
+ if((icp->code==ALLOCREG||icp->code==FREEREG)&®sv[icp->q1.reg]){
+ /* irgendwelche allocreg/freereg im Code entfernen */
+ /* sollte nur beim Returnregister vorkommen */
+ IC *m=icp->next;
+ remove_IC(icp);
+ icp=m;continue;
+ }
+ for(i=1;i<=MAXR;i++){
+ if(!regsv[i]) continue;
+ if((icp->q1.flags&(VAR|DONTREGISTERIZE))==VAR&&icp->q1.v==regsv[i]){
+ icp->q1.flags|=REG;
+ icp->q1.reg=i;
+ }
+ if((icp->q2.flags&(VAR|DONTREGISTERIZE))==VAR&&icp->q2.v==regsv[i]){
+ icp->q2.flags|=REG;
+ icp->q2.reg=i;
+ }
+ if((icp->z.flags&(VAR|DONTREGISTERIZE))==VAR&&icp->z.v==regsv[i]){
+ icp->z.flags|=REG;
+ icp->z.reg=i;
+ }
+ }
+ icp=icp->next;
+ }
+}
+
+
diff --git a/statements.c b/statements.c
new file mode 100644
index 0000000..1779ceb
--- /dev/null
+++ b/statements.c
@@ -0,0 +1,1288 @@
+/* $VER: vbcc (statements.c) $Revision: 1.30 $ */
+
+#include "vbcc_cpp.h"
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+int cont_label=0;
+int test_assignment(type *,np);
+
+static int switchbreak;
+
+#ifdef HAVE_MISRA
+/* 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
+
+#define cr()
+#ifndef cr
+void cr(void)
+/* tested Registerbelegung */
+{
+ int i;
+ for(i=0;i<=MAXR;i++)
+ if(regs[i]!=regsa[i]) {error(149,regnames[i]);regs[i]=regsa[i];}
+}
+#endif
+
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+
+void statement(void)
+/* bearbeitet ein statement */
+{
+ token mtok;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ cr();
+ killsp();
+ if(ctok->type==LBRA){
+ enter_block();
+ if(nesting>0) local_offset[nesting]=local_offset[nesting-1];
+ compound_statement();
+ leave_block();
+ return;
+ }
+ if(ctok->type==NAME){
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#ifndef HAVE_MISRA
+ if(!strcmp("if",ctok->name)){next_token();if_statement(); return;}
+ if(!strcmp("switch",ctok->name)){next_token();switch_statement(); return;}
+ if(!strcmp("for",ctok->name)){next_token();for_statement(); return;}
+ if(!strcmp("while",ctok->name)){next_token();while_statement(); return;}
+ if(!strcmp("do",ctok->name)){next_token();do_statement(); return;}
+ if(!strcmp("goto",ctok->name)){next_token();goto_statement(); return;}
+ if(!strcmp("continue",ctok->name)){next_token();continue_statement(); return;}
+ if(!strcmp("break",ctok->name)){next_token();break_statement(); return;}
+ if(!strcmp("return",ctok->name)){next_token();return_statement(); return;}
+ if(!strcmp("case",ctok->name)){next_token(); labeled_statement(); return;}
+ if(!strcmp("default",ctok->name)){cpbez(buff,0);next_token();labeled_statement(); return;}
+#endif
+ }
+ cpbez(buff,1);
+ copy_token(&mtok,ctok);
+ next_token();killsp();
+ if(ctok->type==T_COLON){labeled_statement();return;}
+ push_token(&mtok);
+ free(mtok.name);
+ expression_statement(); /* if there is an expression statement set misra_last_break to false */
+}
+void labeled_statement(void)
+/* bearbeitet labeled_statement */
+{
+ llist *lp;int def=0;
+ nocode=0;
+ if(ctok->type==T_COLON){
+ next_token();
+ if(!*buff){
+ error(130);
+ return;
+ }
+ if(!strcmp("default",buff)){
+ def=1;
+ lp=0;
+ } else lp=find_label(buff);
+ if(lp&&lp->flags&LABELDEFINED){
+ error(131,buff);
+ return;
+ }
+ if(!lp) lp=add_label(buff);
+ lp->flags|=LABELDEFINED;
+ lp->switch_count=0;
+ if(def){
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(switch_act==0) error(150);
+ lp->flags|=LABELDEFAULT;
+ lp->switch_count=switch_act;
+ }else {
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ }
+ gen_label(lp->label);
+ afterlabel=0;
+ }else{
+ /* case */
+ np tree;llist *lp;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ tree=expression();
+ killsp();
+ if(ctok->type==T_COLON){
+ next_token();
+ killsp();
+ } else error(70);
+ if(!switch_count){
+ error(132);
+ } else {
+ if(!tree||!type_expression(tree,0))
+ {
+ } else {
+ if(tree->flags!=CEXPR||tree->sidefx){
+ error(133);
+ } else {
+ if(!ISINT(tree->ntyp->flags)){
+ error(134);
+ } else {
+ lp=add_label(empty);
+ lp->flags=LABELDEFINED;
+ lp->switch_count=switch_act;
+ eval_constn(tree);
+ insert_const(&lp->val,switch_typ);
+ gen_label(lp->label);
+ }
+ }
+ }
+ }
+ if(tree) free_expression(tree);
+ }
+ cr();
+ killsp();
+ if(ctok->type!=RBRA) statement();
+}
+void if_statement(void)
+/* bearbeitet if_statement */
+{
+ int ltrue,lfalse,lout,cexpr=0,cm,tm,merk_elseneed;
+ np tree;IC *new;
+ static int elseneed;
+ merk_elseneed=elseneed;
+ elseneed=0;
+ killsp();
+ if(ctok->type==LPAR) next_token(); else error(151);
+ killsp();cm=nocode;
+ tree=expression();
+ if(!tree){
+ error(135);
+ }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ ltrue=++label;lfalse=++label;
+ simple_alg_opt(tree);
+ if(type_expression(tree,andcomp(tree,0))){
+ tree=makepointer(tree);
+ if(!ISARITH(tree->ntyp->flags)&&!ISPOINTER(tree->ntyp->flags)){
+ error(136);
+ }else{
+ if(tree->flags==ASSIGN&&tree->right->flags!=CALL) error(164);
+ gen_IC(tree,ltrue,lfalse);
+ if(tree->flags==CEXPR){
+ eval_const(&tree->val,tree->ntyp->flags&NU);
+ if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))) cexpr=2; else cexpr=1;
+ }else
+ cexpr=0;
+ if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&cexpr) free_reg(tree->o.reg);
+ if(tree->o.flags&&!cexpr){
+ gen_test(&tree->o,tree->ntyp->flags,BEQ,lfalse);
+#if 0
+ new=new_IC();
+ new->code=TEST;
+ new->q1=tree->o;
+ new->q2.flags=new->z.flags=0;
+ new->typf=tree->ntyp->flags;
+ add_IC(new);
+ new=new_IC();
+ new->code=BEQ;
+ new->typf=lfalse;
+ add_IC(new);
+#endif
+ }
+ if(cexpr==2){
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lfalse;
+ add_IC(new);
+ }
+ }
+ }
+ tm=tree->o.flags;
+ free_expression(tree);
+ }
+ killsp(); if(ctok->type==RPAR) next_token(); else error(59);
+ if(cexpr==2) nocode=1;
+ if(!cexpr&&!tm) gen_label(ltrue);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ statement();
+ killsp();
+ if(ctok->type!=NAME||strcmp("else",ctok->name)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ nocode=cm;
+ if(cexpr!=1) gen_label(lfalse);
+ elseneed=merk_elseneed;
+ return;
+ }
+ next_token();
+ lout=++label;
+ if(cexpr!=2){
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lout;
+ add_IC(new);
+ }
+ if(cexpr!=1) {nocode=cm;gen_label(lfalse);}
+ if(cexpr==1) nocode=1; else nocode=cm;
+ if(ctok->type!=LBRA){
+ if(ctok->type!=NAME||strcmp("if",ctok->name)) {
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ }
+ else
+ elseneed=1;
+ }
+ statement();
+ elseneed=merk_elseneed;
+ nocode=cm;
+ if(cexpr!=2) gen_label(lout);
+ cr();
+}
+
+
+void switch_statement(void)
+/* bearbeitet switch_statement */
+{
+ np tree;int merk_typ,merk_count,merk_break,num_cases;
+ IC *merk_fic,*merk_lic,*new;llist *lp,*l1,*l2;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ nocode=0;
+ killsp();
+ if(ctok->type==LPAR){
+ next_token();killsp();
+ } else error(151);
+ tree=expression(); killsp();
+ if(ctok->type==RPAR){
+ next_token();killsp();
+ } else error(59);
+ merk_typ=switch_typ;merk_count=switch_act;merk_break=break_label;
+ if(!tree){
+ error(137);
+ } else {
+ if(!type_expression(tree,0)){
+ }else{
+ if(!ISINT(tree->ntyp->flags)){
+ error(138);
+ } else {
+ int m1,m2,m3,def=0,rm,rm1,rm2,minflag;
+ zmax l,ml,s;zumax ul,mul,us;
+ if(tree->flags==ASSIGN&&tree->right->flags!=CALL) error(164);
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ m3=break_label=++label;m1=switch_act=++switch_count;
+ m2=switch_typ=tree->ntyp->flags&NU;
+ gen_IC(tree,0,0);
+ if((SWITCHSUBS&&!shortcut(SUB,m2))||(!SWITCHSUBS&&!shortcut(COMPARE,m2))){
+ switch_typ=m2=int_erw(m2);
+ convert(tree,m2);
+ }
+ if((tree->o.flags&(DREFOBJ|SCRATCH))!=SCRATCH){
+ new=new_IC();
+ new->code=ASSIGN;
+ new->q1=tree->o;
+ new->q2.flags=0;
+ new->q2.val.vmax=sizetab[m2&NQ];
+ get_scratch(&new->z,m2,0,0);
+ new->typf=m2;
+ tree->o=new->z;
+ add_IC(new);
+ }
+ if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)){
+ int r=tree->o.reg;
+ rm=regs[r];
+ regs[r]=regsa[r];
+ if(reg_pair(r,&rp)){
+ rm1=regs[rp.r1];
+ rm2=regs[rp.r2];
+ regs[rp.r1]=regsa[rp.r1];
+ regs[rp.r2]=regsa[rp.r2];
+ }
+ }
+ merk_fic=first_ic;merk_lic=last_ic;
+
+ first_ic=last_ic=0;
+ {
+ int merk_sb=switchbreak;
+ switchbreak=1;
+ statement();
+ switchbreak=merk_sb;
+ }
+
+ if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)){
+ int r=tree->o.reg;
+ regs[r]=rm;
+ if(reg_pair(r,&rp)){
+ regs[rp.r1]=rm1;
+ regs[rp.r2]=rm2;
+ }
+ }
+ minflag=0;s=l2zm(0L);us=ul2zum(0UL);
+ num_cases=0;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ for(l1=first_llist;l1;l1=l1->next)
+ if(l1->switch_count==m1) num_cases++;
+ for(l1=first_llist;l1;l1=l1->next){
+ if(l1->switch_count!=m1) continue;
+ if(l1->flags&LABELDEFAULT){
+ if(def) error(139);
+ def=l1->label;
+ continue;
+ }
+ lp=0;minflag&=~1;
+ for(l2=first_llist;l2;l2=l2->next){
+ if(l2->switch_count!=m1) continue;
+ if(l2->flags&LABELDEFAULT) continue;
+ eval_const(&l2->val,m2);
+ if(minflag&2){
+ if(m2&UNSIGNED){
+ if(zumleq(vumax,mul)||zumeqto(vumax,mul)) continue;
+ }else{
+ if(zmleq(vmax,ml)||zmeqto(vmax,ml)) continue;
+ }
+ }
+ if(minflag&1){
+ if(m2&UNSIGNED){
+ if(!(minflag&4)&&zumeqto(vumax,ul)){
+ error(201);
+ minflag|=4;
+ }
+ if(zumleq(vumax,ul)){
+ lp=l2;
+ ul=vumax;
+ }
+ }else{
+ if(!(minflag&4)&&zmeqto(vmax,l)){ error(201);minflag|=4;}
+ if(zmleq(vmax,l)){lp=l2;l=vmax;}
+ }
+ }else{
+ minflag|=1;
+ l=vmax;
+ ul=vumax;
+ lp=l2;
+ }
+ }
+ if(!lp) continue;
+ ml=l;mul=ul;minflag|=2;
+ if(SWITCHSUBS&&num_cases<JUMP_TABLE_LENGTH){
+ new=new_IC();
+ new->line=0;
+ new->file=0;
+ new->typf=m2;
+ new->code=SUB;
+ new->q1=tree->o;
+ new->z=tree->o;
+ new->q2.flags=KONST;
+ eval_const(&lp->val,m2);
+ if(m2&UNSIGNED){
+ gval.vumax=zumsub(vumax,us);
+ eval_const(&gval,UNSIGNED|MAXINT);
+ }else{
+ gval.vmax=zmsub(vmax,s);
+ eval_const(&gval,MAXINT);
+ }
+ insert_const(&new->q2.val,m2);
+ new->q1.am=new->q2.am=new->z.am=0;
+ s=l;us=ul;
+ new->prev=merk_lic;
+ if(merk_lic) merk_lic->next=new; else merk_fic=new;
+ merk_lic=new;
+ new=new_IC();
+ new->line=0;
+ new->file=0;
+ new->typf=m2;
+ new->code=TEST;
+ new->q1=tree->o;
+ new->q2.flags=new->z.flags=0;
+ new->prev=merk_lic;
+ new->q1.am=new->q2.am=new->z.am=0;
+ if(merk_lic) merk_lic->next=new; else merk_fic=new;
+ merk_lic=new;
+ }else{
+ new=new_IC();
+ new->line=0;
+ new->file=0;
+ new->code=COMPARE;
+ new->typf=m2;
+ new->q1=tree->o;
+ new->q2.flags=KONST;
+ new->q2.val=lp->val;
+ new->z.flags=0;
+ new->prev=merk_lic;
+ new->q1.am=new->q2.am=new->z.am=0;
+ if(merk_lic) merk_lic->next=new; else merk_fic=new;
+ merk_lic=new;
+ }
+ new=new_IC();
+ new->line=0;
+ new->file=0;
+ new->code=BEQ;
+ new->typf=lp->label;
+ new->q1.flags=new->q2.flags=new->z.flags=0;
+ new->prev=merk_lic;
+ new->q1.am=new->q2.am=new->z.am=0;
+ merk_lic->next=new;
+ merk_lic=new;
+ }
+ if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)){ /* free_reg(tree->o.reg); */
+ new=new_IC();
+ new->line=0;
+ new->file=0;
+ new->code=FREEREG;new->typf=0;
+ new->q2.flags=new->z.flags=0;
+ new->q1.flags=REG;
+ new->q1.reg=tree->o.reg;
+ new->prev=merk_lic;
+ new->q1.am=new->q2.am=new->z.am=0;
+ if(merk_lic) merk_lic->next=new; else merk_fic=new;
+ merk_lic=new;
+ regs[tree->o.reg]=regsa[tree->o.reg];
+ if(reg_pair(tree->o.reg,&rp)){ regs[rp.r1]=regsa[rp.r1];regs[rp.r2]=regsa[rp.r2];}
+ }
+ new=new_IC();
+ new->line=0;
+ new->file=0;
+ new->code=BRA;
+ if(def) new->typf=def; else {
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ new->typf=m3;
+ }
+ new->q1.flags=new->q2.flags=new->z.flags=0;
+ if(merk_lic) merk_lic->next=new; else merk_fic=new;
+ new->prev=merk_lic;
+ if(first_ic){
+ first_ic->prev=new;
+ new->next=first_ic;
+ }else{
+ last_ic=new;
+ new->next=first_ic;
+ }
+ new->q1.am=new->q2.am=new->z.am=0;
+ first_ic=merk_fic;
+ gen_label(m3);
+ }
+ }
+ }
+ switch_typ=merk_typ;switch_act=merk_count;break_label=merk_break;
+ if(tree) free_expression(tree);
+ cr();
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+}
+void repair_tree(np p)
+/* Bearbeitet einen Ausdruckbaum so, dass er ein zweites Mal */
+/* mit gen_IC erzeugt werden kann. */
+{
+ if(p->left) repair_tree(p->left);
+ if(p->right) repair_tree(p->right);
+ if(p->flags==IDENTIFIER||p->flags==(IDENTIFIER|256))
+ p->o.v=find_var(p->identifier,0);
+ if(p->flags==CALL){
+ argument_list *al=p->alist;
+ while(al){
+ repair_tree(al->arg);
+ al=al->next;
+ }
+ }
+}
+void while_statement(void)
+/* bearbeitet while_statement */
+{
+ np tree;int lloop,lin,lout,cm,cexpr,contm,breakm;
+ IC *new,*mic; int line,tvalid;char *file;
+ killsp();
+ if(ctok->type==LPAR) {next_token();killsp();} else error(151);
+ tree=expression();
+ cexpr=0;
+ if(tree){
+ simple_alg_opt(tree);
+ if(tvalid=type_expression(tree,andcomp(tree,0))){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ tree=makepointer(tree);
+ if(!ISARITH(tree->ntyp->flags)&&!ISPOINTER(tree->ntyp->flags)){
+ error(140);
+ cexpr=-1;
+ }else{
+ if(tree->flags==ASSIGN&&tree->right->flags!=CALL) error(164);
+ if(tree->flags==CEXPR){
+ eval_const(&tree->val,tree->ntyp->flags);
+ if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))) cexpr=1; else cexpr=2;
+ if(cexpr==1) error(152);
+ }
+ }
+ }else cexpr=-1;
+ } else error(141);
+ lloop=++label;lin=++label;lout=++label;cm=nocode;
+ contm=cont_label;breakm=break_label;
+ if(!cexpr||tree->sidefx) cont_label=lin; else cont_label=lloop;
+ if(!cexpr||tree->sidefx){
+ if(c_flags_val[0].l&2){ /* bei Optimierung */
+ if(tvalid){
+ gen_IC(tree,lloop,lout);
+ if(tree->o.flags){
+ gen_test(&tree->o,tree->ntyp->flags,BEQ,lout);
+#if 0
+ new=new_IC();
+ new->code=TEST;
+ new->typf=tree->ntyp->flags;
+ new->q1=tree->o;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ new=new_IC();
+ new->code=BEQ;
+ new->typf=lout;
+ add_IC(new);
+#endif
+ }
+ repair_tree(tree);
+ }
+ }else{
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lin;
+ new->flags|=LOOP_COND_TRUE;
+ add_IC(new);
+ }
+ }
+ if(cexpr==1){
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lout;
+ add_IC(new);
+ }else{
+ gen_label(lloop);
+ last_ic->flags|=LOOP_COND_TRUE;
+ }
+ line=last_ic->line;file=last_ic->file;
+ cm=nocode;break_label=lout;
+ if(cexpr==1) nocode=1;
+ currentpri*=looppri;
+ killsp();
+ if(ctok->type==RPAR) {next_token();killsp();} else error(59);
+ {
+ int merk_sb=switchbreak;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ switchbreak=0;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ statement();
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ switchbreak=merk_sb;
+ }
+ mic=last_ic;
+ nocode=cm;cont_label=contm;break_label=breakm;
+ if(!cexpr||tree->sidefx) gen_label(lin);
+ /* correct if mic was a branch to label lin and eliminated */
+ if(last_ic->prev!=mic) mic=last_ic;
+ if(tree&&cexpr>=0){
+ if(cexpr!=1||tree->sidefx){
+ gen_IC(tree,lloop,lout);
+ if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&cexpr) free_reg(tree->o.reg);
+ }
+ if(tree->o.flags&&!cexpr){
+ gen_test(&tree->o,tree->ntyp->flags,BNE,lloop);
+#if 0
+ new=new_IC();
+ new->code=TEST;
+ new->typf=tree->ntyp->flags;
+ new->q1=tree->o;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ new=new_IC();
+ new->code=BNE;
+ new->typf=lloop;
+ add_IC(new);
+#endif
+ }
+ if(cexpr==2){
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lloop;
+ add_IC(new);
+ }
+ }
+ if(tree) free_expression(tree);
+ for(mic=mic->next;mic;mic=mic->next){
+ mic->line=line;mic->file=file;
+ }
+ gen_label(lout);
+ currentpri/=looppri;
+ cr();
+}
+void for_statement(void)
+/* bearbeitet for_statement */
+{
+ np tree1=0,tree2=0,tree3=0;int lloop,lin,lout,cm,cexpr=0,contm,breakm,with_decl,tvalid;
+ IC *new,*mic;int line;char *file;
+ killsp();
+ if(ctok->type==LPAR) {next_token();killsp();} else error(59);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(c99&&declaration(0)){
+ with_decl=1;
+ enter_block();
+ if(nesting>0) local_offset[nesting]=local_offset[nesting-1];
+ for_decl=1;
+ var_declaration();
+ for_decl=0;
+ }else{
+ with_decl=0;
+ if(ctok->type!=SEMIC) tree1=expression();
+ if(tree1){
+ if(tree1->flags==POSTINC) tree1->flags=PREINC;
+ if(tree1->flags==POSTDEC) tree1->flags=PREDEC;
+ if(type_expression(tree1,0)){
+ if(tree1->sidefx){
+ gen_IC(tree1,0,0);
+ if(tree1&&(tree1->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(tree1->o.reg);
+ }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ error(153);
+ }
+ }
+ free_expression(tree1);
+ }
+ killsp();
+ if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+ }
+ if(ctok->type!=SEMIC) {tree2=expression();killsp();} else {cexpr=2;}
+ if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+ if(ctok->type!=RPAR) tree3=expression();
+ killsp();
+ if(ctok->type==RPAR) {next_token();killsp();} else error(59);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(tree3){
+ if(!type_expression(tree3,0)){
+ free_expression(tree3);
+ tree3=0;
+ }
+ }
+ if(tree2){
+ simple_alg_opt(tree2);
+ if(tvalid=type_expression(tree2,andcomp(tree2,0))){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ tree2=makepointer(tree2);
+ if(!ISARITH(tree2->ntyp->flags)&&!ISPOINTER(tree2->ntyp->flags)){
+ error(142);
+ cexpr=-1;
+ }else{
+ if(tree2->flags==ASSIGN&&tree2->right->flags!=CALL) error(164);
+ if(tree2->flags==CEXPR){
+ eval_const(&tree2->val,tree2->ntyp->flags);
+ if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))) cexpr=1; else cexpr=2;
+ if(cexpr==1) error(152);
+ }
+ }
+ }else cexpr=-1;
+ }
+ lloop=++label;lin=++label;lout=++label;cm=nocode;
+ contm=cont_label;breakm=break_label;
+ cont_label=++label;break_label=lout;
+ if(!cexpr||(tree2&&tree2->sidefx)){
+ if(c_flags_val[0].l&2){ /* bei Optimierung */
+ if(tvalid){
+ gen_IC(tree2,lloop,lout);
+ if(tree2->o.flags){
+ gen_test(&tree2->o,tree2->ntyp->flags,BEQ,lout);
+#if 0
+ new=new_IC();
+ new->code=TEST;
+ new->typf=tree2->ntyp->flags;
+ new->q1=tree2->o;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ new=new_IC();
+ new->code=BEQ;
+ new->typf=lout;
+ add_IC(new);
+#endif
+ }
+ repair_tree(tree2);
+ }
+ }else{
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lin;
+ new->flags|=LOOP_COND_TRUE;
+ add_IC(new);
+ }
+ }
+ if(cexpr==1){
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lout;
+ add_IC(new);
+ }else{
+ gen_label(lloop);
+ last_ic->flags|=LOOP_COND_TRUE;
+ }
+ line=last_ic->line;file=last_ic->file;
+ cm=nocode;
+ if(cexpr==1) nocode=1;
+ currentpri*=looppri;
+ {
+ int merk_sb=switchbreak;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ switchbreak=0;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+ statement();
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ switchbreak=merk_sb;
+ }
+ mic=last_ic;
+ nocode=cm;
+ gen_label(cont_label);
+ cont_label=contm;break_label=breakm;
+ if(tree3){
+ if(tree3->flags==POSTINC) tree3->flags=PREINC;
+ if(tree3->flags==POSTDEC) tree3->flags=PREDEC;
+ if(tree3->sidefx){
+ gen_IC(tree3,0,0);
+ if(tree3&&(tree3->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(tree3->o.reg);
+ }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ error(153);}
+ free_expression(tree3);
+ }
+ if(!cexpr||(tree2&&tree2->sidefx)) gen_label(lin);
+ if(tree2&&cexpr>=0){
+ if(cexpr!=1||tree2->sidefx){
+ gen_IC(tree2,lloop,lout);
+ if((tree2->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&cexpr) free_reg(tree2->o.reg);
+ }
+ if(tree2->o.flags&&!cexpr){
+ gen_test(&tree2->o,tree2->ntyp->flags,BNE,lloop);
+#if 0
+ new=new_IC();
+ new->code=TEST;
+ new->typf=tree2->ntyp->flags;
+ new->q1=tree2->o;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ new=new_IC();
+ new->code=BNE;
+ new->typf=lloop;
+ add_IC(new);
+#endif
+ }
+ if(cexpr==2){
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lloop;
+ add_IC(new);
+ }
+ }
+ if(!tree2&&cexpr==2){
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lloop;
+ add_IC(new);
+ }
+ if(tree2) free_expression(tree2);
+ for(mic=mic->next;mic;mic=mic->next){
+ mic->line=line;mic->file=file;
+ }
+ gen_label(lout);
+ currentpri/=looppri;
+ cr();
+ if(with_decl)
+ leave_block();
+}
+void do_statement(void)
+/* bearbeitet do_statement */
+{
+ np tree;int lloop,lout,contm,breakm;
+ IC *new;
+ lloop=++label;lout=++label;currentpri*=looppri;
+ gen_label(lloop);
+ breakm=break_label;contm=cont_label;cont_label=++label;break_label=lout;
+ {
+ int merk_sb=switchbreak;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ switchbreak=0;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+#endif
+ statement();
+
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ switchbreak=merk_sb;
+ }
+ killsp();
+ gen_label(cont_label);cont_label=contm;break_label=breakm;
+ if(ctok->type!=NAME||strcmp("while",ctok->name)) error(154);
+ next_token();killsp();
+ if(ctok->type==LPAR) {next_token();killsp();} else error(151);
+ tree=expression();
+ if(tree){
+ simple_alg_opt(tree);
+ if(type_expression(tree,andcomp(tree,0))){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ tree=makepointer(tree);
+ if(ISARITH(tree->ntyp->flags)||ISPOINTER(tree->ntyp->flags)){
+ if(tree->flags==ASSIGN&&tree->right->flags!=CALL) error(164);
+ if(tree->flags==CEXPR){
+ eval_const(&tree->val,tree->ntyp->flags);
+ if(tree->sidefx) gen_IC(tree,0,0);
+ if(!zldeqto(vldouble,d2zld(0.0))){
+ new=new_IC();
+ new->code=BRA;
+ new->typf=lloop;
+ add_IC(new);
+ }
+ }else{
+ gen_IC(tree,lloop,lout);
+ if(tree->o.flags){
+ gen_test(&tree->o,tree->ntyp->flags,BNE,lloop);
+#if 0
+ new=new_IC();
+ new->code=TEST;
+ new->typf=tree->ntyp->flags;
+ new->q1=tree->o;
+ new->q2.flags=new->z.flags=0;
+ add_IC(new);
+ new=new_IC();
+ new->code=BNE;
+ new->typf=lloop;
+ add_IC(new);
+#endif
+ }
+ }
+ }else error(143);
+ }
+ free_expression(tree);
+ }
+ killsp();
+ if(ctok->type==RPAR) {next_token();killsp();} else error(59);
+ if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+ gen_label(lout);
+ currentpri/=looppri;
+ cr();
+}
+void goto_statement(void)
+/* bearbeitet goto_statement */
+{
+ llist *lp;
+ IC *new;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ killsp();
+ if(ctok->type!=NAME){
+ error(144);
+ }else{
+ if(is_keyword(ctok->name)) error(216,ctok->name);
+ lp=find_label(ctok->name);
+ if(!lp){
+ lp=add_label(ctok->name);
+ lp->switch_count=0;
+ }
+ lp->flags|=LABELUSED;
+ new=new_IC();
+ new->typf=lp->label;
+ new->code=BRA;
+ new->typf=lp->label;
+ add_IC(new);
+ next_token();
+ killsp();
+ if(ctok->type==SEMIC){next_token();killsp();} else error(54);
+ cr();
+ goto_used=1;
+ }
+}
+void continue_statement(void)
+/* bearbeitet continue_statement */
+{
+ IC *new;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(cont_label==0){error(145);return;}
+ //if(block_vla[nesting]) freevl();
+ new=new_IC();
+ new->code=BRA;
+ new->typf=cont_label;
+ add_IC(new);
+ killsp();
+ if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+ cr();
+}
+void break_statement(void)
+/* bearbeitet break_statement */
+{
+ IC *new;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ if(break_label==0){error(146);return;}
+ //if(block_vla[nesting]) freevl();
+ new=new_IC();
+ new->code=BRA;
+ new->typf=break_label;
+ add_IC(new);
+ killsp();
+ if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+ cr();
+}
+static void check_auto_return(np tree)
+/* Testet, ob Knoten Adresse einer automatischen Variable ist. */
+{
+ if((tree->flags==ADDRESS||tree->flags==ADDRESSS||tree->flags==ADDRESSA)&&tree->left->flags==IDENTIFIER){
+ Var *v;
+ if(v=find_var(tree->left->identifier,0)){
+ if(v->storage_class==AUTO) error(224);
+ }
+ }
+}
+extern int has_return;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+void return_statement(void)
+/* bearbeitet return_statement */
+/* SETRETURN hat Groesse in q2.reg und z.reg==ffreturn(rtyp) */
+{
+ np tree;
+ IC *new;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ has_return=1;
+ killsp();
+ if(ctok->type!=SEMIC){
+ if(tree=expression()){
+ if(!return_typ){
+ if(type_expression(tree,0)){
+ tree=makepointer(tree);
+ if((tree->ntyp->flags&NQ)!=VOID)
+ error(155);
+ else{
+ error(225);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ }
+ gen_IC(tree,0,0);
+ if((tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(tree->o.reg);
+ }
+ }else{
+ if(type_expression(tree,return_typ)){
+ tree=makepointer(tree);
+ if(tree->flags==ADD||(tree->flags==SUB&&ISPOINTER(tree->ntyp->flags))){
+ check_auto_return(tree->left);
+ check_auto_return(tree->right);
+ }else{
+ check_auto_return(tree);
+ }
+ if(!test_assignment(return_typ,tree)){free_expression(tree);return;}
+ gen_IC(tree,0,0);
+ convert(tree,return_typ->flags);
+#ifdef OLDPARMS /* alte CALL/RETURN-Methode */
+ new=new_IC();
+ new->code=ASSIGN;
+ new->typf=return_typ->flags&NU;
+ new->q1=tree->o;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(return_typ);
+ if(ffreturn(return_typ)){
+ new->z.flags=SCRATCH|REG;
+ new->z.reg=ffreturn(return_typ);
+ if(!regs[new->z.reg]){
+ IC *alloc=new_IC();
+ alloc->code=ALLOCREG;
+ alloc->q1.flags=REG;
+ alloc->q2.flags=alloc->z.flags=0;
+ alloc->q1.reg=new->z.reg;
+ regs[new->z.reg]=1;
+ add_IC(alloc);
+ }
+ }else{
+ new->z.reg=0;
+ new->z.v=return_var;
+ new->z.flags=SCRATCH|VAR;
+ new->z.val.vmax=l2zm(0L);
+ }
+ add_IC(new);
+ /* das hier ist nicht sehr schoen, aber wie sonst? */
+ if((new->z.flags&(SCRATCH|REG))==(SCRATCH|REG)&®s[new->z.reg]) free_reg(new->z.reg);
+#else
+ new=new_IC();
+ if(return_var){ /* Returnwert ueber Zeiger */
+ new->code=ASSIGN;
+ new->z.flags=VAR|DREFOBJ;
+ new->z.dtyp=POINTER_TYPE(return_typ);
+ new->z.val.vmax=l2zm(0L);
+ new->z.v=return_var;
+ new->z.reg=0;
+ }else{
+ new->code=SETRETURN;
+ new->z.reg=ffreturn(return_typ);
+ new->z.flags=0;
+ }
+ new->typf=return_typ->flags;
+ /*new->typf=tree->ntyp->flags;*/
+ new->q1=tree->o;
+ new->q2.flags=0;
+ new->q2.val.vmax=szof(return_typ);
+ add_IC(new);
+#endif
+ }
+ }
+ free_expression(tree);
+ killsp();
+ if(ctok->type==SEMIC) {next_token();killsp();} else error(54);
+ }else{
+ if(return_typ) error(156);
+ }
+ }else{
+ next_token();
+ if(return_typ) error(156);
+ }
+ new=new_IC();
+ new->code=BRA;
+ new->typf=return_label;
+ add_IC(new);
+ cr();
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+}
+
+void expression_statement(void)
+/* bearbeitet expression_statement */
+{
+ np tree;
+ killsp();
+ if(ctok->type==SEMIC){
+ int oline=ctok->line;
+ next_token();
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ return;
+ }
+ if(tree=expression()){
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ if(tree->flags==POSTINC) tree->flags=PREINC;
+ if(tree->flags==POSTDEC) tree->flags=PREDEC;
+ if(type_expression(tree,0)){
+ if(DEBUG&2){
+ pre(stdout,tree);
+ printf("\n");
+ }
+ if(tree->sidefx){
+ gen_IC(tree,0,0);
+ if((tree->o.flags&(SCRATCH|REG))==REG) ierror(0);
+ if(tree&&(tree->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(tree->o.reg);
+ }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ error(153);
+ if(DEBUG&2) prd(stdout,tree->ntyp);
+ }
+ }
+ free_expression(tree);
+ }
+ killsp();
+ if(ctok->type==SEMIC) next_token(); else error(54);
+ cr();
+}
+void compound_statement(void)
+/* bearbeitet compound_statement (block) */
+{
+ killsp();
+ if(ctok->type==LBRA) next_token(); else error(157);
+ if(c99||ecpp){
+ killsp();
+ while(ctok->type!=RBRA){
+ if(declaration(0))
+ var_declaration();
+ else
+ statement();
+ killsp();
+ }
+ }else{
+ killsp();
+ while(declaration(0)){
+ var_declaration();
+ killsp();
+ }
+ while(ctok->type!=RBRA){
+ statement();
+ killsp();
+ }
+ }
+ next_token();/*killsp();*/
+}
+llist *add_label(char *identifier)
+/* Fuegt label in Liste */
+{
+ llist *new;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ new=mymalloc(LSIZE);
+ new->next=0;new->label=++label;new->flags=0;
+ new->identifier=add_identifier(identifier,strlen(identifier));
+ if(first_llist==0){
+ first_llist=last_llist=new;
+ }else{
+ last_llist->next=new;
+ last_llist=new;
+ }
+ return last_llist; /* return(new) sollte aequiv. sein */
+}
+llist *find_label(char *identifier)
+/* Sucht Label, gibt Zeiger auf llist oder 0 bei Fehler zurueck */
+{
+ llist *p;
+ p=first_llist;
+ while(p){
+ if(!strcmp(p->identifier,identifier)) return p;
+ p=p->next;
+ }
+ return 0;
+}
+void free_llist(llist *p)
+/* Gibt llist frei */
+
+{
+ llist *merk;
+ while(p){
+ merk=p->next;
+ if(!(p->flags&LABELDEFINED)) error(147,p->identifier);
+ if(!(p->flags&LABELUSED)&&!p->switch_count) error(148,p->identifier);
+ free(p);
+ p=merk;
+ }
+}
diff --git a/supp.c b/supp.c
new file mode 100644
index 0000000..fd10032
--- /dev/null
+++ b/supp.c
@@ -0,0 +1,2012 @@
+/* $VER: vbcc (supp.c) $Revision: 1.49 $ */
+
+#include "supp.h"
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+#ifndef HAVE_EXT_TYPES
+char *typname[]={"strange","char","short","int","long","long long",
+ "float","double","long double","void",
+ "pointer","array","struct","union","enum","function",
+ "bool","vector"};
+#endif
+
+char *storage_class_name[]={"strange","auto","register","static","extern","typedef"};
+
+char *ename[]={"strange","sequence","move","set+","set-","set*","set/","set%",
+ "set&","set^","set|","set<<","set>>","?:","lor","land","or",
+ "eor","and","eq","neq","lt","le","gt","ge","lsl",
+ "lsr","add","sub","mul","div","mod","negate",
+ "not","preinc","postinc","predec","postdec","neg",
+ "dref-pointer","address-of","cast","call","index",
+ "dref-struct-pointer","dref-struct","identifier","constant",
+ "string","member",
+ "convert","convert-short","convert-int","convert-long",
+ "convert-float","convert-double","convert-void","convert-pointer",
+ "convert-uchar","convert-ushort","convert-uint","convert-ulong",
+ "address-of-array","first-element-of-array","pmult",
+ "allocreg","freereg","pconstant","test","label","beq","bne",
+ "blt","bge","ble","bgt","bra","compare","push","pop",
+ "address-of-struct","add-int-to-pointer","sub-int-from-pointer",
+ "sub-pointer-from-pointer","push-reg","pop-reg","pop-args",
+ "save-regs","restore-regs","identifier-label","dc","align",
+ "colon","get-return","set-return","move-from-reg","move-to-reg",
+ "nop","bitfield"};
+
+char *empty="";
+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;
+
+union atyps gval;
+
+#ifndef DEBUG
+int DEBUG;
+#endif
+
+int label;
+
+int regs[MAXR+1],regused[MAXR+1],simple_scratch[MAXR+1];
+Var *regsv[MAXR+1];
+int goto_used;
+int ic_count;
+zmax max_offset;
+int function_calls,vlas;
+int coloring;
+int dmalloc;
+int disable;
+int multiple_ccs;
+int lastlabel,return_label;
+int only_inline;
+IC *err_ic;
+long maxoptpasses=30;
+long optflags;
+int optsize,optspeed,unroll_all,stack_check;
+int cross_module,final,no_emit;
+int debug_info;
+long inline_size=100;
+long inline_depth=1;
+long unroll_size=200;
+long clist_copy_stack=6;
+long clist_copy_static=6;
+long clist_copy_pointer=20;
+long inline_memcpy_sz=INLINEMEMCPY;
+int fp_assoc,noaliasopt,noitra;
+char *filename;
+IC *first_ic,*last_ic;
+int float_used;
+bvtype regs_modified[RSIZE/sizeof(bvtype)];
+/* Das haette ich gern woanders */
+Var *vl0,*vl1,*vl2,*vl3;
+int align_arguments=1;
+zmax stackalign;
+int misracheck,misraversion,misracomma,misratok;
+int pack_align;
+int short_push;
+int default_unsigned;
+Var *add_attr_haddecl;
+
+char *emit_buffer[EMIT_BUF_DEPTH];
+char *emit_p;
+int emit_f,emit_l;
+int no_inline_peephole;
+
+static int get_scalar_byte(int f,union atyps *v,zmax n, zuchar *out)
+/* Yields byte n of a constant */
+{
+ if(!zmleq(l2zm(0L),n)) ierror(0);
+ f&=NQ;
+ if(f>=CHAR&&f<=LLONG){
+ int j;
+ eval_const(v,f);
+ if(LITTLEENDIAN)
+ j=zm2l(n);
+ else
+ j=(int)sizetab[f]-(int)zm2l(n)-1;
+ while(j){
+ vumax=zumrshift(vumax,char_bit);
+ j--;
+ }
+ *out=zum2zuc(vumax);
+ return 1;
+ }else
+ return 0;
+}
+
+zumax get_clist_int(type *t, const_list *cl, zmax n, int sz,int *state)
+/* yields an integer of size sz from offset n */
+{
+ zuchar zuc;
+ zumax val = ZU0;
+
+ if(LITTLEENDIAN)
+ n=zmadd(n,l2zm((long)(sz-1)));
+
+ while(sz){
+ val=zumlshift(val,char_bit);
+ if(!get_clist_byte(t,cl,n,&zuc)) {*state=0;return ZU0;}
+ val=zumadd(val,zuc2zum(zuc));
+ sz--;
+ n=LITTLEENDIAN?zmsub(n,Z1):zmadd(n,Z1);
+ }
+ *state=1;
+ return val;
+}
+
+int get_clist_byte(type *t,const_list *cl, zmax n, zuchar *out)
+/* Yields byte n from a const list */
+{
+ if(!cl){
+ *out=zum2zuc(ul2zum(0UL));
+ return 1;
+ }
+
+ if(ISARRAY(t->flags)){
+ zmax i,j,x;
+ x=szof(t->next);
+ i=zmdiv(n,x);
+ while(1){
+ if(!cl) break;
+ if(zmleq(i,cl->idx)) break;
+ cl=cl->next;
+ }
+ if(!cl||!zmeqto(cl->idx,i)){
+ *out=zum2zuc(ul2zum(0UL));
+ return 1;
+ }
+ return get_clist_byte(t->next,cl->other,zmmod(n,x),out);
+ }
+ if(ISUNION(t->flags)){
+ int i=zm2l(cl->idx);
+ if(cl->tree) return 0;
+ return get_clist_byte((*t->exact->sl)[i].styp,cl->other,n,out);
+ }
+ if(ISSTRUCT(t->flags)){
+ zmax al;int fl;type *st;
+ int i,bfo,bfs;zmax sz;zumax bfval=ul2zum(0UL);
+
+ sz=l2zm(0L);
+ if(cl&&cl->tree){
+ /* initialized by another */
+ return 0;
+ }else{
+ for(i=0;i<t->exact->count&&cl;i++){
+ if(!cl->other){ierror(0);}
+ st=(*t->exact->sl)[i].styp;
+ al=(*t->exact->sl)[i].align;
+ if(!(*t->exact->sl)[i].identifier) ierror(0);
+ bfo=(*t->exact->sl)[i].bfoffset;
+ if(!zmeqto(zmmod(sz,al),l2zm(0L))){
+ sz=zmadd(sz,zmsub(al,zmmod(sz,al)));
+ if(!zmleq(sz,n)){
+ *out=zum2zuc(ul2zum(0L));
+ return 1;
+ }
+ }
+ if(bfo>=0){
+ /* bitfield */
+
+ if((*t->exact->sl)[i].identifier[0]){
+ bfs=(*t->exact->sl)[i].bfsize;
+ if(zmeqto(l2zm((long)i),cl->idx)){
+ eval_const(&cl->other->val,st->flags);
+ cl=cl->next;
+ }else{
+ vumax=ul2zum(0UL);
+ }
+ vumax=zumand(vumax,zumsub(zumlshift(ul2zum(1UL),ul2zum((unsigned long)bfs)),ul2zum(1UL)));
+ bfval=zumor(bfval,zumlshift(vumax,ul2zum((unsigned long)bflayout(bfo,bfs,st->flags))));
+ }
+ if(i+1>=t->exact->count||(*t->exact->sl)[i+1].bfoffset<=0||!cl){
+ /* last bitfield in integer */
+ gval.vumax=bfval;
+ eval_const(&gval,UNSIGNED|MAXINT);
+ insert_const(&gval,st->flags&NU);
+ bfval=ul2zum(0L);
+ sz=zmadd(sz,szof(st));
+ if(!zmleq(sz,n))
+ return get_scalar_byte(st->flags,&gval,zmsub(n,zmsub(sz,szof(st))),out);
+ }
+ }else{
+ sz=zmadd(sz,szof(st));
+ if(!zmleq(sz,n)){
+ if(zmeqto(l2zm((long)i),cl->idx)){
+ return get_clist_byte(st,cl->other,zmsub(n,zmsub(sz,szof(st))),out);
+ }else{
+ *out=zum2zuc(ul2zum(0UL));
+ return 1;
+ }
+ }
+ if(zmeqto(l2zm((long)i),cl->idx))
+ cl=cl->next;
+ }
+ }
+ }
+ *out=zum2zuc(ul2zum(0UL));
+ return 1;
+ }
+
+ if(zmeqto(cl->idx,l2zm(-1L)))
+ return 0;
+ else{
+ if(cl->tree)
+ return 0;
+ else
+ return get_scalar_byte(t->flags,&cl->val,n,out);
+
+ }
+ ierror(0);
+}
+
+type *new_typ(void)
+/* Erzeigt neuen (leeren) Typ. */
+{
+ type *new=mymalloc(TYPS);
+ new->flags=0;
+ new->next=0;
+ new->exact=0;
+ new->attr=0;
+ new->dsize=0;
+ new->reg=0;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+ return new;
+}
+
+type *clone_typ(type *old)
+/* Erzeugt Kopie eines Typs und liefert Zeiger auf Kopie. */
+{
+ type *new;
+ if(!old) return 0;
+ new=new_typ();
+ *new=*old;
+ if(old->attr){
+ new->attr=mymalloc(strlen(old->attr)+1);
+ strcpy(new->attr,old->attr);
+ }
+ if(new->next) new->next=clone_typ(new->next);
+ return new;
+}
+Var *new_var(void)
+{
+ Var *new=mymalloc(sizeof(*new));
+ new->clist=0;
+ new->vtyp=0;
+ new->storage_class=0;
+ new->reg=0;
+ new->vattr=0;
+ new->next=0;
+ new->flags=0;
+ new->fi=0;
+ new->nesting=0;
+ new->filename=0;
+ new->line=0;
+ new->dfilename=0;
+ new->dline=0;
+ new->description=0;
+ new->tunit=0;
+ new->offset=l2zm(0L);
+ new->identifier=0;
+#ifdef HAVE_TARGET_ATTRIBUTES
+ new->tattr=0;
+#endif
+#ifdef ALEX_REG
+ new->iRegCopyNr = -1;
+ new->iRegCopyNrHc12V = -1;
+#endif
+ return new;
+}
+
+IC *new_IC(void)
+{
+ IC *p=mymalloc(ICS);
+ p->change_cnt=0;
+ p->use_cnt=0;
+ p->call_cnt=0;
+ p->arg_cnt=0;
+ p->use_list=0;
+ p->change_list=0;
+ p->call_list=0;
+ p->arg_list=0;
+ p->line=0;
+ p->file=0;
+ p->flags=0;
+ p->q1.flags=p->q2.flags=p->z.flags=0;
+ p->q1.am=p->q2.am=p->z.am=0;
+ p->q1.val.vmax=p->q2.val.vmax=p->z.val.vmax=l2zm(0L);
+ p->savedsp=0;
+ p->typf=p->typf2=0;
+#ifdef ALEX_REG
+ p->iZWebIndex = -1;
+ p->iQ1WebIndex = -1;
+ p->iQ2WebIndex = -1;
+ p->pFlow = NULL;
+#endif /* GC_RALLOC */
+
+ return p;
+}
+/* (partially) clones an IC list */
+IC *clone_ic(IC *p)
+{
+ IC *new,*first,*last;
+ first=last=new=0;
+ while(p){
+ new=mymalloc(sizeof(*new));
+ *new=*p;
+ p->copy=new;
+
+ if(p->q1.am||p->q2.am||p->z.am) ierror(0);
+
+ if(new->code==CALL){
+ int i;
+ new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
+ for(i=0;i<new->arg_cnt;i++){
+ if(!p->arg_list[i])
+ ierror(0);
+ if(!p->arg_list[i]->copy)
+ ierror(0);
+ new->arg_list[i]=p->arg_list[i]->copy;
+ }
+ }
+ new->prev=last;
+ new->next=0;
+ if(!first) first=new;
+ if(last) last->next=new;
+ last=new;
+ p=p->next;
+ }
+ return first;
+}
+void free_IC(IC *p)
+/* Gibt IC-Liste inkl. Typen frei. */
+{
+ IC *merk;
+ if(DEBUG&1) printf("free_IC()\n");
+ while(p){
+ /*if(p->q1.am&&!p->q1.flags) ierror(0);
+ if(p->q2.am&&!p->q2.flags) ierror(0);
+ if(p->z.am&&!p->z.flags) ierror(0);*/
+
+ if(p->q1.am&&p->q1.am==p->q2.am)
+ ierror(0);
+
+ if(p->q1.am) free(p->q1.am);
+ if(p->q2.am) free(p->q2.am);
+ if(p->z.am) free(p->z.am);
+ if(p->code==CALL) free(p->arg_list);
+ merk=p->next;
+ free(p);
+ p=merk;
+ }
+}
+void move_IC(IC *after,IC *p)
+{
+ if(p->prev)
+ p->prev->next=p->next;
+ else
+ first_ic=p->next;
+ if(p->next)
+ p->next->prev=p->prev;
+ else
+ last_ic=p->prev;
+ insert_IC(after,p);
+}
+void remove_IC(IC *p)
+/* Entfernt IC p aus Liste. */
+{
+ if(p->prev) p->prev->next=p->next; else first_ic=p->next;
+ if(p->next) p->next->prev=p->prev; else last_ic=p->prev;
+ if(p->q1.am) free(p->q1.am);
+ if(p->q2.am) free(p->q2.am);
+ if(p->z.am) free(p->z.am);
+ free(p);
+}
+void freetyp(type *p)
+/* Gibt eine Typ-Liste frei, aber keine struct_declaration oder so. */
+{
+ int f;type *merk;
+ if(DEBUG&8){printf("freetyp: ");prd(stdout,p);printf("\n");}
+ while(p){
+ merk=p->next;
+ f=p->flags&NQ;
+ if(merk&&!ISARRAY(f)&&!ISPOINTER(f)&&!ISFUNC(f)&&!ISVECTOR(f))
+ ierror(0);
+ free(p->attr);
+ free(p);
+ p=merk;
+ }
+}
+
+#ifndef HAVE_TGT_FALIGN
+zmax falign(type *t)
+/* Liefert Alignment eines Typs. Funktioniert im Gegensatz zum */
+/* align[]-Array auch mit zusammengesetzten Typen. */
+{
+ int i,f; zmax al,alt;
+ f=t->flags&NQ;
+ if(ISVECTOR(f)) return szof(t);
+ al=align[f];
+ if(ISSCALAR(f)) return al;
+ if(ISARRAY(f)){
+ do{
+ t=t->next;
+ f=t->flags&NQ;
+ }while(ISARRAY(f)||ISVECTOR(f));
+ alt=falign(t);
+ if(zmleq(al,alt)) return alt; else return al;
+ }
+ if(ISUNION(f)||ISSTRUCT(f)){
+ if(!t->exact) ierror(0);
+ for(i=0;i<t->exact->count;i++){
+ alt=(*t->exact->sl)[i].align;
+ if(!zmleq(alt,al)) al=alt;
+ }
+ }
+ return al;
+}
+#endif
+
+/* check, whether t is a variable length array */
+int is_vlength(type *t)
+{
+ if(!ISARRAY(t->flags))
+ return 0;
+ if(t->dsize)
+ return 1;
+ else
+ return is_vlength(t->next);
+}
+
+/* calculate size of a variable length array */
+Var *vlength_szof(type *t)
+{
+ IC *new;type *nt;
+ if(!ISARRAY(t->flags))
+ ierror(0);
+ new=new_IC();
+ new->code=MULT;
+ new->typf=HAVE_INT_SIZET?(UNSIGNED|INT):(UNSIGNED|LONG);
+ if(t->dsize){
+ new->q1.flags=VAR;
+ new->q1.v=t->dsize;
+ new->q1.val.vmax=l2zm(0L);
+ }else{
+ new->q1.flags=KONST;
+#if HAVE_INT_SIZET
+ new->q1.val.vuint=zum2zui(zm2zum(t->size));
+#else
+ new->q1.val.vulong=zum2zul(zm2zum(t->size));
+#endif
+ }
+ new->z.flags=VAR;
+ nt=new_typ();
+ nt->flags=new->typf;
+ new->z.v=add_tmp_var(nt);
+ new->z.val.vmax=l2zm(0L);
+ if(is_vlength(t->next)){
+ new->q2.flags=VAR;
+ new->q2.v=vlength_szof(t->next);
+ new->q2.val.vmax=l2zm(0L);
+ }else{
+ new->q2.flags=KONST;
+#if HAVE_INT_SIZET
+ new->q2.val.vuint=zum2zui(zm2zum(szof(t->next)));
+#else
+ new->q2.val.vulong=zum2zul(zm2zum(szof(t->next)));
+#endif
+ }
+ add_IC(new);
+ return new->z.v;
+}
+
+/* return the type of a d-dim vector of base type x */
+int mkvec(int x,int d)
+{
+ int t=x&NQ,r;
+ if(d!=2&&d!=3&&d!=4&&d!=8&&d!=16) ierror(0);
+ switch(t){
+ case BOOL:
+ r=VECBOOL;break;
+ case CHAR:
+ r=VECCHAR;break;
+ case SHORT:
+ r=VECSHORT;break;
+ case INT:
+ r=VECINT;break;
+ case LONG:
+ r=VECLONG;break;
+ case FLOAT:
+ r=VECFLOAT;break;
+ default:
+ ierror(0);
+ }
+ return (r+d-1)|(x&~NQ);
+}
+
+/* return the base type of a vector */
+int VECTYPE(int x)
+{
+ int t=x&NQ,r=0;
+ if(t>=VECBOOL&&t<=VECBOOL+MAXVECDIM)
+ r=BOOL;
+ if(t>=VECCHAR&&t<=VECCHAR+MAXVECDIM)
+ r=CHAR;
+ if(t>=VECSHORT&&t<=VECSHORT+MAXVECDIM)
+ r=SHORT;
+ if(t>=VECINT&&t<=VECINT+MAXVECDIM)
+ r=INT;
+ if(t>=VECLONG&&t<=VECLONG+MAXVECDIM)
+ r=LONG;
+ if(t>=VECFLOAT&&t<=VECFLOAT+MAXVECDIM)
+ r=FLOAT;
+ if(!r) ierror(0);
+ return r|(x&~NQ);
+}
+
+
+#ifndef HAVE_TGT_SZOF
+zmax szof(type *t)
+/* Liefert die benoetigte Groesse eines Typs in Bytes. */
+{
+ int i=t->flags&NQ,j;zmax size,m;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+
+ if(ISSCALAR(i)) return sizetab[i];
+ if(ISARRAY(i)){
+ if(is_vlength(t))
+ return sizetab[POINTER_TYPE(t->next)];
+ size=zmmult((t->size),szof(t->next));
+ m=align[ARRAY];
+ return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */
+ }
+ if(ISVECTOR(i)){
+ zmax dim=VECDIM(i);
+ if(zmeqto(dim,l2zm(3L))) dim=l2zm(4L);
+ return zmmult(dim,sizetab[VECTYPE(i)&NQ]);
+ }
+ if(ISUNION(i)){
+ for(j=0,size=l2zm(0L);j<t->exact->count;j++){
+ m=szof((*t->exact->sl)[j].styp);
+ if(zmeqto(m,l2zm(0L))) return l2zm(0L);
+ if(!zmleq(m,size)) size=m;
+ }
+ m=falign(t);
+ return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */
+ }
+ if(ISSTRUCT(i)){
+ size=l2zm(0L);
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ for(j=0;j<t->exact->count;j++){
+ type *h=(*t->exact->sl)[j].styp;
+ if((*t->exact->sl)[j].bfoffset<=0){
+ int n;size_t al;
+ al=(*t->exact->sl)[j].align;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+ if(zmeqto(al,l2zm(0L))) {prd(stdout,h);ierror(0);}
+ m=szof(h);
+ /* find the largest type in a bitfield */
+ for(n=j+1;n<t->exact->count&&(*t->exact->sl)[n].bfoffset>0;n++){
+ size_t tmp=szof((*t->exact->sl)[n].styp);
+ if(zmleq(m,tmp))
+ m=tmp;
+ }
+ size=zmmult(zmdiv(zmadd(size,zmsub(al,l2zm(1L))),al),al);
+ /*if(zmeqto(m,l2zm(0L))) return l2zm(0L);*/
+ size=zmadd(size,m);
+ }
+ }
+ m=falign(t);
+ return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */
+ }
+ return sizetab[i];
+}
+zmax struct_offset(struct_declaration *sd,const char *identifier)
+{
+ int i=0,intbitfield=-1;zmax offset=l2zm(0),al;
+ while(i<sd->count&&strcmp((*sd->sl)[i].identifier,identifier)){
+ if((*sd->sl)[i].bfoffset>=0){
+ if(i+1<sd->count&&(*sd->sl)[i+1].bfoffset>0){
+ i++;
+ continue;
+ }
+ }
+ al=(*sd->sl)[i].align;
+ offset=zmmult(zmdiv(zmadd(offset,zmsub(al,l2zm(1L))),al),al);
+ offset=zmadd(offset,szof((*sd->sl)[i].styp));
+ i++;
+ }
+ if(i>=sd->count) {error(23,identifier);return l2zm(0L);}
+ al=(*sd->sl)[i].align;
+ offset=zmmult(zmdiv(zmadd(offset,zmsub(al,l2zm(1L))),al),al);
+ return offset;
+}
+#ifdef HAVE_ECPP
+/* 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
+#endif
+
+#ifndef HAVE_TGT_PRINTVAL
+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)){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;
+ 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);}
+}
+#endif
+
+void pric2(FILE *f,IC *p)
+/* Gibt ein IC aus. */
+{
+ if(p->code>NOP) ierror(0);
+ if(p->next&&p->next->prev!=p) ierror(0);
+ if(p->code>=LABEL&&p->code<=BRA){
+ if(p->code==LABEL)
+ fprintf(f,"L%d",p->typf);
+ else{
+ fprintf(f,"\t%s L%d",ename[p->code],p->typf);
+ if(p->q1.flags){ fprintf(f,",");probj(f,&p->q1,0);}
+ }
+ if(p->code==LABEL&&(p->flags&LOOP_COND_TRUE)) fprintf(f," (while-loop)");
+ if(p->code==BRA&&(p->flags&LOOP_COND_TRUE)) fprintf(f," (to-loop-test)");
+ }else{
+ fprintf(f,"\t%s ",ename[p->code]);
+ if(p->typf&VOLATILE) fprintf(f,"volatile ");
+ if(p->typf&CONST) fprintf(f,"const ");
+ if(p->typf&UNSIGNED) fprintf(f,"unsigned ");
+ if(p->typf){
+ if(ISVECTOR(p->typf))
+ fprintf(f,"%s%d ",typname[VECTYPE(p->typf)&NQ],VECDIM(p->typf));
+ else
+ fprintf(f,"%s ",typname[p->typf&NQ]);
+ }
+ probj(f,&p->q1,q1typ(p));
+ if(p->q2.flags){fprintf(f,",");probj(f,&p->q2,q2typ(p));}
+ if(p->z.flags){fprintf(f,"->");probj(f,&p->z,ztyp(p));}
+ if(p->code==ASSIGN||p->code==PUSH||p->code==POP||p->code==CALL)
+ fprintf(f," size=%ld",zm2l(p->q2.val.vmax));
+ if((p->code==SAVEREGS||p->code==RESTOREREGS)&&p->q1.reg)
+ fprintf(f," except %s",regnames[p->q1.reg]);
+ if(p->code==CONVERT)
+ fprintf(f," from %s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]);
+ if(p->code==LSHIFT||p->code==RSHIFT)
+ fprintf(f," shift-type %s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]);
+ if(p->code==ADDI2P||p->code==SUBIFP||p->code==SUBPFP||p->code==ADDRESS)
+ fprintf(f," ptype=%s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]);
+ if(p->code==ASSIGN||p->code==PUSH)
+ if(p->typf2) fprintf(f," align=%d\n",p->typf2);
+ }
+ if(p->code==CALL){
+ fprintf(f," =>");
+ if(p->call_cnt==0)
+ fprintf(f,"(unknown)");
+ else{
+ int i;
+ for(i=0;i<p->call_cnt;i++)
+ fprintf(f," %s",p->call_list[i].v->identifier);
+ }
+
+ }
+ if(p->flags&EFF_IC) fprintf(f," (eff_ic)");
+ fprintf(f,"\n");
+#if 0
+ if(p->code==CALL){
+ int i;
+ //fprintf(f,"c=%p\n",p);
+ for(i=0;i<p->arg_cnt;i++){
+ //fprintf(f,"%p!\n",p->arg_list[i]);
+ fprintf(f,"%02d:",i);
+ pric2(f,p->arg_list[i]);
+ }
+ }
+#endif
+}
+void pric(FILE *f,IC *p)
+/* Gibt IC-Liste auf dem Bildschirm aus. */
+{
+ while(p){
+ pric2(f,p);
+/* if(p->q1.am||p->q2.am||p->z.am) ierror(0);*/
+ p=p->next;
+ }
+}
+void printzm(FILE *f,zmax x)
+/* Konvertiert zmax nach ASCII. */
+/* Basiert noch einigermassen auf */
+/* Zweierkomplementdarstellung (d.h. -MIN>MAX). */
+/* Ausserdem muss max(abs(max))<=max(unsigned max). */
+{
+ zmax zm;zumax zum;
+ zm=l2zm(0L);
+ if(zmleq(x,zm)&&!zmeqto(x,zm)){
+ fprintf(f,"-");zm=zum2zm(t_max(MAXINT));
+ if(zmleq(x,zmsub(l2zm(0L),zm))&&!zmeqto(x,zmsub(l2zm(0L),zm))){
+ /* aufpassen, da -x evtl. >LONG_MAX */
+ zum=t_max(MAXINT);
+ x=zmadd(x,zm);
+ }else
+ zum=ul2zum(0UL);
+ x=zmsub(l2zm(0L),x);
+ vumax=zm2zum(x);
+ zum=zumadd(zum,vumax);
+ }else
+ zum=zm2zum(x);
+ printzum(f,zum);
+}
+void printzum(FILE *f,zumax x)
+/* Konvertiert zumax nach ASCII. */
+{
+ zumax zum;unsigned long l;
+ zum=ul2zum(10UL);
+ if(!zumeqto(zumdiv(x,zum),ul2zum(0UL))) printzum(f,zumdiv(x,zum));
+ zum=zummod(x,zum);l=zum2ul(zum);
+ fprintf(f,"%c",(int)(l+'0'));
+}
+
+void printzld(FILE *f,zldouble x)
+/* Konvertiert zdouble nach ASCII, noch nicht fertig. */
+{
+ fprintf(f,"fp-constant");
+}
+void emitzm(FILE *f,zmax x)
+/* Konvertiert zmax nach ASCII. */
+/* Basiert noch einigermassen auf */
+/* Zweierkomplementdarstellung (d.h. -MIN>MAX). */
+/* Ausserdem muss max(abs(max))<=max(unsigned max). */
+{
+ zmax zm;zumax zum;
+ zm=l2zm(0L);
+ if(zmleq(x,zm)&&!zmeqto(x,zm)){
+ emit(f,"-");zm=zum2zm(t_max(MAXINT));
+ if(zmleq(x,zmsub(l2zm(0L),zm))&&!zmeqto(x,zmsub(l2zm(0L),zm))){
+ /* aufpassen, da -x evtl. >LONG_MAX */
+ zum=t_max(MAXINT);
+ x=zmadd(x,zm);
+ }else
+ zum=ul2zum(0UL);
+ x=zmsub(l2zm(0L),x);
+ vumax=zm2zum(x);
+ zum=zumadd(zum,vumax);
+ }else
+ zum=zm2zum(x);
+ emitzum(f,zum);
+}
+void emitzum(FILE *f,zumax x)
+/* Konvertiert zumax nach ASCII. */
+{
+ zumax zum;unsigned long l;
+ zum=ul2zum(10UL);
+ if(!zumeqto(zumdiv(x,zum),ul2zum(0UL))) emitzum(f,zumdiv(x,zum));
+ zum=zummod(x,zum);l=zum2ul(zum);
+ emit(f,"%c",(int)(l+'0'));
+}
+
+void emitzld(FILE *f,zldouble x)
+/* Konvertiert zdouble nach ASCII, noch nicht fertig. */
+{
+ emit(f,"fp-constant");
+}
+
+typedef struct memblock {struct memblock *next;void *p;} memblock;
+static memblock *first_mb;
+
+static void add_mb(void *p)
+{
+ memblock *mb_second=first_mb;
+ memblock *mb=malloc(sizeof(*mb));
+ if(!mb){
+ error(12);
+ raus();
+ }
+ first_mb=mb;
+ mb->next=mb_second;
+ mb->p=p;
+}
+
+static void remove_mb(void *p)
+{
+ memblock *mb_prev=0;
+ memblock *mb=first_mb;
+ while(mb){
+ if(mb->p==p){
+ if(mb_prev==0) first_mb=mb->next;
+ else mb_prev->next=mb->next;
+ (free)(mb);
+ return;
+ }
+ mb_prev=mb;
+ mb=mb->next;
+ }
+ ierror(0);
+}
+
+void *mymalloc(size_t size)
+/* Allocate memory and quit on failure. */
+{
+ void *p;
+ if(dmalloc)
+ size+=sizeof(size);
+ else if(size==0)
+ /* Not very nice, but simplest way to avoid a failure when size==0. */
+ size=1;
+ if(!(p=malloc(size))){
+ error(12);
+ raus();
+ }
+ if(DEBUG&32768){
+ printf("malloc %p (s=%lu)\n",p,(unsigned long)size);
+ fflush(stdout);
+ }
+ if(DEBUG&65536) add_mb(p);
+ if(dmalloc){
+ *(size_t *)p=size;
+ p=((char *)p)+sizeof(size);
+ memset(p,0xaa,size-sizeof(size));
+ }
+ return p;
+}
+
+void *myrealloc(void *p,size_t size)
+/* Reallocate memory and quit on failure. */
+{
+ void *new;
+ if(!p) return mymalloc(size);
+ if(dmalloc){
+ size+=sizeof(size);
+ new=realloc(((char *)p)-sizeof(size),size);
+ if(!new){
+ error(12);
+ raus();
+ }
+ if(DEBUG&32768){
+ printf("realloc %p to %p (s=%lu)\n",p,new,(unsigned long)size);
+ fflush(stdout);
+ }
+ if(DEBUG&65536){
+ remove_mb(p);
+ add_mb(new);
+ }
+ *(size_t *)new=size;
+ new=((char *)new)+sizeof(size);
+ return new;
+ }else{
+ new=realloc(p,size);
+ if(!new){
+ error(12);
+ raus();
+ }
+ if(DEBUG&32768){
+ printf("realloc %p to %p (s=%lu)\n",p,new,(unsigned long)size);
+ fflush(stdout);
+ }
+ if(DEBUG&65536){
+ remove_mb(p);
+ add_mb(new);
+ }
+ return new;
+ }
+}
+
+void myfree(void *p)
+{
+ if(p&&dmalloc){
+ p=((char*)p)-sizeof(size_t);
+ memset(p,0xbb,*(size_t *)(p));
+ }
+ if(DEBUG&32768){
+ printf("free %p\n",p);
+ fflush(stdout);
+ }
+ if((DEBUG&65536)&&p) remove_mb(p);
+ (free)(p); /* supp.h has #define free(x) myfree(x) */
+}
+
+char *mystrdup(char *p)
+{
+ char *new=mymalloc(strlen(p)+1);
+ strcpy(new,p);
+ return new;
+}
+
+/* Testet, ob zwei objs dieselben Register belegen. */
+int collides(obj *x,obj *y)
+{
+ int x1,x2,y1,y2;
+ if(!(x->flags®)||!(y->flags®)) return 0;
+ if(reg_pair(x->reg,&rp)){
+ x1=rp.r1;x2=rp.r2;
+ }else{
+ x1=x->reg;x2=-1;
+ }
+ if(reg_pair(y->reg,&rp)){
+ y1=rp.r1;y2=rp.r2;
+ }else{
+ y1=y->reg;y2=-2;
+ }
+ if(x1==y1||x1==y2||x2==y1||x2==y2)
+ return 1;
+ else
+ return 0;
+}
+
+/* Versucht, ein IC so zu drehen, dass q2 und z kein gemeinsames */
+/* Register belegen. Liefert Null, wenn das nicht moeglich ist. */
+int switch_IC(IC *p)
+{
+ int c;
+ obj o;
+ if(!collides(&p->q2,&p->z)) return 1;
+ c=p->code;
+ if((c<OR||c>AND)&&c!=ADD&&c!=MULT&&c!=ADDI2P) return 0;
+ if(c==ADDI2P&&must_convert(q1typ(p),q2typ(p),0)) return 0;
+ if(collides(&p->q1,&p->z)) return 0;
+ o=p->q2;p->q2=p->q1;p->q1=o;
+ return 1;
+}
+
+void probj(FILE *f,obj *p,int t)
+/* Gibt Objekt auf Bildschirm aus. */
+{
+ if(p->am){ fprintf(f,"[tgt-addressing-mode]");return;}
+ if(p->flags&DREFOBJ){
+ fprintf(f,"([");
+ if(p->dtyp&CONST) fprintf(f,"const ");
+ if(p->dtyp&VOLATILE) fprintf(f,"volatile ");
+ if(p->dtyp&PVOLATILE) fprintf(f,"pvolatile ");
+ fprintf(f,"%s]",typname[p->dtyp&NQ]);
+ }
+ if(p->flags&VARADR) fprintf(f,"#");
+ if(p->flags&VAR) {
+ if(!(p->flags®))
+ printval(f,&p->val,MAXINT);
+ if(p->flags®){
+ fprintf(f,"%s",regnames[p->reg]);
+ }else if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
+ fprintf(f,"+%ld(FP)", zm2l(p->v->offset));
+ }else{
+ if(p->v->storage_class==STATIC){
+ fprintf(f,"+L%ld",zm2l(p->v->offset));
+ }else{
+ fprintf(f,"+_%s",p->v->identifier);
+ }
+ }
+ if(*p->v->identifier)
+ fprintf(f,"(%s)",p->v->identifier);
+ else if(p->v->description)
+ fprintf(f,"(%s)",p->v->description);
+ else
+ fprintf(f,"(%p)",(void *)p->v);
+ if(p->v->reg) fprintf(f,":%s",regnames[abs(p->v->reg)]);
+ }
+ if((p->flags®)&&!(p->flags&VAR)) fprintf(f,"%s",regnames[p->reg]);
+ if(p->flags&KONST){
+ fprintf(f,"#");
+ if(p->flags&DREFOBJ)
+ printval(f,&p->val,p->dtyp&NU);
+ else
+ printval(f,&p->val,t&NU);
+ }
+ if(p->flags&SCRATCH) fprintf(f,"[S]");
+ if(p->flags&DREFOBJ) fprintf(f,")");
+}
+void prl(FILE *o,struct_declaration *p)
+/* Gibt eine struct_declaration auf dem Bildschirm aus. */
+{
+ int i;
+ static int recurse=2;
+ int merk_recurse=recurse;
+ --recurse;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ for(i=0;i<p->count;i++){
+ fprintf(o," %d.:",i);
+ if(recurse>=0){
+ if((*p->sl)[i].identifier)fprintf(o," ident: %s; ",(*p->sl)[i].identifier);
+ prd(o,(*p->sl)[i].styp);
+ }
+ }
+ recurse=merk_recurse;
+}
+void prd(FILE *o,type *p)
+/* Gibt einen Typ auf dem Bildschirm aus. */
+{
+ int f;
+ if(!p) {fprintf(o,"empty type ");return;}
+ f=p->flags;
+/* fprintf(o,"(Sizeof=%ld,flags=%d)",zl2l(szof(p)),f);*/
+/* if(type_uncomplete(p)) {fprintf(o,"incomplete ");}*/
+ if(f&CONST) {fprintf(o,"const ");f&=~CONST;}
+ if(f&STRINGCONST) {fprintf(o,"string-const ");f&=~STRINGCONST;}
+ if(f&VOLATILE) {fprintf(o,"volatile ");f&=~VOLATILE;}
+ if(f&UNSIGNED) {fprintf(o,"unsigned ");f&=~UNSIGNED;}
+ if(p->attr) fprintf(o,"attr(%s) ",p->attr);
+ if(p->reg) fprintf(o,"reg(%s) ",regnames[p->reg]);
+ if(ISFUNC(f)){
+ fprintf(o,"%s with parameters (",typname[f&NQ]);
+ prl(o,p->exact);
+ fprintf(o,") returning ");prd(o,p->next);return;
+ }
+ if(ISSTRUCT(f)||ISUNION(f)){
+ fprintf(o,"%s with components {",typname[f&NQ]);
+ prl(o,p->exact); fprintf(o,"} ");
+ return;
+ }
+ if(ISPOINTER(f)) {fprintf(o,"%s to ",typname[f&NQ]);prd(o,p->next);return;}
+ if(ISARRAY(f)) {fprintf(o,"%s [size %ld] of ",typname[f&NQ],zm2l(p->size));prd(o,p->next);return;}
+ if(ISVECTOR(f)) {fprintf(o,"vector [size %ld] of %s",zm2l(p->size),typname[VECTYPE(f)&NQ]);return;}
+
+ fprintf(o,"%s",typname[f&NQ]);
+}
+void print_var(FILE *o,Var *p)
+/* Gibt eine Variable aus. */
+{
+ if(p->identifier&&*p->identifier){
+ fprintf(o, "ident: %s: ", p->identifier);
+ }
+ prd(o, p->vtyp);
+}
+
+/* returns the first base Type in an compound type */
+int get_first_base_type(type *t)
+{
+ if (!t) return 0;
+ if (ISARRAY(t->flags)) {
+ return get_first_base_type(t->next);
+ } else if ((ISSTRUCT(t->flags)) || (ISUNION(t->flags))) {
+ return get_first_base_type((*t->exact->sl)[0].styp);
+ } else return t->flags;
+}
+
+
+#ifndef HAVE_EXT_TYPES
+
+void insert_const(union atyps *p,int t)
+/* Traegt Konstante in entprechendes Feld ein. */
+{
+ 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==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(!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);
+}
+#endif
+
+function_info *new_fi(void)
+/* Belegt neue function_info-Struktur und initialisiert sie. */
+{
+ function_info *new;
+ new=mymalloc(sizeof(*new));
+ new->first_ic=new->last_ic=new->opt_ic=0;
+ new->vars=0;
+ new->statics=0;
+ new->inline_asm=0;
+ new->flags=0;
+ new->call_cnt=new->use_cnt=new->change_cnt=0;
+ new->call_list=new->use_list=new->change_list=0;
+ memset(new->regs_modified,0,sizeof(new->regs_modified));
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ new->stack1=ul2zum(0UL);
+ new->stack2=ul2zum(0UL);
+ new->inline_size=-1;
+ new->inline_depth=0;
+ return new;
+}
+void free_fi(function_info *p)
+/* Gibt ein function_info mit Inhalt frei. */
+{
+ if(p->first_ic) free_IC(p->first_ic);
+ if(p->opt_ic) free_IC(p->opt_ic);
+ if(p->vars) free_var(p->vars);
+ /* do not free statics */
+ free(p->call_list);
+ free(p->use_list);
+ free(p->change_list);
+ free(p->inline_asm);
+ free(p);
+}
+
+void print_fi(FILE *f,function_info *p)
+/* Gibt function_info aus. */
+{
+ int i;
+ fprintf(f,"function_info:\n");
+ if(p->first_ic){
+ IC *ic=p->first_ic;
+ fprintf(f," inline_code:\n");
+ pric2(f,ic);
+ while(ic!=p->last_ic){
+ ic=ic->next;
+ pric2(f,ic);
+ }
+ }
+ if(p->inline_asm)
+ fprintf(f," inline_asm:\n%s\n",p->inline_asm);
+ if(p->flags&ALL_CALLS)
+ fprintf(f," all calls have been evaluated\n");
+ if(p->flags&ALL_USES)
+ fprintf(f," all uses have been evaluated\n");
+ if(p->flags&ALL_MODS)
+ fprintf(f," all changes have been evaluated\n");
+ if(p->flags&ALL_REGS){
+ fprintf(f," all reg-changes have been evaluated\n");
+ for(i=1;i<=MAXR;i++)
+ if(BTST(p->regs_modified,i)) fprintf(f," %s\n",regnames[i]);
+ }
+ fprintf(f," call_list:\n");print_varlist(f,p->call_list,p->call_cnt);
+ fprintf(f," use_list:\n");print_varlist(f,p->use_list,p->use_cnt);
+ fprintf(f," change_list:\n");print_varlist(f,p->change_list,p->change_cnt);
+ if(p->flags&ALL_STACK){
+ fprintf(f,"stack1: ");printzum(f,p->stack1);fprintf(f,"\n");
+ fprintf(f,"stack2: ");printzum(f,p->stack2);fprintf(f,"\n");
+ }
+ if(p->flags&NEVER_RETURNS)
+ fprintf(f," never returns\n");
+ if(p->flags&ALWAYS_RETURNS)
+ fprintf(f," always returns\n");
+ if(p->flags&NOSIDEFX)
+ fprintf(f," no side effects\n");
+}
+
+void print_varlist(FILE *f,varlist *p,int n)
+{
+ int i;
+ char *s;
+ for(i=0;i<n;i++){
+ if(p[i].v) s=p[i].v->identifier; else s="<unknown>";
+ fprintf(f," %s(%p), flags=%d\n",s,(void*)p[i].v,p[i].flags);
+ }
+}
+
+int is_const(type *t)
+/* tested, ob ein Typ konstant (und damit evtl. in der Code-Section) ist */
+{
+ 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;
+}
+
+/* is object volatile? */
+int is_volatile_obj(obj *o)
+{
+ if(o->flags&DREFOBJ){
+ if(o->dtyp&(VOLATILE|PVOLATILE)){
+ return 1;
+ }
+ if((o->flags&VAR)&&ISPOINTER(o->v->vtyp->flags)&&(o->v->vtyp->next->flags&VOLATILE)){
+ return 1;
+ }
+ }
+ if(o->flags&VAR){
+ return o->v->vtyp->flags&VOLATILE;
+ }else{
+ return 0;
+ }
+}
+
+/* is IC volatile? */
+int is_volatile_ic(IC *p)
+{
+ if(p->q1.flags){
+ if(is_volatile_obj(&p->q1)||(q1typ(p)&VOLATILE)) return 1;
+ }
+ if(p->q2.flags){
+ if(is_volatile_obj(&p->q2)||(q2typ(p)&VOLATILE)) return 1;
+ }
+ if(p->z.flags){
+ if(is_volatile_obj(&p->z)||(ztyp(p)&VOLATILE)) return 1;
+ }
+ return 0;
+}
+
+/* removes last asm-line from emit-buffer */
+void remove_asm(void)
+{
+ emit_l--;
+ if(emit_l<0) emit_l=EMIT_BUF_DEPTH-1;
+}
+
+/* flush the asm-output buffer */
+void emit_flush(FILE *f)
+{
+ if(!f||no_emit) return;
+ while(emit_f!=emit_l){
+ fputs(emit_buffer[emit_f],f);
+ emit_f++;
+ if(emit_f>=EMIT_BUF_DEPTH) emit_f=0;
+ }
+ emit_l=emit_f=0;
+ emit_p=emit_buffer[0];
+}
+
+/* emit inline-asm, depending on no_inline_peephole, feed it through
+ asm_peephole() or flush the buffer and print it directly to the file */
+void emit_inline_asm(FILE *f,char *p)
+{
+ if(!f||no_emit) return;
+ if(no_inline_peephole){
+ emit_flush(f);
+ fprintf(f,"%s\n",p);
+ }else{
+ while(*p){
+ emit(f,"%c",*p++);
+ }
+ emit(f,"\n");
+ }
+}
+
+/* print output; this is only to be used for assembly output! */
+void emit(FILE *f,const char *fmt,...)
+{
+ static char tmp[EMIT_BUF_LEN];
+ char *p;
+ va_list vl;
+ if(!f||no_emit) return;
+ va_start(vl,fmt);
+ vsprintf(tmp,fmt,vl);
+ p=tmp;
+ while(*p){
+ *emit_p++=*p++;
+ if(p[-1]=='\n'){
+ *emit_p=0;
+#if HAVE_TARGET_PEEPHOLE
+ while(emit_peephole());
+#endif
+ emit_l++;
+ if(emit_l>=EMIT_BUF_DEPTH) emit_l=0;
+ emit_p=emit_buffer[emit_l];
+ if(emit_l==emit_f){
+ /* FIXME: error check */
+ fputs(emit_buffer[emit_f],f);
+ emit_f++;
+ if(emit_f>=EMIT_BUF_DEPTH) emit_f=0;
+ }
+ }
+ }
+ *emit_p=0;
+}
+
+void emit_char(FILE *f,int c)
+{
+ static char tmp[2];
+ tmp[0]=c;
+ emit(f,tmp);
+}
+
+/* detect whether the following code resembles a switch-case-statement */
+/* will return the longest sequence which has at least min_density */
+case_table *calc_case_table(IC *p,double min_density)
+{
+ static case_table ct;
+ obj *o,*ccr;
+ static union atyps *vals;
+ union atyps min,max;
+ zumax diff;
+ static int *labels,cur_size;
+ double cur_density;
+ int t,j,num;
+ if(p->code!=COMPARE||!(p->q2.flags&KONST))
+ return 0;
+ o=&p->q1;t=p->typf;
+ if(!ISINT(t)||(t&VOLATILE)) return 0;
+ num=0;
+ ct.num=0;
+ if(t&UNSIGNED){
+ max.vumax=t_min(UNSIGNED|MAXINT);
+ min.vumax=t_max(UNSIGNED|MAXINT);
+ }else{
+ max.vmax=t_min(MAXINT);
+ min.vmax=t_max(MAXINT);
+ }
+ while(p&&p->code==COMPARE&&(p->q2.flags&KONST)&&p->typf==t&&objs_equal(o,&p->q1,t)){
+ zumax zum;zmax zm;
+ if(multiple_ccs) ccr=&p->z;
+ if(num>=cur_size){
+ cur_size+=64;
+ labels=myrealloc(labels,cur_size*sizeof(*labels));
+ vals=myrealloc(vals,cur_size*sizeof(*vals));
+ }
+ for(j=0;j<num;j++){
+ if(!compare_const(&vals[j],&p->q2.val,t)){
+ return 0; /* FIXME? Could simply ignore? */
+ }
+ }
+ vals[num]=p->q2.val;
+ p=p->next;
+ while(p&&(p->code==NOP||p->code==ALLOCREG||p->code==FREEREG)) p=p->next;
+ if(p->code!=BEQ||(multiple_ccs&&!objs_equal(ccr,&p->q1,0))) break;
+ labels[num]=p->typf;
+ p=p->next;
+ while(p&&(p->code==NOP||p->code==ALLOCREG||p->code==FREEREG)) p=p->next;
+ eval_const(&vals[num],t);
+ num++;
+ if(t&UNSIGNED){
+ if(zumleq(vumax,min.vumax))
+ insert_const(&min,UNSIGNED|MAXINT);
+ if(zumleq(max.vumax,vumax))
+ insert_const(&max,UNSIGNED|MAXINT);
+ cur_density=num/(1+zld2d(zum2zld(zumsub(max.vumax,min.vumax))));
+ if(cur_density>=min_density){
+ ct.num=num;
+ ct.next_ic=p;
+ ct.min=min;
+ ct.max=max;
+ ct.diff=zumsub(max.vumax,min.vumax);
+ ct.density=cur_density;
+ }
+ }else{
+ if(zmleq(vmax,min.vmax))
+ insert_const(&min,MAXINT);
+ if(zmleq(max.vmax,vmax))
+ insert_const(&max,MAXINT);
+ cur_density=num/zld2d(zum2zld((1+zumsub(zm2zum(max.vmax),zm2zum(min.vmax)))));
+ if(cur_density>=min_density){
+ ct.num=num;
+ ct.next_ic=p;
+ ct.min=min;
+ ct.max=max;
+ ct.diff=zumsub(zm2zum(max.vmax),zm2zum(min.vmax));
+ ct.density=cur_density;
+ }
+ }
+ }
+ ct.vals=vals;
+ ct.labels=labels;
+ ct.typf=t;
+ return &ct;
+}
+
+/* emit a list of jump-table entries */
+void emit_jump_table(FILE *f,case_table *ct,char *da,char *labprefix,int defl)
+{
+ unsigned long l,e;
+ int i;
+ zmax zm;zumax zum;
+ if(ct->typf&UNSIGNED){
+ zum=ct->min.vumax;
+ zm=zum2zm(zum);
+ }else{
+ zm=ct->min.vmax;
+ zum=zm2zum(zm);
+ }
+ e=zum2ul(ct->diff);
+ for(l=0;l<=e;l++){
+ emit(f,"%s",da);
+ for(i=0;i<ct->num;i++){
+ eval_const(&ct->vals[i],ct->typf);
+ if(zmeqto(vmax,zm)&&zumeqto(vumax,zum)){
+ emit(f,"%s%d\n",labprefix,ct->labels[i]);
+ break;
+ }
+ }
+ if(i>=ct->num)
+ emit(f,"%s%d\n",labprefix,defl);
+ zm=zmadd(zm,l2zm(1L));
+ zum=zumadd(zum,ul2zum(1UL));
+ }
+}
+/* display warnings if specified stack-size cannot be guaranteed */
+void static_stack_check(Var *v)
+{
+ /*FIXME*/
+}
+
+#ifdef HAVE_REGPARMS
+/* return the offset of the first variable-argument-macro to the
+ beginning of the argument-area (i.e. the space occupied by
+ normal arguments on the stack */
+zmax va_offset(Var *v)
+{
+ int i;
+ zmax offset=l2zm(0L);
+ static type rp={0};
+ treg_handle rh=empty_reg_handle;
+ if((v->vtyp->next->flags&NQ)!=VOID&&!freturn(v->vtyp->next)){
+ rp.next=v->vtyp->next;
+ rp.flags=POINTER_TYPE(v->vtyp->next);
+ if(!reg_parm(&rh,&rp,0,v->vtyp)){
+ ierror(0);
+ }
+ }
+ for(i=0;i<v->vtyp->exact->count;i++){
+#if 0
+ if((*v->vtyp->exact->sl)[i].reg!=0)
+ continue;
+#endif
+ if(((*v->vtyp->exact->sl)[i].styp->flags&NQ)==VOID)
+ ierror(0);
+ if(reg_parm(&rh,(*v->vtyp->exact->sl)[i].styp,0,v->vtyp)!=0)
+ continue;
+ offset=zmadd(offset,szof((*v->vtyp->exact->sl)[i].styp));
+ offset=zmmult(zmdiv(zmadd(offset,zmsub(stackalign,l2zm(1L))),stackalign),stackalign);
+ }
+ return offset;
+}
+#endif
+
+/* We provide an own qsort to get reproducable results. */
+void vqsort (void *base,size_t nmemb,size_t size,int (*compar)(const void *,const void *))
+{ char *base2=(char *)base;
+ char tmp;
+ size_t i,a,b,c;
+ while(nmemb>1)
+ { a=0;
+ b=nmemb-1;
+ c=(a+b)/2; /* Middle element */
+ for(;;)
+ { while((*compar)(&base2[size*c],&base2[size*a])>0)
+ a++; /* Look for one >= middle */
+ while((*compar)(&base2[size*c],&base2[size*b])<0)
+ b--; /* Look for one <= middle */
+ if(a>=b)
+ break; /* We found no pair */
+ for(i=0;i<size;i++) /* swap them */
+ { tmp=base2[size*a+i];
+ base2[size*a+i]=base2[size*b+i];
+ base2[size*b+i]=tmp; }
+ if(c==a) /* Keep track of middle element */
+ c=b;
+ else if(c==b)
+ c=a;
+ a++; /* These two are already sorted */
+ b--;
+ } /* a points to first element of right intervall now (b to last of left) */
+ b++;
+ if(b<nmemb-b) /* do recursion on smaller intervall and iteration on larger one */
+ { vqsort(base2,b,size,compar);
+ base2=&base2[size*b];
+ nmemb=nmemb-b;
+ }
+ else
+ { vqsort(&base2[size*b],nmemb-b,size,compar);
+ nmemb=b; }
+ }
+ return;
+}
+
+/* calculates registers used by this call IC
+ returns 0 if not possible */
+int calc_regs(IC *p,int showwarnings)
+{
+ int i;
+ if(p->call_cnt){
+ for(i=0;i<p->call_cnt;i++){
+ if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_REGS)){
+ bvunite(regs_modified,p->call_list[i].v->fi->regs_modified,RSIZE);
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }else{
+ int r;
+ for(r=1;r<=MAXR;r++) if(regscratch[r]) BSET(regs_modified,r);
+ 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_REGS)){
+ error(318,p->call_list[i].v->identifier);
+ p->call_list[i].v->fi->flags|=WARNED_REGS;
+ }
+ return 0;
+ }
+ }
+ return 1;
+ }
+ err_ic=p;if(showwarnings) error(320);
+ return 0;
+}
+
+
+
+#ifndef HAVE_TARGET_BFLAYOUT
+int bflayout(int bfoffset,int bfsize,int t)
+{
+ if(BIGENDIAN)
+ return (int)zm2l(zmmult(sizetab[t&NQ],char_bit))-bfoffset-bfsize;
+ else
+ return bfoffset;
+}
+#endif
+
+long get_pof2(zumax x)
+/* Yields log2(x)+1 oder 0. */
+{
+ zumax p;int ln=1,max=(int)zm2l(zmmult(sizetab[LLONG],char_bit));
+ p=ul2zum(1L);
+ while(ln<=max&&zumleq(p,x)){
+ if(zumeqto(x,p)) return ln;
+ ln++;p=zumadd(p,p);
+ }
+ return 0;
+}
+
+/* check if type is a varargs function */
+int is_varargs(type *t)
+{
+ int c;
+ if(t->exact&&(c=t->exact->count)!=0&&(*t->exact->sl)[c-1].styp->flags!=VOID)
+ return 1;
+ else
+ return 0;
+}
+
+/* add string to type- oder variable-aatribute */
+void add_attr(char **attr,char *new)
+{
+ int ln,lo;
+ if(!new) return;
+ if(*attr&&strstr(*attr,new)) return;
+ if(add_attr_haddecl&&(!*attr||!strstr(*attr,new))) error(371,add_attr_haddecl->identifier,new);
+ ln=strlen(new);
+ if(*attr){
+ lo=strlen(*attr);
+ *attr=myrealloc(*attr,lo+ln+2);
+ }else{
+ lo=0;
+ *attr=mymalloc(ln+2);
+ }
+ (*attr)[lo]=';';
+ strcpy(*attr+lo+1,new);
+}
+
+
+hashtable *new_hashtable(size_t size)
+{
+ hashtable *new = mymalloc(sizeof(*new));
+
+ new->size = size;
+ new->collisions = 0;
+ new->entries = mymalloc(size*sizeof(*new->entries));
+ memset(new->entries,0,size*sizeof(*new->entries));
+ return new;
+}
+
+size_t hashcode(char *name)
+{
+ size_t h = 5381;
+ int c;
+
+ while (c = (unsigned char)*name++)
+ h = ((h << 5) + h) + c;
+ return h;
+}
+
+/* add to hashtable; name must be unique */
+void add_hashentry(hashtable *ht,char *name,hashdata data)
+{
+ size_t i=(hashcode(name)%ht->size);
+ hashentry *new=mymalloc(sizeof(*new));
+ new->name=name;
+ new->data=data;
+ if(DEBUG&1){
+ if(ht->entries[i])
+ ht->collisions++;
+ }
+ new->next=ht->entries[i];
+ ht->entries[i]=new;
+}
+
+/* finds unique entry in hashtable */
+hashdata find_name(hashtable *ht,char *name)
+{
+ size_t i=hashcode(name)%ht->size;
+ hashentry *p;
+ for(p=ht->entries[i];p;p=p->next){
+ if(!strcmp(name,p->name)){
+ return p->data;
+ }else
+ ht->collisions++;
+ }
+ return 0;
+}
+
+#ifndef CHARBACK
+unsigned char CHARBACK(unsigned char x)
+{
+ static unsigned char tab[256],init=0;
+ if(!init){
+ int i,j;
+ for(i=0;i<256;i++)
+ for(j=0;j<256;j++)
+ if(tab[j]==0&&CHARCONV(i)==j){
+ tab[j&255]=i;
+ break;
+ }
+ init=1;
+ }
+ return tab[x&255];
+}
+
+void STRBACK(unsigned char *p)
+{
+ while(p&&*p){
+ *p=CHARBACK(*p);
+ p++;
+ }
+}
+#endif
+
+int objs_equal(obj *o1,obj *o2,int t)
+/* Vergleicht die beiden Objekte; liefert 1, wenn sie gleich sind, sonst 0 */
+{
+ int i1,i2;
+ i1=o1->flags&~SCRATCH;i2=o2->flags&~SCRATCH;
+ if(i1!=i2) return 0;
+ if(i1&DREFOBJ){
+ if(o1->dtyp!=o2->dtyp) return 0;
+ }
+ if(i1&KONST) return(!compare_const(&o1->val,&o2->val,t));
+ if(i1&VAR){
+ if(o1->v!=o2->v) return 0;
+ if(!zmeqto(o1->val.vmax,o2->val.vmax)) return 0;
+ }
+ return 1;
+}
+
+
+#ifdef HAVE_MISRA
+/* 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/supp.h b/supp.h
new file mode 100644
index 0000000..7313fce
--- /dev/null
+++ b/supp.h
@@ -0,0 +1,880 @@
+/* $VER: vbcc (supp.h) $Revision: 1.58 $ */
+
+
+#ifndef SUPP_H
+#define SUPP_H 1
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <ctype.h>
+/* typenames */
+#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 BOOL 16
+#define MAXINT 17 /* should not be accessible to application */
+#define MAX_TYPE MAXINT
+#define MAXVECDIM 16
+#define VECBOOL (MAXINT+1)
+#define VECCHAR (VECBOOL+MAXVECDIM)
+#define VECSHORT (VECCHAR+MAXVECDIM)
+#define VECINT (VECSHORT+MAXVECDIM)
+#define VECLONG (VECINT+MAXVECDIM)
+#define VECFLOAT (VECLONG+MAXVECDIM)
+#define VECLAST (VECFLOAT+MAXVECDIM)
+#define NQ 255 /* f&NQ gives type without any qualifiers */
+#define NU 511 /* f&NU gives type without any qualifiers but UNSIGNED */
+#define q1typ(p) ((p->code==ADDI2P||p->code==SUBIFP||p->code==CONVERT||p->code==SUBPFP)?p->typf2:p->typf)
+#define q2typ(p) ((p->code==SUBPFP||p->code==LSHIFT||p->code==RSHIFT)?p->typf2:p->typf)
+#define ztyp(p) ((p->code==ADDI2P||p->code==SUBIFP||p->code==ADDRESS)?p->typf2:p->typf)
+#define iclabel(p) (p->typf)
+#define opsize(p) (p->q2.val.vmax)
+#define pushsize(p) (p->z.val.vmax)
+#define pushedargsize(p) (p->q2.val.vmax)
+#define isstatic(x) ((x)==STATIC)
+#define isextern(x) ((x)==EXTERN)
+#define isauto(x) ((x)==AUTO||(x)==REGISTER)
+/* operations on bit-vectors */
+typedef unsigned int bvtype;
+#define BVBITS (sizeof(bvtype)*CHAR_BIT)
+#define BVSIZE(x) ((((x)+BVBITS-1)/BVBITS)*sizeof(bvtype))
+#define BSET(array,bit) (array)[(bit)/BVBITS]|=1<<((bit)%BVBITS)
+#define BCLR(array,bit) (array)[(bit)/BVBITS]&=~(1<<((bit)%BVBITS))
+#define BTST(array,bit) ((array)[(bit)/BVBITS]&(1<<((bit)%BVBITS)))
+/* type-qualifiers */
+#define UNSIGNED (NQ+1)
+#define CONST (UNSIGNED<<1)
+#define VOLATILE (CONST<<1)
+#define RESTRICT (VOLATILE<<1)
+#define UNCOMPLETE (RESTRICT<<1)
+#define STRINGCONST (UNCOMPLETE<<1)
+#define BOOLEAN (STRINGCONST<<1)
+#define SIGNED_CHARACTER (BOOLEAN<<1)
+#define PVOLATILE (SIGNED_CHARACTER<<1)
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+#define t_min(x) (((x)&UNSIGNED)?l2zm(0L):t_min[(x)&NQ])
+#define t_max(x) (((x)&UNSIGNED)?tu_max[(x)&NQ]:t_max[(x)&NQ])
+/* macro for internal errors */
+#define ierror(a) error(-1,(a),__LINE__,FILE_)
+/* macros for target errors */
+#define twarning(x) error(323,x);
+#define terror(x) error(324,x);
+/* this header is provided by the code generator */
+#include "machine.h"
+#define Z0 l2zm(0L)
+#define Z1 l2zm(1L)
+#define ZU0 ul2zum(0UL)
+#define ZU1 ul2zum(1UL)
+
+#ifndef HAVE_EXT_TYPES
+typedef zllong zmax;
+typedef zullong zumax;
+#endif
+#ifndef ISPOINTER
+#define ISPOINTER(x) ((x&NQ)==POINTER)
+#endif
+#ifndef ISINT
+#define ISINT(x) ((x&NQ)>=CHAR&&(x&NQ)<=LLONG)
+#endif
+#ifndef ISFLOAT
+#define ISFLOAT(x) ((x&NQ)>=FLOAT&&(x&NQ)<=LDOUBLE)
+#endif
+#ifndef ISFUNC
+#define ISFUNC(x) ((x&NQ)==FUNKT)
+#endif
+#ifndef ISSTRUCT
+#define ISSTRUCT(x) ((x&NQ)==STRUCT)
+#endif
+#ifndef ISUNION
+#define ISUNION(x) ((x&NQ)==UNION)
+#endif
+#ifndef ISARRAY
+#define ISARRAY(x) ((x&NQ)==ARRAY)
+#endif
+#ifndef ISVECTOR
+#define ISVECTOR(x) ((x&NQ)>=VECBOOL&&(x&NQ)<=VECLAST)
+#endif
+#ifndef VECDIM
+#define VECDIM(x) ((((x&NQ)-VECBOOL)&15)+1)
+#endif
+#ifndef ISSCALAR
+#define ISSCALAR(x) ((x&NQ)>=CHAR&&(x&NQ)<=POINTER)
+#endif
+#ifndef ISARITH
+#define ISARITH(x) (ISINT(x)||ISFLOAT(x))
+#endif
+#ifndef POINTER_TYPE
+#define POINTER_TYPE(x) POINTER
+#endif
+#ifndef MAXINT
+#define MAXINT LLONG
+#endif
+#ifndef HAVE_INT_SIZET
+#define HAVE_INT_SIZET 0
+#endif
+#ifndef PTRDIFF_T
+#define PTRDIFF_T(x) INT
+#endif
+#ifndef MAXADDI2P
+#define MAXADDI2P LLONG
+#endif
+#ifndef MINADDUI2P
+#define MINADDUI2P (MINADDI2P|UNSIGNED)
+#endif
+#ifndef MAXADDUI2P
+#define MAXADDUI2P (MAXADDI2P|UNSIGNED)
+#endif
+#ifndef BESTCOPYT
+#define BESTCOPYT INT
+#endif
+#define RSIZE BVSIZE(MAXR+1)
+#define ALL_CALLS 1
+#define ALL_REGS 2
+#define ALL_USES 4
+#define ALL_MODS 8
+#define ALL_STACK 16
+#define ALWAYS_RETURNS 32
+#define NEVER_RETURNS 64
+#define NOSIDEFX 128
+#define WARNED_STACK 256
+#define WARNED_REGS 512
+#define USES_VLA 1024
+#define NO_INLINE 2048
+#define FULL_INLINE 4096
+typedef struct reg_handle treg_handle;
+typedef struct tunit{
+ struct Var *statics;
+ struct tunit *next;
+} tunit;
+/* additional information for functions; used by the optimizer */
+typedef struct function_info{
+ struct IC *first_ic; /* inline copy of function starts here */
+ struct IC *last_ic; /* " " " ends here */
+ struct IC *opt_ic; /* code after optimizing */
+ struct Var *vars; /* pointer to list of vars of that function */
+ struct Var *statics; /* static variables of translation-unit */
+ char *inline_asm; /* pointer to code for inline assembler */
+ unsigned long flags; /* misc flags, see above */
+ /* functions called, variables used and changed */
+ int call_cnt,use_cnt,change_cnt;
+ struct varlist *call_list;
+ struct varlist *use_list;
+ struct varlist *change_list;
+ zmax max_offset;
+ /* registers used and modified by that function */
+ bvtype regs_modified[RSIZE/sizeof(bvtype)];
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+#endif
+ zumax stack1;
+ zumax stack2;
+ long inline_size; /* size after inlining/optimizing for cross-module */
+ int inline_depth; /* minimum depth for cross-module-inlining */
+} function_info;
+typedef int typfl;
+#if PVOLATILE >= INT_MAX
+#error "need host with larger int size"
+#endif
+/* struct for types. */
+typedef struct Typ{
+ typfl flags; /* see above */
+ struct Typ *next;
+ struct struct_declaration *exact; /* used for STRUCT/UNION/FUNKT */
+ zmax size; /* used for ARRAY */
+ struct Var *dsize; /* used for variable-length arrays */
+ char *attr;
+ int reg;
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+} type;
+#define TYPS sizeof(type)
+#ifndef HAVE_EXT_TYPES
+typedef 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;
+} atyps;
+#endif
+/* This struct represents objects in the intermediate code. */
+typedef struct obj{
+ int flags; /* see below */
+ int reg; /* number of reg if flags® */
+ int dtyp; /* type of pointer for DREFOBJ */
+ struct Var *v;
+ struct AddressingMode *am;
+ union atyps val;
+} obj;
+/* Available flags in struct obj. */
+ /* KONST muss immer am kleinsten sein, um beim Swappen */
+ /* fuer available_expressions und Konstanten nach */
+ /* rechts nicht in eine Endlosschleife zu kommen. */
+#define KONST 1 /* The object is a constant. Its value is stored in */
+ /* val. */
+#define VAR 2 /* The object is a variable (stored in v). */
+#define SCRATCH 8 /* The object is a temporary. */
+#define STACK 16 /* obsolete */
+#define DREFOBJ 32 /* The object must be dereferenced. */
+#define REG 64 /* The object is contained in a hardware register. */
+#define VARADR 128 /* The object is the address of a static variable. */
+#define DONTREGISTERIZE 256 /* Do not put this object into a register. */
+#define VKONST 512 /* Variable containing a constant (for reg-alloc). */
+typedef struct Var{
+ int storage_class; /* see below */
+ int reg; /* Var is assigned to this hard-reg */
+ int priority; /* Priority to be used in simple_regs() */
+ long flags; /* see below */
+ char *identifier; /* name of the variable */
+ int nesting; /* can be freely used by the frontend */
+ int index; /* used by the optimizer */
+ int inr; /* counter for num_vars */
+ zmax offset; /* offset relative to the stack frame */
+ int line; /* line number of first declaration */
+ char *filename; /* filename of first declaration */
+ int dline; /* line number of definition */
+ char *dfilename; /* filename of definition */
+ type *vtyp; /* type of the variable */
+ struct const_list *clist; /* initialized? */
+ struct Var *next; /* pointer to next variable */
+ struct function_info *fi; /* used by the optimizer */
+ struct Var *inline_copy; /* used for function-inlining */
+ struct tunit *tunit; /* translation unit the variable belongs to */
+ char *vattr; /* extended variable attributes */
+ char *description; /* description of variable meaning */
+ struct obj cobj; /* used for register-allocation of constants */
+ int ctyp; /* ----------------- " ----------------- */
+#ifdef HAVE_TARGET_ATTRIBUTES
+ unsigned long tattr; /* target-specific attributes */
+#endif
+#ifdef ALEX_REG
+ int iRegCopyNr;
+ int iRegCopyNrHc12V;
+#endif
+} Var;
+/* available storage-classes */
+#define AUTO 1 /* var is allocated on the stack */
+#define REGISTER 2 /* basically the same as AUTO (C-only) */
+#define STATIC 3 /* var is static but has no external linkage */
+#define EXTERN 4 /* var is static and has external linkage */
+#define TYPEDEF 5 /* C-only */
+/* available flags in struct Var */
+#define USEDASSOURCE 1 /* the var has been read */
+#define USEDASDEST 2 /* the var has been written */
+#define DEFINED 4 /* the var has been defined (i.e. storage will
+ be allocated in the current file) */
+#define USEDASADR 8 /* the address of the var has been taken */
+#define GENERATED 16 /* code for static vars has been generated */
+#define CONVPARAMETER 32
+#define TENTATIVE 64 /* C-only */
+#define USEDBEFORE 128 /* used by the optimizer */
+#define INLINEV 256 /* " " */
+#define PRINTFLIKE 512 /* C-only */
+#define SCANFLIKE 1024 /* C-only */
+#define NOTTYPESAFE 2048 /* used by the optimizer */
+#define DNOTTYPESAFE 4096 /* " " */
+#define REGPARM 8192 /* the var is a register parameter */
+#define DBLPUSH 16384 /* parameter is also on the stack */
+#define NOTINTU 32768 /* variable not (yet) defined in this translation-unit */
+#define REFERENCED 65536 /* variable referenced */
+#define STATICAUTO 131072 /* auto variable converted to static */
+#define INLINEFUNC (STATICAUTO*2)
+#define INLINEEXT (INLINEFUNC*2)
+#define BUILTIN (INLINEEXT*2)
+#define NEEDS (BUILTIN*2)
+
+/* C-only */
+typedef struct struct_list{
+ char *identifier; /* name of the struct/union-tag */
+ type *styp; /* type of the member/parameter */
+ zmax align; /* alignment of struct-member */
+ int bfoffset; /* bitfield-offset */
+ int bfsize; /* bitfield-size */
+ int storage_class; /* storage-class of function-parameter */
+ int reg; /* register to pass function-parameter */
+#ifdef HAVE_ECPP
+/* removed */
+#endif
+} struct_list;
+
+#define SLSIZE 32 /* realloc struct_lists in those steps */
+/* These structs are used to describe members of STRUCT/UNION or */
+/* parameters of FUNKT. Some of the entries in struct_list are not */
+/* relevant for both alternatives. */
+typedef struct struct_declaration{
+ int count; /* number of members/parameters */
+ int label; /* used for debug output */
+ int typ;
+ struct tunit *tunit;
+ struct struct_declaration *next;
+ struct struct_list (*sl)[];
+ char *identifier;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+} struct_declaration;
+
+/* The quads in the intermediate code. */
+typedef struct IC{
+ struct IC *prev; /* pointer to the next IC */
+ struct IC *next; /* pointer to the previous IC */
+ int code; /* see below */
+ int typf; /* usually type of the operands, see interface.doc */
+ int typf2; /* used for CONVERT,ADDI2P,SUBIFP,SUBPFP */
+ int defindex; /* used by optimizer */
+ int expindex;
+ int copyindex;
+ int change_cnt;
+ int use_cnt;
+ int call_cnt;
+ int line; /* corresponding line in source file (or 0) */
+ struct varlist *change_list; /* used by optimizer */
+ struct varlist *use_list;
+ struct varlist *call_list;
+ struct obj q1; /* source 1 */
+ struct obj q2; /* source 2 */
+ struct obj z; /* target */
+ char *file; /* filename of the source file */
+ int arg_cnt;
+ struct IC **arg_list; /* pointers to function argument ICs (only for code==CALL) */
+ struct IC *copy; /* for copying/inlining */
+ type *ityp;
+ long flags;
+ struct Var *savedsp; /* only for branch instructions and vlas */
+#ifdef HAVE_EXT_IC
+ struct ext_ic ext;
+#endif
+#ifdef ALEX_REG
+ int iZWebIndex; /* web for z in case z is a pointer and its value is defed*/
+ int iQ1WebIndex; /* web for argument q1 */
+ int iQ2WebIndex; /* web for argument q2 */
+ void *pFlow; /* flowgraph reverse lookup */
+#endif
+} IC;
+#define ICS sizeof(struct IC)
+/* flags for ICs */
+#define LOOP_COND_TRUE 1 /* loop condition is true at first iteration */
+#define EFF_IC 2 /* do not transform IC with doubtful optimizations */
+#define ORDERED_PUSH_COPY 4 /* mark a copy of an ordered push */
+
+/* Available codes for struct IC. See interface.doc. */
+#define KOMMA 1
+#define ASSIGN 2
+#define ASSIGNOP 3
+
+#if 0
+/* obsolete */
+#define ASSIGNADD 3
+#define ASSIGNSUB 4
+#define ASSIGNMULT 5
+#define ASSIGNDIV 6
+#define ASSIGNMOD 7
+#define ASSIGNAND 8
+#define ASSIGNXOR 9
+#define ASSIGNOR 10
+#define ASSIGNLSHIFT 11
+#define ASSIGNRSHIFT 12
+#endif
+
+#define COND 13
+#define LOR 14
+#define LAND 15
+#define OR 16
+#define XOR 17
+#define AND 18
+#define EQUAL 19
+#define INEQUAL 20
+#define LESS 21
+#define LESSEQ 22
+#define GREATER 23
+#define GREATEREQ 24
+#define LSHIFT 25
+#define RSHIFT 26
+#define ADD 27
+#define SUB 28
+#define MULT 29
+#define DIV 30
+#define MOD 31
+#define NEGATION 32
+#define KOMPLEMENT 33
+#define PREINC 34
+#define POSTINC 35
+#define PREDEC 36
+#define POSTDEC 37
+#define MINUS 38
+#define CONTENT 39
+#define ADDRESS 40
+#define CAST 41
+#define CALL 42
+#define INDEX 43
+#define DPSTRUCT 44
+#define DSTRUCT 45
+#define IDENTIFIER 46
+#define CEXPR 47
+#define STRING 48
+#define MEMBER 49
+#define CONVERT 50
+#if 0
+#define CONVCHAR 50
+#define CONVSHORT 51
+#define CONVINT 52
+#define CONVLONG 53
+#define CONVFLOAT 54
+#define CONVDOUBLE 55
+#define CONVVOID 56
+#define CONVPOINTER 57
+#define CONVUCHAR 58
+#define CONVUSHORT 59
+#define CONVUINT 60
+#define CONVULONG 61
+#endif
+#define ADDRESSA 62
+#define FIRSTELEMENT 63
+#define PMULT 64
+#define ALLOCREG 65
+#define FREEREG 66
+#define PCEXPR 67
+#define TEST 68
+#define LABEL 69
+#define BEQ 70
+#define BNE 71
+#define BLT 72
+#define BGE 73
+#define BLE 74
+#define BGT 75
+#define BRA 76
+#define COMPARE 77
+#define PUSH 78
+#define POP 79
+#define ADDRESSS 80
+#define ADDI2P 81
+#define SUBIFP 82
+#define SUBPFP 83
+#define PUSHREG 84
+#define POPREG 85
+#define POPARGS 86
+#define SAVEREGS 87
+#define RESTOREREGS 88
+#define ILABEL 89
+#define DC 90
+#define ALIGN 91
+#define COLON 92
+#define GETRETURN 93
+#define SETRETURN 94
+#define MOVEFROMREG 95
+#define MOVETOREG 96
+#define NOP 97
+#define BITFIELD 98
+#define LITERAL 99
+#define REINTERPRET 100
+extern char *typname[];
+extern zmax sizetab[];
+extern char *storage_class_name[];
+extern char *ename[];
+extern int align_arguments; /* arguments correctly aligned on stack or
+ just stackalign? */
+extern zmax align[],maxalign,stackalign;
+/* an empty string */
+extern char *empty;
+extern zchar vchar; extern zuchar vuchar;
+extern zshort vshort; extern zushort vushort;
+extern zint vint; extern zuint vuint;
+extern zlong vlong; extern zulong vulong;
+extern zllong vllong; extern zullong vullong;
+extern zmax vmax; extern zumax vumax;
+extern zfloat vfloat; extern zdouble vdouble;
+extern zldouble vldouble;
+extern union atyps gval;
+#ifndef DEBUG
+extern int DEBUG;
+#endif
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+/* used by the optimizer */
+/* for lists in ICs flags may be DREFOBJ to mark dereferences */
+/* for lists in function infos flags is the type of access */
+typedef struct varlist{
+ struct Var *v;
+ int flags;
+} varlist;
+#define VLS sizeof(struct varlist)
+extern struct IC *first_ic,*last_ic;
+#define REGSA_NEVER 1
+#define REGSA_TEMPS 2
+extern int regs[MAXR+1],regsa[MAXR+1],regused[MAXR+1],simple_scratch[MAXR+1];
+extern int sregsa[MAXR+1];
+extern int reg_prio[MAXR+1],regscratch[MAXR+1];
+extern zmax regsize[MAXR+1];
+extern type *regtype[MAXR+1];
+extern struct Var *regsv[MAXR+1];
+extern char *regnames[];
+extern bvtype regs_modified[RSIZE/sizeof(bvtype)];
+extern int optspeed,optsize,unroll_all,stack_check;
+extern int cross_module,final,no_emit;
+extern int debug_info;
+extern int label,return_label;
+/* The structures used for available options of the code generator. */
+union ppi {char *p;long l;void (*f)(char *);};
+#define USEDFLAG 1
+#define STRINGFLAG 2
+#define VALFLAG 4
+#define FUNCFLAG 8
+extern int g_flags[MAXGF];
+extern char *g_flags_name[MAXGF];
+extern union ppi g_flags_val[MAXGF];
+extern zmax max_offset;
+extern int function_calls,vlas;
+extern int coloring;
+extern int dmalloc;
+extern int sec_per_obj;
+extern int disable;
+extern int misracheck,misraversion,misracomma,misratok;
+extern int pack_align;
+extern int short_push;
+extern int static_cse,dref_cse;
+extern int no_eff_ics,early_eff_ics;
+extern int force_statics,prefer_statics;
+extern int range_opt;
+extern int default_unsigned;
+extern Var *add_attr_haddecl;
+
+/* Das haette ich gern woanders */
+extern struct struct_declaration *add_sd(struct struct_declaration *,int);
+typedef struct node{
+ int flags,lvalue,sidefx;
+ int bfs,bfo;
+ type *ntyp;
+ struct node *left;
+ struct node *right;
+ struct argument_list *alist;
+ char *identifier;
+ struct const_list *cl;
+ struct Var *dsize;
+ union atyps val;
+ struct obj o;
+} node;
+typedef node *np;
+#define NODES sizeof(struct node)
+typedef struct const_list{
+ union atyps val;
+ np tree;
+ zmax idx;
+ struct const_list *other,*next;
+} const_list;
+#define CLS sizeof(struct const_list)
+typedef struct case_table{
+ int num,typf;
+ struct IC *next_ic;
+ double density;
+ union atyps *vals;
+ int *labels;
+ union atyps min,max;
+ zumax diff;
+} case_table;
+extern zmax t_min[];
+extern zumax t_max[];
+extern zumax tu_max[];
+extern zmax char_bit;
+extern char cg_copyright[];
+#ifdef HAVE_TARGET_ATTRIBUTES
+extern char *g_attr_name[];
+#endif
+extern char **target_macros;
+extern int goto_used;
+extern int ic_count;
+extern int only_inline;
+extern int multiple_ccs;
+extern int float_used;
+extern IC *err_ic;
+extern long maxoptpasses,optflags,inline_size,unroll_size,inline_depth;
+extern long clist_copy_stack;
+extern long clist_copy_static;
+extern long clist_copy_pointer;
+extern long inline_memcpy_sz;
+extern int noaliasopt,fp_assoc,noitra;
+extern Var *vl0,*vl1,*vl2,*vl3;
+extern char *filename;
+extern char *emit_buffer[EMIT_BUF_DEPTH];
+extern char *emit_p;
+extern int emit_f,emit_l;
+extern int no_inline_peephole;
+extern int ecpp;
+/* functions which must be provided by the frontend */
+extern void add_IC(IC *);
+extern void error(int,...);
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+extern Var *add_tmp_var(type *);
+extern void free_var(Var *);
+extern void raus(void);
+/* functions provided by supp.c */
+#define printtype prd
+#define printobj probj
+#define printic pric2
+#define printiclist pric
+extern void free_IC(IC *);
+extern void insert_IC(IC *,IC *);
+extern void move_IC(IC *,IC *);
+extern void pric(FILE *,IC *);
+extern void pric2(FILE *,IC *);
+extern void probj(FILE *,obj *,int);
+extern void emit(FILE *,const char *,...);
+extern void emit_char(FILE *,int);
+void emit_flush(FILE *);
+void remove_asm(void);
+#if HAVE_TARGET_PEEPHOLE
+extern int emit_peephole(void);
+#endif
+extern void emit_remove(void);
+extern void emit_inline_asm(FILE *,char *);
+extern void emitzm(FILE *,zmax);
+extern void emitzum(FILE *,zumax);
+extern void emitzld(FILE *,zldouble);
+extern void emitval(FILE *,union atyps *,int);
+extern void printzm(FILE *,zmax);
+extern void printzum(FILE *,zumax);
+extern void printzld(FILE *,zldouble);
+extern void printval(FILE *,union atyps *,int);
+extern void insert_const(union atyps *,int);
+extern void prd(FILE *,type *);
+extern void print_var(FILE *,Var *);
+extern void freetyp(type *);
+extern type *new_typ(void);
+extern type *clone_typ(type *);
+#ifdef HAVE_EXT_TYPES
+extern void conv_typ(type *);
+#endif
+extern int VECTYPE(int);
+extern int mkvec(int,int);
+extern zmax szof(type *);
+extern int is_vlength(type *);
+extern Var *vlength_szof(type *);
+extern zmax struct_offset(struct_declaration *,const char *);
+extern zmax falign(type *);
+int get_first_base_type(type *);
+extern int objs_equal(obj *,obj *,int);
+extern void eval_const(union atyps *,int);
+extern int get_clist_byte(type *,const_list *, zmax, zuchar *);
+extern zumax get_clist_int(type *, const_list *, zmax, int, int *);
+extern function_info *new_fi(void);
+extern void free_fi(function_info *);
+extern void print_fi(FILE *,function_info *);
+extern void static_stack_check(Var *);
+#ifdef HAVE_REGPARMS
+extern zmax va_offset(Var *);
+#endif
+extern void print_varlist(FILE *f,varlist *,int);
+extern void add_attr(char **,char *);
+extern int switch_IC(IC *);
+extern int collides(obj *,obj *);
+extern int is_const(type *);
+extern int is_volatile_obj(obj *);
+extern int is_volatile_ic(IC *);
+extern case_table *calc_case_table(IC *,double);
+int calc_regs(IC *,int);
+Var *declare_builtin(char *name,int ztyp,int q1typ,int q1reg,int q2typ,int q2reg,int nosidefx,char *asm);
+extern void emit_jump_table(FILE *,case_table *,char *,char *,int);
+extern void optimize(long, Var *);
+int bvcmp(bvtype *dest,bvtype *src,size_t len);
+int bvdointersect(bvtype *,bvtype *,size_t len);
+void bvunite(bvtype *dest,bvtype *src,size_t len);
+void bvintersect(bvtype *dest,bvtype *src,size_t len);
+void bvdiff(bvtype *dest,bvtype *src,size_t len);
+void vqsort (void *,size_t,size_t,int (*)(const void *,const void *));
+#define bvcopy(dest,src,len) memcpy(dest,src,len)
+#define bvclear(dest,len) memset(dest,0,len)
+#define bvsetall(dest,len) memset(dest,-1,len)
+extern void remove_IC(IC *);
+extern IC *clone_ic(IC *);
+extern IC *new_IC(void);
+extern Var *new_var(void);
+extern void insert_bitfield(obj *,obj *,obj *,int,int,int,int);
+extern void *mymalloc(size_t);
+extern void *myrealloc(void *,size_t);
+extern void myfree(void *p);
+#define free(x) myfree(x)
+extern char *mystrdup(char *);
+extern void simple_regs(void);
+extern int bflayout(int,int,int);
+/* functions provided by the code generator */
+extern int regok(int,int,int);
+typedef struct rpair {int r1,r2;} rpair;
+int reg_pair(int,rpair *);
+extern rpair rp;
+extern int freturn(type *);
+#define ffreturn(x) ((x)->reg?(x)->reg:freturn(x))
+extern void gen_code(FILE *,IC *,Var *,zmax);
+extern int init_cg(void);
+extern void cleanup_cg(FILE *);
+extern void init_db(FILE *);
+void cleanup_db(FILE *);
+extern int dangerous_IC(IC *);
+extern void gen_dc(FILE *,int,const_list *);
+extern void gen_ds(FILE *,zmax,type *);
+extern void gen_var_head(FILE *,Var *);
+extern void gen_align(FILE *,zmax);
+extern int shortcut(int, int);
+extern int must_convert(int,int,int);
+long get_pof2(zumax);
+int is_varargs(type *);
+
+typedef void *hashdata;
+
+typedef struct hashentry {
+ char *name;
+ hashdata data;
+ struct hashentry *next;
+} hashentry;
+
+typedef struct hashtable {
+ hashentry **entries;
+ size_t size;
+ int collisions;
+} hashtable;
+
+hashtable *new_hashtable(size_t);
+size_t hashcode(char *);
+void add_hashentry(hashtable *,char *,hashdata);
+hashdata find_name(hashtable *,char *);
+
+#ifdef HAVE_TARGET_PRAGMAS
+extern int handle_pragma(const char *);
+#endif
+#ifdef HAVE_LIBCALLS
+extern char *use_libcall(int code,int t1,int t2);
+#ifndef LIBCALL_CMPTYPE
+#define LIBCALL_CMPTYPE INT
+#endif
+#endif
+#ifdef HAVE_TARGET_VARHOOK_PRE
+extern void add_var_hook_pre(const char *,type *,int,const_list *);
+#endif
+#ifdef HAVE_TARGET_VARHOOK_POST
+extern void add_var_hook_post(Var *);
+#endif
+extern int cost_savings(IC *,int,obj *);
+/* additional declarations for targets which pass arguments in */
+/* registers by default. */
+#ifdef HAVE_REGPARMS
+extern treg_handle empty_reg_handle;
+/* last parameter is function type or return type or pointer to function type */
+extern int reg_parm(treg_handle *, type *,int,type *);
+#endif
+#ifdef HAVE_TARGET_EFF_IC
+extern void mark_eff_ics(void);
+#else
+#define mark_eff_ics()
+#endif
+#ifndef JUMP_TABLE_DENSITY
+#define JUMP_TABLE_DENSITY 1
+#endif
+#ifndef JUMP_TABLE_LENGTH
+#define JUMP_TABLE_LENGTH 1000
+#endif
+#ifndef ALLOCVLA_REG
+#define ALLOCVLA_REG 0
+#endif
+#ifndef ALLOCVLA_INLINEASM
+#define ALLOCVLA_INLINEASM 0
+#endif
+#ifndef FREEVLA_REG
+#define FREEVLA_REG 0
+#endif
+#ifndef FREEVLA_INLINEASM
+#define FREEVLA_INLINEASM 0
+#endif
+#ifndef OLDSPVLA_INLINEASM
+#define OLDSPVLA_INLINEASM 0
+#endif
+#ifndef FPVLA_REG
+#define FPVLA_REG 0
+#endif
+#ifndef MIN_INT_TO_FLOAT_TYPE
+#define MIN_INT_TO_FLOAT_TYPE CHAR
+#endif
+#ifndef MIN_FLOAT_TO_INT_TYPE
+#define MIN_FLOAT_TO_INT_TYPE CHAR
+#endif
+#ifndef AVOID_FLOAT_TO_UNSIGNED
+#define AVOID_FLOAT_TO_UNSIGNED 0
+#endif
+#ifndef AVOID_UNSIGNED_TO_FLOAT
+#define AVOID_UNSIGNED_TO_FLOAT 0
+#endif
+#ifndef CHARCONV
+#define CHARCONV(x) (x)
+#define CHARBACK(x) (x)
+#define STRBACK(x)
+#else
+unsigned char CHARBACK(unsigned char);
+void STRBACK(unsigned char *);
+#endif
+
+#if HAVE_OSEK
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+
+#endif /* SUPP_H */
diff --git a/t1.h b/t1.h
new file mode 100644
index 0000000..e6f8b57
--- /dev/null
+++ b/t1.h
@@ -0,0 +1,4 @@
+/* $Revision: 1.2 $ */
+
+#include "t2.h"
+
diff --git a/t2.h b/t2.h
new file mode 100755
index 0000000..8ffe1e3
--- /dev/null
+++ b/t2.h
@@ -0,0 +1,2 @@
+t2 is here
+
diff --git a/tasm.c b/tasm.c
new file mode 100755
index 0000000..fb6374f
--- /dev/null
+++ b/tasm.c
@@ -0,0 +1,128 @@
+/* Test-language for vbcc. */
+
+#include "supp.h"
+
+struct Var *fv;
+
+struct Typ tint,mfunc;
+struct struct_declaration msd; /* initialized to zero */
+
+void raus(void)
+{
+ while(fv){
+ struct Var *m=fv->next;
+ free(fv);
+ fv=m;
+ }
+ while(first_ic){
+ struct IC *m=first_ic->next;
+ free(first_ic);
+ first_ic=m;
+ }
+ exit(0);
+}
+void add_IC(struct IC *new)
+{
+ new->next=0;
+ new->prev=last_ic;
+ new->change_cnt=new->use_cnt=0;
+ new->change_list=new->use_list=0;
+ new->line=0;
+ new->file=0;
+ if(!last_ic){
+ first_ic=new;
+ }else{
+ last_ic->next=new;
+ }
+ last_ic=new;
+}
+struct Var *add_var(char *name,struct Typ *t,int sc)
+{
+ struct Var *v=mymalloc(sizeof(*v));
+ v->vtyp=t;
+ v->storage_class=sc;
+ v->reg=0;
+ v->identifier=name;
+ v->offset=max_offset;
+ if(sc==AUTO) max_offset=zmadd(max_offset,sizetab[t->flags&NQ]);
+ v->priority=1;
+ v->flags=0;
+ v->next=fv;
+ v->clist=0;
+ v->fi=0;
+ v->inline_copy=0;
+ fv=v;
+ return v;
+}
+struct Var *add_tmp_var(struct Typ *t)
+{
+ return add_var(empty,t,AUTO);
+}
+struct Var *get_var(char *name)
+{
+ struct Var *v;char *buf;
+ for(v=fv;v;v=v->next){
+ if(!strcmp(name,v->identifier)) return v;
+ }
+ buf=mymalloc(strlen(name)+1);
+ strcpy(buf,name);
+ return add_var(buf,&tint,AUTO);
+}
+
+void read_ics()
+{
+ char s[400],q1[100],q2[100],z[100],op;
+ struct IC *new;
+ gets(s);
+ while(sscanf(s,"%99s = %99s %c %99s",z,q1,&op,q2)==4){
+ new=new_IC();
+ switch(op){
+ case '+': new->code=ADD;break;
+ case '*': new->code=MULT;break;
+ case '-': new->code=SUB;break;
+ case '/': new->code=DIV;break;
+ default: return;
+ }
+ new->typf=INT;
+ new->q1.flags=new->q2.flags=new->z.flags=VAR;
+ new->q1.am=new->q2.am=new->z.am=0;
+ new->q1.val.vmax=l2zm(0L);
+ new->q2.val.vmax=l2zm(0L);
+ new->z.val.vmax=l2zm(0L);
+ new->q1.v=get_var(q1);
+ new->q2.v=get_var(q2);
+ new->z.v=get_var(z);
+ add_IC(new);
+ gets(s);
+ }
+}
+void error(int n,...)
+{
+ printf("error %d\n",n);
+ raus();
+}
+void savescratch()
+{}
+
+main()
+{
+ struct Var *main;
+ max_offset=l2zm(0L);
+ if(!init_cg()) raus();
+ tint.flags=INT;
+ tint.next=0;
+ mfunc.flags=FUNKT;
+ mfunc.next=∭
+ mfunc.exact=&msd;
+ main=add_var("main",&mfunc,EXTERN);
+ read_ics();
+ printf("optflags: ");
+ scanf("%ld",&optflags);
+ pric(stdout,first_ic);
+ vl1=vl3=0;
+ vl2=fv;
+ optimize(optflags,main);
+ pric(stdout,first_ic);
+ gen_code(stdout,first_ic,main,max_offset);
+ raus();
+}
diff --git a/tt.h b/tt.h
new file mode 100755
index 0000000..9de6d55
--- /dev/null
+++ b/tt.h
@@ -0,0 +1,3 @@
+test1
+test2
+
diff --git a/type_expr.c b/type_expr.c
new file mode 100644
index 0000000..4c68805
--- /dev/null
+++ b/type_expr.c
@@ -0,0 +1,3090 @@
+/* $VER: vbcc (type_expr.c) $Revision: 1.64 $ */
+
+#include "vbc.h"
+
+static char FILE_[]=__FILE__;
+
+#define CONSTADDR 256
+
+
+/* if MASK is set, a specialized version will be generated */
+#define USEHALF (1L<<1)
+#define USELONG (1L<<2)
+#define USELLONG (1L<<3)
+#define USEFLOAT (1L<<4)
+#define USEHEXL (1L<<5)
+#define USEHEXU (1L<<6)
+#define USEDEC (1L<<7)
+#define USEOCT (1L<<8)
+#define USEINT (1L<<9)
+#define USEUNS (1L<<10)
+#define USESTR (1L<<11)
+#define USECHAR (1L<<12)
+#define USEPERC (1L<<13)
+#define USECNT (1L<<14)
+#define USEALT (1L<<15)
+#define USEZPAD (1L<<16)
+#define USELALGN (1L<<17)
+#define USEBLANK (1L<<18)
+#define USESIGN (1L<<19)
+#define USEWIDTH (1L<<20)
+#define USEAST (1L<<21)
+#define USEPREC (1L<<22)
+#define USESPEC (1L<<23)
+#define USEREXP (1L<<24)
+
+int alg_opt(np,type *);
+void simple_alg_opt(np);
+int test_assignment(type *,np);
+int type_expression2(np,type *);
+void make_cexpr(np);
+
+int dontopt;
+int no_cast_free;
+
+type uct={UNSIGNED|CHAR};
+type ust={UNSIGNED|SHORT};
+type uit={UNSIGNED|INT};
+type ult={UNSIGNED|LONG};
+
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+
+#ifdef HAVE_MISRA
+/* 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 */
+/* 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
+
+
+
+
+
+void insert_constn(np p)
+/* Spezialfall fuer np */
+{
+ if(!p||!p->ntyp) ierror(0);
+ insert_const(&p->val,p->ntyp->flags);
+}
+int const_typ(type *p)
+/* Testet, ob Typ konstant ist oder konstante Elemente enthaelt */
+{
+ int i;struct_declaration *sd;
+ if(p->flags&CONST) return(1);
+ if(ISSTRUCT(p->flags)||ISUNION(p->flags))
+ for(i=0;i<p->exact->count;i++)
+ if(const_typ((*p->exact->sl)[i].styp)) return(1);
+ return 0;
+}
+int arith_flag(int ta,int tb)
+{
+ /* TODO: volatile? */
+ ta&=NU;tb&=NU;
+ if(ta==LDOUBLE||tb==LDOUBLE) return LDOUBLE;
+ if(ta==DOUBLE||tb==DOUBLE) return DOUBLE;
+ if(ta==FLOAT||tb==FLOAT) return FLOAT;
+ ta=int_erw(ta);tb=int_erw(tb);
+ if(ta==(UNSIGNED|LLONG)||tb==(UNSIGNED|LLONG)) return UNSIGNED|LLONG;
+ if(ta==LLONG||tb==LLONG) return LLONG;
+ if(ta==(UNSIGNED|LONG)||tb==(UNSIGNED|LONG)) return UNSIGNED|LONG;
+ if((ta==LONG&&tb==(UNSIGNED|INT))||(ta==(UNSIGNED|INT)&&tb==LONG)){
+ if(zumleq(t_max(UNSIGNED|INT),t_max(LONG)))
+ return LONG;
+ else
+ return UNSIGNED|LONG;
+ }
+ if(ta==LONG||tb==LONG) return LONG;
+ if(ta==(UNSIGNED|INT)||tb==(UNSIGNED|INT)) return UNSIGNED|INT;
+ return INT;
+}
+
+type *arith_typ(type *a,type *b)
+/* Erzeugt Typ fuer arithmetische Umwandlung von zwei Operanden */
+{
+ int ta,tb,va,vol;type *new;
+ new=new_typ();
+ ta=a->flags&NU;tb=b->flags&NU;
+ vol=(a->flags&VOLATILE)|(b->flags&VOLATILE);
+ if(ta==LDOUBLE||tb==LDOUBLE){new->flags=LDOUBLE|vol;return new;}
+ if(ta==DOUBLE||tb==DOUBLE){new->flags=DOUBLE|vol;return new;}
+ if(ta==FLOAT||tb==FLOAT){new->flags=FLOAT|vol;return new;}
+ ta=int_erw(ta);tb=int_erw(tb);
+ if(ta==(UNSIGNED|LLONG)||tb==(UNSIGNED|LLONG)){new->flags=UNSIGNED|LLONG|vol;return new;}
+ if(ta==LLONG||tb==LLONG){new->flags=LLONG|vol;return new;}
+ if(ta==(UNSIGNED|LONG)||tb==(UNSIGNED|LONG)){new->flags=UNSIGNED|LONG|vol;return new;}
+ if((ta==LONG&&tb==(UNSIGNED|INT))||(ta==(UNSIGNED|INT)&&tb==LONG)){
+ if(zumleq(t_max(UNSIGNED|INT),t_max(LONG))) new->flags=LONG|vol; else new->flags=UNSIGNED|LONG|vol;
+ return new;
+ }
+ if(ta==LONG||tb==LONG){new->flags=LONG|vol;return new;}
+ if(ta==(UNSIGNED|INT)||tb==(UNSIGNED|INT)){new->flags=UNSIGNED|INT|vol;return new;}
+ new->flags=INT|vol;
+ return new;
+}
+int int_erw(int t)
+/* Fuehrt Integer_Erweiterung eines Typen durch */
+{
+ if((t&NQ)>=INT) return t;
+ if(t&UNSIGNED){
+ if((t&NQ)<=CHAR&&zumleq(t_max(UNSIGNED|CHAR),t_max(INT))) return INT;
+ if((t&NQ)<=SHORT&&zumleq(t_max(UNSIGNED|SHORT),t_max(INT))) return INT;
+ return UNSIGNED|INT;
+ }
+ return INT;
+}
+#if HAVE_AOS4
+static int aos4err;
+int aos4_attr(type *p,char *s)
+{
+ if(p->attr&&strstr(p->attr,s))
+ return 1;
+ if(p->next)
+ return aos4_attr(p->next,s);
+ else
+ return 0;
+}
+static np aos4_clone_tree(np p)
+{
+ np new;
+ if(!p) return 0;
+ new=new_node();
+ *new=*p;
+ new->ntyp=clone_typ(p->ntyp);
+ new->left=aos4_clone_tree(p->left);
+ new->right=aos4_clone_tree(p->right);
+ new->alist=0;new->cl=0;new->dsize=0;
+ if(p->flags==CALL/*||p->cl||p->dsize*/) aos4err=1;
+ return new;
+}
+#endif
+#ifdef HAVE_MISRA
+/* 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
+int type_expression(np p,type *ttyp)
+/* Art Frontend fuer type_expression2(). Setzt dontopt auf 0 */
+{
+ int ret_val;
+ dontopt=0;
+ simple_alg_opt(p);
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ ret_val = type_expression2(p,ttyp);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ return ret_val;
+
+}
+
+static void fix_addr_ptype(np op)
+{
+ np p=op;
+ while(p->flags==FIRSTELEMENT) p=p->left;
+ if(p->left->flags==CONTENT){
+ int pt=p->left->left->ntyp->flags;
+ if(!ISPOINTER(pt)) ierror(0);
+ if(!ISPOINTER(op->ntyp->flags)) ierror(0);
+ op->ntyp->flags=pt;
+ }
+}
+
+static int ptype(np op)
+{
+#ifdef POINTER_VARADR
+ Var *v=0;
+ np p=op;
+
+ while(p->flags==FIRSTELEMENT/*||p->flags==CONTENT*/) p=p->left;
+
+ if(p->flags==IDENTIFIER)
+ v=find_var(p->identifier,0);
+ if(v)
+ return POINTER_VARADR(v);
+ else
+ return POINTER_TYPE(op->ntyp);
+#else
+ return POINTER_TYPE(op->ntyp);
+#endif
+}
+
+static int decide_shortcut(np p,type *ttyp)
+{
+ int ttf=ttyp->flags,f=p->flags;
+ if(f==PMULT) f=MULT;
+ if(!shortcut(f,ttyp->flags&NU)||
+ ISFLOAT(ttf)||ISFLOAT(p->left->ntyp->flags)||ISFLOAT(p->right->ntyp->flags)
+ )
+ return 0;
+ ttf&=NQ;
+ if(ttf<INT) return 1;
+ if(zm2l(sizetab[ttf])<zm2l(sizetab[(p->left->ntyp->flags&NQ)])) return 1;
+ if(zm2l(sizetab[ttf])<zm2l(sizetab[(p->right->ntyp->flags&NQ)])) return 1;
+ return 0;
+}
+
+
+
+static type *best_addi2pt(zmax sz)
+{
+ if(!zmeqto(sizetab[CHAR],sizetab[INT])&&!zmeqto(sz,Z0)&&MINADDI2P<=CHAR&&zumleq(zm2zum(sz),zumadd(tu_max[CHAR],ZU1))){
+ return &uct;
+ }else if(!zmeqto(sizetab[SHORT],sizetab[INT])&&!zmeqto(sz,Z0)&&MINADDI2P<=SHORT&&zumleq(zm2zum(sz),zumadd(tu_max[SHORT],ZU1))){
+ return &ust;
+ }
+ return 0;
+}
+
+type *andcomp(np and,np cmp)
+{
+ int i=0;zmax sval;zumax uval;
+ if(cmp){
+ if((cmp->flags==CEXPR||cmp->flags==PCEXPR)){i=1;eval_constn(cmp);sval=vmax;uval=vumax;}
+ }else{
+ sval=Z0;uval=ZU0;
+ i=1;
+ }
+ if(and->flags==AND&&(and->left->flags==CEXPR||and->left->flags==PCEXPR)){i|=2;eval_constn(and->left);}
+ if(and->flags==AND&&(and->right->flags==CEXPR||and->right->flags==PCEXPR)){i|=2;eval_constn(and->right);}
+ if(i&2){
+ /*printf("CHECK: x&%ld ==/!= %ld\n",zm2l(vmax),(i&1)?zm2l(sval):-1L);*/
+ if(shortcut(COMPARE,UNSIGNED|CHAR)&&shortcut(AND,UNSIGNED|CHAR)&&!zmeqto(sizetab[CHAR],sizetab[SHORT])){
+ if(zmleq(vmax,t_max[CHAR]))
+ return &uct;
+ else if((i&1)&&zumleq(vumax,tu_max[CHAR])&&zumleq(uval,tu_max[CHAR]))
+ return &uct;
+ }
+ if(shortcut(COMPARE,UNSIGNED|SHORT)&&shortcut(AND,UNSIGNED|SHORT)&&!zmeqto(sizetab[SHORT],sizetab[INT])){
+ if(zmleq(vmax,t_max[SHORT]))
+ return &ust;
+ else if((i&1)&&zumleq(vumax,tu_max[SHORT])&&zumleq(uval,tu_max[SHORT]))
+ return &ust;
+ }
+ if(!zmeqto(sizetab[INT],sizetab[LONG])){
+ if(zmleq(vmax,t_max[INT]))
+ return &uit;
+ else if((i&1)&&zumleq(vumax,tu_max[INT])&&zumleq(uval,tu_max[INT]))
+ return &uit;
+ }
+ if(!zmeqto(sizetab[LONG],sizetab[LLONG])){
+ if(zmleq(vmax,t_max[LONG]))
+ return &ult;
+ else if((i&1)&&zumleq(vumax,tu_max[LONG])&&zumleq(uval,tu_max[LONG]))
+ return &ult;
+ }
+ }
+ return 0;
+}
+
+static int nullpointer(np p)
+{
+ if(p->flags!=CEXPR) return 0;
+ eval_constn(p); /* TODO: do we need to use other measure to verify null pointer? */
+ if(zmeqto(Z0,vmax)) return 1;
+ return 0;
+}
+
+int type_expression2(np p,type *ttyp)
+/* Erzeugt Typ-Strukturen fuer jeden Knoten des Baumes und */
+/* liefert eins zurueck, wenn der Baum ok ist, sonst 0 */
+/* Die Berechnung von Konstanten und andere Vereinfachungen */
+/* sollten vielleicht in eigene Funktion kommen */
+{
+ int ok,f=p->flags,mopt=dontopt,ttf;
+ type *shorttyp;
+ static int assignop;
+ int aoflag;
+#if HAVE_AOS4
+ np thisp=0;
+#endif
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(!p){ierror(0);return(1);}
+ if(ttyp) ttf=ttyp->flags&NQ;
+ /* if(p->ntyp) printf("Warnung: ntyp!=0\n");*/
+ p->lvalue=0;
+ p->sidefx=0;
+ ok=1;
+ if(!ecpp&&f==CALL&&p->left->flags==IDENTIFIER&&!find_var(p->left->identifier,0)){
+ /* implizite Deklaration bei Aufruf einer Funktion */
+ struct_declaration *sd;type *t;Var *v;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ error(161,p->left->identifier);
+ if(v=find_ext_var(p->left->identifier)){
+ if(!ISFUNC(v->vtyp->flags)||v->vtyp->next->flags!=INT){
+ error(68,p->left->identifier);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ }
+ v->flags&=~NOTINTU;
+ }else{
+ sd=mymalloc(sizeof(*sd));
+ sd->count=0;
+ t=new_typ();
+ t->flags=FUNKT;
+ t->exact=add_sd(sd,FUNKT);
+ t->next=new_typ();
+ t->next->flags=INT;
+ add_var(p->left->identifier,t,EXTERN,0);
+ }
+ }
+#if HAVE_AOS4
+ if(f==CALL&&p->left->flags==DSTRUCT){
+ thisp=new_node();
+ thisp->flags=ADDRESS;
+ aos4err=0;
+ thisp->left=aos4_clone_tree(p->left->left);
+ thisp->right=0;
+ thisp->alist=0;thisp->cl=0;thisp->dsize=0;thisp->ntyp=0;
+ }
+#endif
+#if HAVE_ECPP
+ if(ecpp&&f==CALL){
+ argument_list *al=p->alist;
+ if(al/*&&!al->arg->ntyp*/){
+ while(al){
+ if(!al->arg) ierror(0);
+ if(!type_expression2(al->arg,0)) return 0;
+ al->arg=makepointer(al->arg);
+ if(type_uncomplete(al->arg->ntyp)) error(39);
+ al=al->next;
+ }
+ }
+ }
+ if(ecpp&&f==CALL){
+ ecpp_merk_al=ecpp_al;
+ ecpp_al=p->alist;
+ }
+#endif
+ dontopt=0;
+ if(f==ADDRESS&&p->left->flags==IDENTIFIER) {p->left->flags|=CONSTADDR;/*puts("&const");*/}
+ if(ttyp&&(f==OR||f==AND||f==XOR||f==ADD||f==SUB||f==MULT||f==PMULT||f==DIV||f==MOD||f==KOMPLEMENT||f==MINUS)&&!ISPOINTER(ttyp->flags)&&shortcut(f==PMULT?MULT:f,ttyp->flags&NU))
+ shorttyp=ttyp;
+ else
+ shorttyp=0;
+ if(assignop){
+ aoflag=1;
+ assignop=0;
+ }else
+ aoflag=0;
+
+ if(!shorttyp){
+ if(f==EQUAL||f==INEQUAL){
+ if(p->left->flags==AND) shorttyp=andcomp(p->left,p->right);
+ if(p->right->flags==AND) shorttyp=andcomp(p->right,p->left);
+ }
+ }
+ if(!shorttyp&&(f==LAND||f==LOR)&&p->left->flags==AND) shorttyp=andcomp(p->left,0);
+ if(p->left&&p->flags!=ASSIGNOP){
+ struct_declaration *sd;
+ /* bei ASSIGNOP wird der linke Zweig durch den Link bewertet */
+ if(!p->left) ierror(0);
+ if(p->flags==CAST)
+ ok&=type_expression2(p->left,p->ntyp);
+ else
+ ok&=type_expression2(p->left,shorttyp);
+ if(p->left) p->sidefx|=p->left->sidefx;
+ if(!ok) return 0;
+ }
+ if(aoflag){
+ if(!p->left||!p->right) ierror(0);
+ shorttyp=p->left->ntyp;
+ ttyp=shorttyp;
+ ttf=ttyp->flags&NQ;
+ }
+
+ if(f==LAND||f==LOR){
+ shorttyp=0;
+ if(p->right->flags==AND) shorttyp=andcomp(p->right,0);
+ }
+
+ if(f==ADD){
+ if(p->left->flags==ADDRESSS||p->left->flags==ADDRESSA||p->left->flags==ADDRESSS){
+ zmax sz=szof(p->left->left->ntyp);
+ shorttyp=best_addi2pt(sz);
+ }
+ if((p->left->ntyp->flags&NQ)==ARRAY){
+ zmax sz=szof(p->left->ntyp);
+ shorttyp=best_addi2pt(sz);
+ if(shorttyp){
+ np new=new_node();
+ new->flags=CAST;
+ new->ntyp=clone_typ(shorttyp);
+ new->left=p->right;
+ p->right=new;
+ }
+ }
+ }
+ if(p->right&&p->right->flags!=MEMBER){
+ struct_declaration *sd;
+ if(p->flags==ASSIGNOP){
+ dontopt=1;
+ assignop=1;
+ }else
+ dontopt=0;
+ if(p->flags==ASSIGN)
+ ok&=type_expression2(p->right,p->left->ntyp);
+ else
+ ok&=type_expression2(p->right,shorttyp);
+ p->sidefx|=p->right->sidefx;
+ if(!ok) return 0;
+ }
+#if HAVE_AOS4
+ if(thisp){
+ if(aos4_attr(p->left->ntyp,"libcall")){
+ argument_list *n=mymalloc(sizeof(*n));
+ n->arg=thisp;
+ n->next=p->alist;
+ n->pushic=0;
+ p->alist=n;
+ if(aos4err) {pre(stdout,thisp);ierror(0);}
+ }else{
+ free_expression(thisp);
+ }
+ }
+#endif
+#if HAVE_ECPP
+ if(ecpp&&f==CALL){
+ ecpp_al=ecpp_merk_al;
+ }
+#endif
+/* printf("bearbeite %s\n",ename[p->flags]);*/
+/* Erzeugung von Zeigern aus Arrays */
+/* Hier muss noch einiges genauer werden (wie gehoert das?) */
+ if(p->left&&f!=PCEXPR&&(ISARRAY(p->left->ntyp->flags)||ISFUNC(p->left->ntyp->flags))){
+ if(f!=ADDRESS&&f!=ADDRESSA&&f!=ADDRESSS&&f!=FIRSTELEMENT&&f!=DSTRUCT&&(f<PREINC||f>POSTDEC)&&(f<ASSIGN||f>ASSIGNOP)){
+ np new=new_node();
+ zmax sz=szof(p->left->ntyp);
+ if((p->left->ntyp->flags&NQ)==ARRAY) new->flags=ADDRESSA;
+ else new->flags=ADDRESS;
+ new->ntyp=0;
+ new->left=p->left;
+ new->right=0;new->lvalue=0;new->sidefx=0; /* sind sidefx immer 0? */
+ p->left=new;
+ ok&=type_expression2(p->left,0);
+ }
+ }
+ if(p->right&&f!=PCEXPR&&f!=FIRSTELEMENT&&f!=DSTRUCT&&f!=ADDRESSS&&p->right->ntyp&&(ISARRAY(p->right->ntyp->flags)||ISFUNC(p->right->ntyp->flags))){
+ np new=new_node();
+ if(ISARRAY(p->right->ntyp->flags)) new->flags=ADDRESSA;
+ else new->flags=ADDRESS;
+ new->ntyp=0;
+ new->left=p->right;
+ new->right=0;new->lvalue=0;new->sidefx=0; /* sind sidefx immer 0? */
+ p->right=new;
+ ok&=type_expression2(p->right,0);
+ }
+
+ if(f==IDENTIFIER||f==(IDENTIFIER|CONSTADDR)){
+ int ff;Var *v;
+#ifdef HAVE_ECPP
+/* 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
+ if(!ecpp){
+ if(p->identifier==empty)
+ /* variable sizeof-expression */
+ v=p->dsize;
+ else{
+ char buf[20];
+ v=find_var(p->identifier,0);
+ if(v&&v->storage_class==EXTERN){
+ if(!strcmp(p->identifier,"strtod")){sprintf(buf,"vfscanf.%ld",1|USEFLOAT);needs(buf);}
+ if(!strcmp(p->identifier,"strtof")){sprintf(buf,"vscanf.%ld",1|USEFLOAT);needs(buf);}
+ if(!strcmp(p->identifier,"atof")){sprintf(buf,"vscanf.%ld",1|USEFLOAT);needs(buf);}
+ if(!strcmp(p->identifier,"tmpnam")){sprintf(buf,"vfprintf.%ld",1|USEDEC);needs(buf);}
+ if(!strcmp(p->identifier,"fopen")){
+ needs("__read.2");
+ needs("__write.2");
+ needs("stdin.2");
+ needs("stdout.2");
+ needs("stderr.2");
+ }
+ }
+ }
+ }
+ if(v==0){error(82,p->identifier);return(0);}
+ if(disallow_statics&&v->storage_class==STATIC&&v->nesting==0&&*v->identifier){
+ error(302,v->identifier);
+ return 0;
+ }
+ ff=v->vtyp->flags&NQ;
+ if(ISARITH(ff)||ISPOINTER(ff)||ISSTRUCT(ff)||ISUNION(ff)||ISVECTOR(ff)) p->lvalue=1;
+ p->ntyp=clone_typ(v->vtyp);
+ /* arithmetischen const Typ als Konstante behandeln, das muss noch
+ deutlich anders werden, bevor man es wirklich so machen kann
+ if((p->ntyp->flags&CONST)&&ISARITH(p->ntyp->flags)&&v->clist&&!(f&CONSTADDR)){
+ p->flags=CEXPR;
+ p->val=v->clist->val;
+ v->flags|=USEDASSOURCE;
+ }*/
+ p->flags&=~CONSTADDR;
+ if((p->ntyp->flags&NQ)==ENUM){
+ /* enumerations auch als Konstante (int) behandeln */
+ p->flags=CEXPR;
+ if(!v->clist) ierror(0);
+ p->val=v->clist->val;
+ p->ntyp->flags=CONST|INT;
+ }
+ p->o.v=v;
+ if (p->ntyp->flags&VOLATILE) p->sidefx=1; /* Touching a volatile may have side effects */
+ return 1;
+ }
+
+ if(f==CEXPR||f==PCEXPR||f==STRING) return 1;
+
+ if(f==REINTERPRET){
+ /* todo: add checks */
+ return 1;
+ }
+
+ if(f==BITFIELD) return 1;
+
+ if(f==LITERAL){
+ p->lvalue=1;
+ return 1;
+ }
+
+ if(f==KOMMA){
+ if(const_expr){error(46);return 0;}
+ p->ntyp=clone_typ(p->right->ntyp);
+ if(f==CEXPR) p->val=p->right->val;
+ return ok;
+ }
+ if(f==ASSIGN||f==ASSIGNOP){
+ if(!p) ierror(0);
+ if(!p->left) ierror(0);
+ if(p->left->lvalue==0) {error(86);/*prd(p->left->ntyp);*/return 0;}
+ if(const_typ(p->left->ntyp)) {error(87);return 0;}
+ if(type_uncomplete(p->left->ntyp)) {error(88);return 0;}
+ if(type_uncomplete(p->right->ntyp)) {error(88);return 0;}
+ p->ntyp=clone_typ(p->left->ntyp);
+ p->sidefx=1;
+ return(test_assignment(p->left->ntyp,p->right));
+ }
+ if(f==LOR||f==LAND){
+ int a1=-1,a2=-1,m;
+ if(ISVECTOR(p->left->ntyp->flags)){
+ if(ISVECTOR(p->right->ntyp->flags)){
+ if((p->left->ntyp->flags&NU)!=(p->right->ntyp->flags&NU)){error(89);return 0;}
+ }else{
+ if(!ISINT(p->right->ntyp->flags)){error(89);return 0;}
+ }
+ p->ntyp=new_typ();
+ p->ntyp->flags=p->left->ntyp->flags&NQ;
+ return ok;
+ }
+ if(ISVECTOR(p->right->ntyp->flags)){
+ if(!ISINT(p->left->ntyp->flags)){error(89);return 0;}
+ p->ntyp->flags=p->right->ntyp->flags&NQ;
+ return ok;
+ }
+ if(f==LAND) m=1; else m=0;
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ p->ntyp=new_typ();
+ p->ntyp->flags=INT;
+ if(!ISARITH(p->left->ntyp->flags)&&!ISPOINTER(p->left->ntyp->flags))
+ {error(89);ok=0;}
+ if(!ISARITH(p->right->ntyp->flags)&&!ISPOINTER(p->right->ntyp->flags))
+ {error(89);ok=0;}
+ if(p->left->flags==CEXPR){
+ eval_constn(p->left);
+ if(!zldeqto(vldouble,d2zld(0.0))||!zumeqto(vumax,ul2zum(0UL))||!zmeqto(vmax,l2zm(0L))) a1=1; else a1=0;
+ }
+ if(p->right->flags==CEXPR){
+ eval_constn(p->right);
+ if(!zldeqto(vldouble,d2zld(0.0))||!zumeqto(vumax,ul2zum(0UL))||!zmeqto(vmax,l2zm(0L))) a2=1; else a2=0;
+ }
+ if(a1==1-m||a2==1-m||(a1==m&&a2==m)){
+ p->flags=CEXPR;p->sidefx=0;
+ if(!p->left->sidefx) {free_expression(p->left);p->left=0;} else p->sidefx=1;
+ if(!p->right->sidefx||a1==1-m) {free_expression(p->right);p->right=0;} else p->sidefx=0;
+ if(a1==1-m||a2==1-m) {p->val.vint=zm2zi(l2zm((long)(1-m)));}
+ else {p->val.vint=zm2zi(l2zm((long)m));}
+ }
+ return ok;
+ }
+ if(f==OR||f==AND||f==XOR){
+ if(ISVECTOR(p->left->ntyp->flags)){
+ if(!ISINT(VECTYPE(p->left->ntyp->flags))){error(90);return 0;}
+ if(ISVECTOR(p->right->ntyp->flags)){
+ if((p->left->ntyp->flags&NU)!=(p->right->ntyp->flags&NU)){error(98);return 0;}
+ }else{
+ if(!ISINT(p->right->ntyp->flags)){error(90);return 0;}
+ }
+ p->ntyp=clone_typ(p->left->ntyp);
+ return ok;
+ }
+ if(ISVECTOR(p->right->ntyp->flags)){
+ if(!ISINT(VECTYPE(p->right->ntyp->flags))){error(90);return 0;}
+ if(!ISINT(p->left->ntyp->flags)){error(90);return 0;}
+ p->ntyp=clone_typ(p->right->ntyp);
+ return ok;
+ }
+ if(!ISINT(p->left->ntyp->flags)){error(90);return 0;}
+ if(!ISINT(p->right->ntyp->flags)){error(90);return 0;}
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ if(ttyp&&decide_shortcut(p,ttyp))
+ p->ntyp=clone_typ(ttyp);
+ else
+ p->ntyp=arith_typ(p->left->ntyp,p->right->ntyp);
+ if(!mopt){
+ if(!alg_opt(p,ttyp)) ierror(0);
+ }
+ return ok;
+ }
+ if(f==LESS||f==LESSEQ||f==GREATER||f==GREATEREQ||f==EQUAL||f==INEQUAL){
+ /* hier noch einige Abfragen fuer sichere Entscheidungen einbauen */
+ /* z.B. unigned/signed-Vergleiche etc. */
+ /* die val.vint=0/1-Zuweisungen muessen noch an zint angepasst */
+ /* werden */
+ zmax s1,s2;zumax u1,u2;zldouble d1,d2;int c=0;
+ type *t;
+ if(ISVECTOR(p->left->ntyp->flags)){
+ if(ISVECTOR(p->right->ntyp->flags)){
+ if((p->left->ntyp->flags&NU)!=(p->right->ntyp->flags&NU)){error(89);return 0;}
+ }
+ p->ntyp=new_typ();
+ if(ISFLOAT(VECTYPE(p->left->ntyp->flags)))
+ p->ntyp->flags=mkvec(INT,VECDIM(p->left->ntyp->flags));
+ else
+ p->ntyp->flags=p->left->ntyp->flags&NQ;
+ return ok;
+ }
+ if(ISVECTOR(p->right->ntyp->flags)){
+ p->ntyp=new_typ();
+ if(ISFLOAT(VECTYPE(p->right->ntyp->flags)))
+ p->ntyp->flags=mkvec(INT,VECDIM(p->left->ntyp->flags));
+ else
+ p->ntyp->flags=p->right->ntyp->flags&NQ;
+ return ok;
+ }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ if(!ISARITH(p->left->ntyp->flags)||!ISARITH(p->right->ntyp->flags)){
+ if(!ISPOINTER(p->left->ntyp->flags)||!ISPOINTER(p->right->ntyp->flags)){
+ if(f!=EQUAL&&f!=INEQUAL){
+ error(92);return 0;
+ }else{
+ if((!ISPOINTER(p->left->ntyp->flags)||p->right->flags!=CEXPR)&&
+ (!ISPOINTER(p->right->ntyp->flags)||p->left->flags!=CEXPR)){
+ error(93);return 0;
+ }else{
+ if(p->left->flags==CEXPR) eval_constn(p->left);
+ else eval_constn(p->right);
+ if(!zldeqto(vldouble,d2zld(0.0))||!zmeqto(vmax,l2zm(0L))||!zumeqto(vumax,ul2zum(0UL)))
+ {error(40);return 0;}
+ }
+ }
+ }else{
+ if(compatible_types(p->left->ntyp->next,p->right->ntyp->next,NQ)){
+ }else{
+ if(f!=EQUAL&&f!=INEQUAL) error(41);
+ if((p->left->ntyp->next->flags&NQ)!=VOID&&(p->right->ntyp->next->flags&NQ)!=VOID)
+ {error(41);}
+ }
+ }
+ }
+ if(p->left->flags==CEXPR){
+ eval_constn(p->left);
+ d1=vldouble;u1=vumax;s1=vmax;c|=1;
+ if((p->right->ntyp->flags&UNSIGNED)&&!(p->left->ntyp->flags&UNSIGNED)){
+ if(zldleq(d1,d2zld(0.0))&&zmleq(s1,l2zm(0L))){
+ if(!zldeqto(d1,d2zld(0.0))||!zmeqto(s1,l2zm(0L))){
+ if(zumleq(tu_max[p->right->ntyp->flags&NQ],t_max[p->left->ntyp->flags&NQ]))
+ error(165);
+ }else{
+ if(f==GREATER||f==LESSEQ) error(165);
+ }
+ }
+ }
+ }
+ if(p->right->flags==CEXPR){
+ eval_constn(p->right);
+ d2=vldouble;u2=vumax;s2=vmax;c|=2;
+ if((p->left->ntyp->flags&UNSIGNED)&&!(p->right->ntyp->flags&UNSIGNED)){
+ if(zldleq(d2,d2zld(0.0))&&zmleq(s2,l2zm(0L))){
+ if(!zldeqto(d2,d2zld(0.0))||!zmeqto(s2,l2zm(0L))){
+ if(zumleq(tu_max[p->left->ntyp->flags&NQ],t_max[p->right->ntyp->flags&NQ]))
+ error(165);
+ }else{
+ if(f==LESS||f==GREATEREQ) error(165);
+ }
+ }
+ }
+ }
+ p->ntyp=new_typ();
+ p->ntyp->flags=INT;
+ if(c==3){
+ p->flags=CEXPR;
+ t=arith_typ(p->left->ntyp,p->right->ntyp);
+ if(!p->left->sidefx) {free_expression(p->left);p->left=0;}
+ if(!p->right->sidefx) {free_expression(p->right);p->right=0;}
+ if(ISFLOAT(t->flags)){
+ if(f==EQUAL) p->val.vint=zm2zi(l2zm((long)zldeqto(d1,d2)));
+ if(f==INEQUAL) p->val.vint=zm2zi(l2zm((long)!zldeqto(d1,d2)));
+ if(f==LESSEQ) p->val.vint=zm2zi(l2zm((long)zldleq(d1,d2)));
+ if(f==GREATER) p->val.vint=zm2zi(l2zm((long)!zldleq(d1,d2)));
+ if(f==LESS){
+ if(zldleq(d1,d2)&&!zldeqto(d1,d2))
+ p->val.vint=zm2zi(l2zm(1L));
+ else
+ p->val.vint=zm2zi(l2zm(0L));
+ }
+ if(f==GREATEREQ){
+ if(!zldleq(d1,d2)||zldeqto(d1,d2))
+ p->val.vint=zm2zi(l2zm(1L));
+ else
+ p->val.vint=zm2zi(l2zm(0L));
+ }
+ }else{
+ if(t->flags&UNSIGNED){
+ if(f==EQUAL) p->val.vint=zm2zi(l2zm((long)zumeqto(u1,u2)));
+ if(f==INEQUAL) p->val.vint=zm2zi(l2zm((long)!zumeqto(u1,u2)));
+ if(f==LESSEQ) p->val.vint=zm2zi(l2zm((long)zumleq(u1,u2)));
+ if(f==GREATER) p->val.vint=zm2zi(l2zm((long)!zumleq(u1,u2)));
+ if(f==LESS){
+ if(zumleq(u1,u2)&&!zumeqto(u1,u2))
+ p->val.vint=zm2zi(l2zm(1L));
+ else
+ p->val.vint=zm2zi(l2zm(0L));
+ }
+ if(f==GREATEREQ){
+ if(!zumleq(u1,u2)||zumeqto(u1,u2))
+ p->val.vint=zm2zi(l2zm(1L));
+ else
+ p->val.vint=zm2zi(l2zm(0L));
+ }
+ }else{
+ if(f==EQUAL) p->val.vint=zm2zi(l2zm((long)zmeqto(s1,s2)));
+ if(f==INEQUAL) p->val.vint=zm2zi(l2zm((long)!zmeqto(s1,s2)));
+ if(f==LESSEQ) p->val.vint=zm2zi(l2zm((long)zmleq(s1,s2)));
+ if(f==GREATER) p->val.vint=zm2zi(l2zm((long)!zmleq(s1,s2)));
+ if(f==LESS){
+ if(zmleq(s1,s2)&&!zmeqto(s1,s2))
+ p->val.vint=zm2zi(l2zm(1L));
+ else
+ p->val.vint=zm2zi(l2zm(0L));
+ }
+ if(f==GREATEREQ){
+ if(!zmleq(s1,s2)||zmeqto(s1,s2))
+ p->val.vint=zm2zi(l2zm(1L));
+ else
+ p->val.vint=zm2zi(l2zm(0L));
+ }
+ }
+ }
+ freetyp(t);
+ }
+ return ok;
+ }
+ if(f==ADD||f==SUB||f==MULT||f==DIV||f==MOD||f==LSHIFT||f==RSHIFT||f==PMULT){
+ if(ISVECTOR(p->left->ntyp->flags)){
+ if((f==MOD||f==LSHIFT||f==RSHIFT)&&ISFLOAT(VECTYPE(p->left->ntyp->flags))){
+ error(98);
+ return 0;
+ }
+ if(ISARITH(p->right->ntyp->flags)){
+ p->ntyp=clone_typ(p->left->ntyp);
+ return ok;
+ }
+ if((p->left->ntyp->flags&NU)==(p->right->ntyp->flags&NU)){
+ p->ntyp=clone_typ(p->left->ntyp);
+ return ok;
+ }
+ error(98);
+ return 0;
+ }
+ if(ISVECTOR(p->right->ntyp->flags)){
+ if((f==MOD||f==LSHIFT||f==RSHIFT)&&ISFLOAT(VECTYPE(p->right->ntyp->flags))){
+ error(98);
+ return 0;
+ }
+ if(ISARITH(p->left->ntyp->flags)){
+ p->ntyp=clone_typ(p->right->ntyp);
+ return ok;
+ }
+ error(98);
+ return 0;
+ }
+ if(!ISARITH(p->left->ntyp->flags)||!ISARITH(p->right->ntyp->flags)){
+ np new;zmax sz; int typf=0;
+#ifdef MAXADDI2P
+ static type pmt={MAXADDI2P};
+#endif
+ if(f!=ADD&&f!=SUB){error(94);return 0;}
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ if(ISPOINTER(p->left->ntyp->flags)){
+ if((p->left->ntyp->next->flags&NQ)==VOID)
+ {error(95);return 0;}
+ if(ISPOINTER(p->right->ntyp->flags)){
+ if((p->right->ntyp->next->flags&NQ)==VOID)
+ {error(95);return 0;}
+ if(!compatible_types(p->left->ntyp->next,p->right->ntyp->next,NQ))
+ {error(41);}
+ if(f!=SUB){
+ error(96);
+ return 0;
+ }else{
+ typf=3;
+ }
+ }else{
+ if(!ISINT(p->right->ntyp->flags))
+ {error(97,ename[f]);return 0;}
+ if(p->right->flags!=PMULT&&p->right->flags!=PCEXPR){
+ new=new_node();
+ new->flags=PMULT;
+ new->ntyp=0;
+ new->left=p->right;
+ new->right=new_node();
+ if(is_vlength(p->left->ntyp->next)){
+ new->right->flags=IDENTIFIER;
+ new->right->identifier=empty;
+ new->right->dsize=vlength_szof(p->left->ntyp->next);
+ new->right->val.vmax=l2zm(0L);
+ new->right->sidefx=0;
+ }else{
+ new->right->flags=PCEXPR;
+ sz=szof(p->left->ntyp->next);
+ if(zmeqto(l2zm(0L),sz)) error(78);
+#if HAVE_INT_SIZET
+ new->right->val.vint=zm2zi(sz);
+#else
+ new->right->val.vlong=zm2zl(sz);
+#endif
+ }
+ new->right->left=new->right->right=0;
+ new->right->ntyp=new_typ();
+#if HAVE_INT_SIZET
+ new->right->ntyp->flags=INT;
+#else
+ new->right->ntyp->flags=LONG;
+#endif
+ p->right=new;
+#ifdef MAXADDI2P
+ ok&=type_expression2(new,(shorttyp&&(shorttyp->flags&NQ)<MAXADDI2P)?shorttyp:&pmt);
+#else
+ ok&=type_expression2(new,shorttyp);
+#endif
+ }
+ typf=1;
+ }
+ }else{
+ np merk;
+ if(!ISPOINTER(p->right->ntyp->flags))
+ {error(98);return 0;}
+ if((p->right->ntyp->next->flags&NQ)==VOID)
+ {error(95);return 0;}
+ if(!ISINT(p->left->ntyp->flags))
+ {error(98);return 0;}
+ if(p->flags==SUB){error(99);return 0;}
+ if(p->left->flags!=PMULT&&p->left->flags!=PCEXPR){
+ new=new_node();
+ new->flags=PMULT;
+ new->ntyp=0;
+ new->left=p->left;
+ new->right=new_node();
+ if(is_vlength(p->right->ntyp->next)){
+ new->right->flags=IDENTIFIER;
+ new->right->identifier=empty;
+ new->right->dsize=vlength_szof(p->right->ntyp->next);
+ new->right->val.vmax=l2zm(0L);
+ new->right->sidefx=0;
+ }else{
+ new->right->flags=PCEXPR;
+ sz=szof(p->right->ntyp->next);
+ if(zmeqto(l2zm(0L),sz)) error(78);
+#if HAVE_INT_SIZET
+ new->right->val.vint=zm2zi(sz);
+#else
+ new->right->val.vlong=zm2zl(sz);
+#endif
+ }
+ new->right->left=new->right->right=0;
+ new->right->ntyp=new_typ();
+#if HAVE_INT_SIZET
+ new->right->ntyp->flags=INT;
+#else
+ new->right->ntyp->flags=LONG;
+#endif
+ p->left=new;
+#ifdef MAXADDI2P
+ ok&=type_expression2(new,&pmt);
+#else
+ ok&=type_expression2(new,0);
+#endif
+ }
+ typf=2;
+ merk=p->left;p->left=p->right;p->right=merk;
+ }
+ if(typf==0){ierror(0);return(0);}
+ else{
+ if(typf==3){
+ p->ntyp=new_typ();
+ p->ntyp->flags=PTRDIFF_T(p->left->ntyp->flags);
+ }else{
+ /*if(typf==1)*/ p->ntyp=clone_typ(p->left->ntyp);
+ /* else p->ntyp=clone_typ(p->right->ntyp);*/
+ /* Abfrage wegen Vertauschen der Knoten unnoetig */
+ }
+ }
+ }else{
+ if(f==LSHIFT||f==RSHIFT){
+ if(ttyp&&f==LSHIFT&&(ttf<=INT||ttf<(p->left->ntyp->flags&NQ))&&shortcut(f,ttyp->flags&NU)){
+ p->ntyp=clone_typ(ttyp);
+ }else if(ttyp&&f==RSHIFT&&ttf<=INT&&ttf<=(p->left->ntyp->flags&NQ)&&shortcut(f,p->left->ntyp->flags&NU)){
+ p->ntyp=clone_typ(p->left->ntyp);
+ }else{
+ p->ntyp=arith_typ(p->left->ntyp,p->left->ntyp);
+ p->ntyp->flags&=~NQ;
+ p->ntyp->flags|=int_erw(p->left->ntyp->flags);
+ }
+ if(p->right->flags==CEXPR){
+ eval_constn(p->right);
+ if(!zmleq(l2zm(0L),vmax)) error(366);
+ if(zmleq(zmmult(sizetab[p->ntyp->flags&NQ],char_bit),vmax)&&zmleq(zmmult(sizetab[p->left->ntyp->flags&NQ],char_bit),vmax)) error(367);
+ }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ }else{
+ /* ggfs. in kleinerem Zieltyp auswerten - bei float keinen shortcut (wäre evtl. double=>float unkritisch?) */
+ if(ttyp&&decide_shortcut(p,ttyp))
+ p->ntyp=clone_typ(ttyp);
+ else
+ p->ntyp=arith_typ(p->left->ntyp,p->right->ntyp);
+ if(!ISINT(p->ntyp->flags)&&(f==MOD||f==LSHIFT||f==RSHIFT))
+ {error(101);ok=0;}
+ }
+ }
+ /* fuegt &a+x zusammen, noch sub und left<->right machen */
+ /* Bei CEXPR statt PCEXPR auch machen? */
+ if((p->flags==ADD||p->flags==SUB)){
+ np m,c=0,a=0;
+ if(p->left->flags==PCEXPR&&p->flags==ADD) c=p->left;
+ if(p->right->flags==PCEXPR) c=p->right;
+ if(p->left->flags==ADDRESS||p->left->flags==ADDRESSA||p->left->flags==ADDRESSS) a=p->left;
+ if(p->right->flags==ADDRESS||p->right->flags==ADDRESSA||p->right->flags==ADDRESSS) a=p->right;
+ if(c&&a){
+ m=a->left;
+ /* kann man das hier so machen oder muss man da mehr testen ? */
+ while(m->flags==FIRSTELEMENT||m->flags==ADDRESS||m->flags==ADDRESSA||m->flags==ADDRESSS) m=m->left;
+ if((m->flags==IDENTIFIER||m->flags==STRING)&&!is_vlength(m->ntyp)){
+ if(DEBUG&1) printf("&a+x with %s combined\n",ename[p->left->flags]);
+ eval_const(&c->val,c->ntyp->flags);
+ if(p->flags==ADD)
+ m->val.vmax=zumadd(m->val.vmax,vmax);
+ else
+ m->val.vmax=zmsub(m->val.vmax,vmax);
+ vmax=szof(m->ntyp);
+ if(!zmeqto(vmax,l2zm(0L))&&zumleq(vmax,m->val.vmax)){
+ if(zumeqto(vmax,m->val.vmax))
+ error(79);
+ else
+ error(80);
+ }
+ vmax=l2zm(0L);
+ if(!zmeqto(m->val.vmax,l2zm(0L))&&zumleq(m->val.vmax,vmax)) error(80);
+ free_expression(c);
+ if(p->ntyp) freetyp(p->ntyp);
+ *p=*a;
+ free(a);
+ return type_expression2(p,0);
+ }
+ }
+ }
+ if(!mopt){
+ if(!alg_opt(p,ttyp)) ierror(0);
+ }
+ return ok;
+ }
+ if(f==CAST){
+ int from=(p->left->ntyp->flags),to=(p->ntyp->flags);
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ from&=NQ;to&=NQ;
+ if(to==VOID) return ok;
+ if(from==VOID)
+ {error(102);return 0;}
+ if((!ISARITH(to)||!ISARITH(from))&&
+ (!ISPOINTER(to)||!ISPOINTER(from))){
+ if(ISPOINTER(to)){
+ if(ISINT(from)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(!zmleq(sizetab[from],sizetab[to])){
+ error(103);
+ }
+ }else{
+ error(104);return 0;
+ }
+ }else{
+ if(!ISPOINTER(from))
+ {error(105);return 0;}
+ if(ISINT(to)){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if(!zmleq(sizetab[from],sizetab[to])){
+ error(106);
+ }
+ }else{
+ error(104);return 0;
+ }
+ }
+ }
+ if(ISINT(from)&&ISINT(to)&&!zmleq(sizetab[from],sizetab[to])&&p->left->flags!=CEXPR) error(166);
+ if(ISPOINTER(to)&&ISPOINTER(from)&&!zmleq(falign(p->ntyp->next),falign(p->left->ntyp->next)))
+ error(167);
+ if(p->left->flags==CEXPR){
+ eval_constn(p->left);
+ if(ISPOINTER(p->ntyp->flags))
+ if(!zumeqto(vumax,ul2zum(0UL))||!zmeqto(vmax,l2zm(0L))||!zldeqto(vldouble,d2zld(0.0)))
+ error(81);
+ insert_constn(p);
+ p->flags=CEXPR;
+ if(!p->left->sidefx){
+ if(!no_cast_free)
+ free_expression(p->left);
+ p->left=0;
+ }
+ }
+#ifdef HAVE_ECPP
+/* 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
+ return ok;
+ }
+ if(f==MINUS||f==KOMPLEMENT||f==NEGATION){
+ if(ISVECTOR(p->left->ntyp->flags)){
+ if(f==NEGATION){
+ if(ISFLOAT(VECTYPE(p->left->ntyp->flags))){error(98);return 0;}
+ p->ntyp=new_typ();
+ p->ntyp->flags=p->left->ntyp->flags&NQ;
+ return ok;
+ }
+ if(f==KOMPLEMENT&&ISFLOAT(VECTYPE(p->left->ntyp->flags))){error(109);return 0;}
+ p->ntyp=clone_typ(p->left->ntyp);
+ return ok;
+ }
+ if(!ISARITH(p->left->ntyp->flags)){
+ if(f!=NEGATION){
+ error(107);return 0;
+ }else{
+ if(!ISPOINTER(p->left->ntyp->flags))
+ {error(108);return 0;}
+ }
+ }
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ if(f==KOMPLEMENT&&!ISINT(p->left->ntyp->flags))
+ {error(109);return 0;}
+ if(f==NEGATION){
+ p->ntyp=new_typ();
+ p->ntyp->flags=INT;
+ }else{
+ if(!p->left->ntyp) ierror(0);
+ p->ntyp=clone_typ(p->left->ntyp);
+ if(ISINT(p->ntyp->flags)){
+ if(!ttyp||!shortcut(f,ttyp->flags&NU)){
+ p->ntyp->flags=int_erw(p->ntyp->flags);
+ }else{
+ if((f==MINUS&&!zmleq(sizetab[ttyp->flags&NQ],sizetab[p->ntyp->flags&NQ]))||
+ (f==KOMPLEMENT&&!zmleq(sizetab[ttyp->flags&NQ],sizetab[p->ntyp->flags&NQ])&&(p->ntyp->flags&UNSIGNED)))
+ p->ntyp->flags=int_erw(p->ntyp->flags);
+ }
+ }
+ }
+ if(p->left->flags==CEXPR){
+ eval_constn(p->left);
+ if(f==KOMPLEMENT){
+ if(p->ntyp->flags&UNSIGNED){
+ gval.vumax=zumkompl(vumax);
+ eval_const(&gval,(UNSIGNED|MAXINT));
+ }else{
+ gval.vmax=zmkompl(vmax);
+ eval_const(&gval,MAXINT);
+ }
+ }
+ if(f==MINUS){
+ if(ISFLOAT(p->ntyp->flags)){
+ gval.vldouble=zldsub(d2zld(0.0),vldouble);
+ eval_const(&gval,LDOUBLE);
+ }else{
+ if(p->ntyp->flags&UNSIGNED){
+ gval.vumax=zumsub(ul2zum(0UL),vumax);
+ eval_const(&gval,(UNSIGNED|MAXINT));
+ }else{
+ gval.vmax=zmsub(l2zm(0L),vmax);
+ eval_const(&gval,MAXINT);
+ }
+ }
+ }
+ if(f==NEGATION){
+ if(zldeqto(vldouble,d2zld(0.0))&&zumeqto(vumax,ul2zum(0UL))&&zmeqto(vmax,l2zm(0L)))
+ gval.vmax=l2zm(1L);
+ else
+ gval.vmax=l2zm(0L);
+ eval_const(&gval,MAXINT);
+ }
+ insert_constn(p);
+ p->flags=CEXPR;
+ if(!p->left->sidefx&&p->left) {free_expression(p->left);p->left=0;}
+ }
+ return ok;
+ }
+ if(f==CONTENT){
+ if(!ISPOINTER(p->left->ntyp->flags))
+ {error(111);return 0;}
+ if(!ISARRAY(p->left->ntyp->next->flags)&&type_uncomplete(p->left->ntyp->next))
+ {error(112);return 0;}
+ p->ntyp=clone_typ(p->left->ntyp->next);
+ if(!ISARRAY(p->ntyp->flags)) p->lvalue=1;
+ if(p->left->flags==ADDRESS&&zumeqto(p->left->val.vumax,ul2zum(0UL))){
+ /* *&x durch x ersetzen */
+ np merk;
+ merk=p->left;
+ if(p->ntyp) freetyp(p->ntyp);
+ if(p->left->ntyp) freetyp(p->left->ntyp);
+ *p=*p->left->left;
+ free(merk->left);
+ free(merk);
+ return ok;
+ }
+ /* *&ax durch firstelement-of(x) ersetzen */
+ if(p->left->flags==ADDRESSA||p->left->flags==ADDRESSS){
+ if(!is_vlength(p->left->left->ntyp)){
+ np merk;
+ if(DEBUG&1) printf("substitutet * and %s with FIRSTELEMENT\n",ename[p->left->flags]);
+ p->flags=FIRSTELEMENT;
+ p->lvalue=1; /* evtl. hier erst Abfrage ? */
+ merk=p->left;
+ p->left=merk->left;
+ p->right=merk->right;
+ if(merk->ntyp) freetyp(merk->ntyp);
+ free(merk);
+ }
+ }
+ if (p->ntyp->flags&VOLATILE) p->sidefx=1;
+ return ok;
+ }
+ if(f==FIRSTELEMENT){
+ if(ISARRAY(p->left->ntyp->flags)){
+ p->ntyp=clone_typ(p->left->ntyp->next);
+ }else{
+ int i,n=-1;
+ for(i=0;i<p->left->ntyp->exact->count;i++)
+ if(!strcmp((*p->left->ntyp->exact->sl)[i].identifier,p->right->identifier)) n=i;
+ if(n<0) ierror(0);
+ p->ntyp=clone_typ((*p->left->ntyp->exact->sl)[n].styp);
+ }
+ p->lvalue=1; /* hier noch genauer testen ? */
+ return ok;
+ }
+ if(f==ADDRESS){
+ if(!ISFUNC(p->left->ntyp->flags)&&!ISARRAY(p->left->ntyp->flags)){
+ if(!p->left->lvalue){error(115);return 0;}
+ if(p->left->flags==IDENTIFIER){
+ Var *v;
+ v=find_var(p->left->identifier,0);
+ if(!v){error(116,p->left->identifier);return 0;}
+ if(v->storage_class==REGISTER)
+ {error(117);return 0;}
+ }
+ }
+ p->ntyp=new_typ();
+ p->ntyp->flags=ptype(p->left);
+ p->ntyp->next=clone_typ(p->left->ntyp);
+ fix_addr_ptype(p);
+ return ok;
+ }
+ if(f==ADDRESSA){
+ p->ntyp=clone_typ(p->left->ntyp);
+ p->ntyp->flags=ptype(p->left);
+ fix_addr_ptype(p);
+ return ok;
+ }
+ if(f==ADDRESSS){
+ int i,n=-1;
+ struct_list *sl=0;
+ if(!ecpp){
+ for(i=0;i<p->left->ntyp->exact->count;i++)
+ if(!strcmp((*p->left->ntyp->exact->sl)[i].identifier,p->right->identifier)) n=i;
+ if(n<0)
+ return 0;
+ else
+ sl=&(*p->left->ntyp->exact->sl)[n];
+ }
+#ifdef HAVE_ECPP
+/* 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
+ p->ntyp=new_typ();
+ if(!p->left->ntyp) ierror(0);
+ if(!p->left->ntyp->exact) ierror(0);
+ if(!sl->styp) ierror(0);
+ p->ntyp->next=clone_typ(sl->styp);
+ p->ntyp->flags=ptype(p->left);
+ fix_addr_ptype(p);
+ return ok;
+ }
+ if(f==DSTRUCT){
+ struct_declaration *sd=p->left->ntyp->exact;
+ char *identifier=p->right->identifier;
+ int i=0,f,bfs=-1,bfo=-1;type *t;np new;zmax offset=l2zm(0L);
+ if(!ISSTRUCT(p->left->ntyp->flags)&&!ISUNION(p->left->ntyp->flags))
+ {error(8);return 0;}
+ if(type_uncomplete(p->left->ntyp)){error(11);return 0;}
+ if(p->right->flags!=MEMBER) ierror(0);
+ if(i>=p->left->ntyp->exact->count) {error(23,p->right->identifier);return 0;}
+ if(!ecpp){
+ offset=struct_offset(sd,identifier);
+ }
+#ifdef HAVE_ECPP
+/* 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
+ if(ISUNION(p->left->ntyp->flags)) offset=l2zm(0L);
+ p->flags=CONTENT;
+ if(p->ntyp) {freetyp(p->ntyp);p->ntyp=0;}
+ new=new_node();
+ new->flags=ADD;
+ new->ntyp=0;
+ new->right=new_node();
+ new->right->left=new->right->right=0;
+ new->right->flags=PCEXPR;
+ new->right->ntyp=new_typ();
+ if(/*MINADDI2P<=INT&&*/zumleq(zm2zum(offset),t_max(INT))){
+ new->right->ntyp->flags=INT;
+ new->right->val.vint=zm2zi(offset);
+ }else{
+ new->right->ntyp->flags=LONG;
+ new->right->ntyp->next=0;
+ new->right->val.vlong=zm2zl(offset);
+ }
+ new->left=new_node();
+ new->left->flags=ADDRESSS;
+ new->left->left=p->left;
+ new->left->right=p->right;
+ new->left->ntyp=0;
+ p->left=new;p->right=0;
+
+ /* Check for bitfields */
+ i=0;
+ while(i<sd->count&&strcmp((*sd->sl)[i].identifier,identifier)){
+ i++;
+ }
+ if(i<sd->count){
+ bfo=(*sd->sl)[i].bfoffset;
+ bfs=(*sd->sl)[i].bfsize;
+ }else
+ bfs=-1;
+ if(bfs!=-1){
+ /* create a special node for bitfields */
+ ok|=type_expression2(p,0);
+ new=new_node();
+ *new=*p;
+ p->flags=BITFIELD;
+ p->left=new;
+ p->right=0;
+ p->sidefx=0;
+ p->bfs=bfs;
+ p->bfo=bfo;
+ p->ntyp=clone_typ(new->ntyp);
+ return ok;
+ }
+ return type_expression2(p,0);
+ }
+ if(f==PREINC||f==POSTINC||f==PREDEC||f==POSTDEC){
+ if(!p->left->lvalue){error(86);return 0;}
+ if(p->left->ntyp->flags&CONST){error(87);return 0;}
+ if(!ISARITH(p->left->ntyp->flags)){
+ if(!ISPOINTER(p->left->ntyp->flags)){
+ error(24);
+ return 0;
+ }else{
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ if((p->left->ntyp->next->flags&NQ)==VOID)
+ {error(95);return 0;}
+ }
+ }
+ p->ntyp=clone_typ(p->left->ntyp);
+ p->sidefx=1;
+ return ok;
+ }
+ if(f==CALL){
+ argument_list *al;int i,flags=0;char *s=0;
+ struct_declaration *sd;
+#ifdef HAVE_ECPP
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+/* removed */
+#endif
+ al=p->alist;
+ if(!ISPOINTER(p->left->ntyp->flags)||!ISFUNC(p->left->ntyp->next->flags))
+ {error(26);return 0;}
+ if(ok&&p->left->left&&p->left->left->flags==IDENTIFIER&&p->left->left->o.v->storage_class==EXTERN){
+ s=p->left->left->o.v->identifier;
+ flags=p->left->left->o.v->flags;
+ }
+ sd=p->left->ntyp->next->exact;
+ if(!sd) ierror(0);
+ if(sd->count==0){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ error(162);
+ if(s){
+ if(!strcmp(s,"printf")||!strcmp(s,"fprintf")||!strcmp(s,"sprintf")||
+ !strcmp(s,"scanf")|| !strcmp(s,"fscanf")|| !strcmp(s,"sscanf"))
+ error(213);
+ }
+ }
+ if(!(ecpp&&al&&al->arg->ntyp)){
+ i=0;
+ while(al){
+ if(!al->arg) ierror(0);
+ if(!type_expression2(al->arg,(short_push&&i<sd->count)?(*sd->sl)[i].styp:0)) return 0;
+ al->arg=makepointer(al->arg);
+ if(type_uncomplete(al->arg->ntyp)) error(39);
+ al=al->next;
+ i++;
+ }
+ }
+ p->sidefx=1;
+ p->ntyp=clone_typ(p->left->ntyp->next->next);
+ i=0;al=p->alist;
+ while(al){
+ if(i>=sd->count) return ok;
+ if(!(*sd->sl)[i].styp) return ok; /* nur Bezeichner, aber kein Typ im Prototype */
+ if(!test_assignment((*sd->sl)[i].styp,al->arg)) return 0;
+#ifdef HAVE_MISRA
+/* removed */
+/* removed */
+#endif
+ if(i==sd->count-1&&(flags&(PRINTFLIKE|SCANFLIKE))){
+ if(al->arg->left&&al->arg->left->flags==STRING){
+ /* Argumente anhand des Formatstrings ueberpruefen */
+ const_list *cl=al->arg->left->cl;
+ int fused=0;long mask=1;
+ al=al->next;
+ while(cl&&cl->other){
+ int c,fflags=' ',at,lflag;
+ type *t;
+ enum{LL=1,HH};
+ c=(int)zm2l(zc2zm(cl->other->val.vchar));
+ cl=cl->next;
+ if(c==0){
+ if(cl) error(215);
+ break;
+ }
+ c=CHARBACK(c);
+ if(c!='%') continue;
+ if(!cl){error(214);return ok;}
+ lflag=0;
+ c=(int)zm2l(zc2zm(cl->other->val.vchar));
+ c=CHARBACK(c);
+ cl=cl->next;
+ while(isdigit((unsigned char)c)||
+ c=='-'||c=='+'||c==' '||c=='#'||c=='.'||
+ c=='h'||c=='l'||c=='L'||c=='z'||c=='j'||c=='t'||c=='*'){
+ if(c=='-') mask|=USELALGN;
+ if(c=='+') mask|=USESIGN;
+ if(c=='#') mask|=USEALT;
+ if(c=='.') mask|=USEPREC;
+ if(c==' ') mask|=USEBLANK;
+ if(c=='0'&&!(mask&USEPREC)&&!(mask&USEWIDTH)) mask|=USEZPAD;
+ if(isdigit((unsigned char)c)&&!(mask&USEPREC)) mask|=USEWIDTH;
+ fused|=3;
+ if(c=='*'&&(flags&PRINTFLIKE)){
+ mask|=USEAST;
+ if(!al) {error(214);return ok;}
+ at=al->arg->ntyp->flags&NQ;
+ al=al->next;
+ if(at>INT) {error(214);return ok;}
+ }
+ if((fflags!='*'||(flags&PRINTFLIKE))&&(c=='h'||c=='l'||c=='L'||c=='*'||c=='t'||c=='z'||c=='j')){
+ if(c=='l'&&fflags=='l')
+ fflags=LL;
+ else if(c=='h'&&fflags=='h')
+ fflags=HH;
+ else
+ fflags=c;
+ }
+ c=(int)zm2l(zc2zm(cl->other->val.vchar));
+ c=CHARBACK(c);
+ cl=cl->next;
+ if(!cl){error(214);return ok;}
+ }
+ /*FIXME: assumes intmax_t==long long */
+ if(fflags=='j') {mask|=USESPEC;fflags=LL;}
+#if HAVE_INT_SIZET
+ if(fflags=='z') {mask|=USESPEC;fflags=' ';}
+#else
+ if(fflags=='z') {mask|=USESPEC;fflags='l';}
+#endif
+ if(fflags=='t'){
+ mask|=USESPEC;
+ if(PTRDIFF_T(CHAR)==LLONG)
+ fflags=LL;
+ else if(PTRDIFF_T(CHAR)==LONG)
+ fflags='l';
+ else
+ fflags=' ';
+ }
+ if(fflags==HH) lflag|=USESPEC;
+ if(fflags=='h') lflag|=USEHALF;
+ if(fflags=='l') lflag|=USELONG;
+ if(fflags==LL) lflag|=USELLONG;
+ if(DEBUG&1) printf("format=%c%c\n",fflags,c);
+ if(fflags=='*'&&(flags&SCANFLIKE)) continue;
+ if(c!='%'){
+ if(!al){error(214);return ok;}
+ t=al->arg->ntyp;
+ if(DEBUG&1){ prd(stdout,t);printf("\n");}
+ if((flags&SCANFLIKE)){
+ if(!ISPOINTER(t->flags)){error(214);return ok;}
+ t=t->next;
+ }
+ at=t->flags&NU;
+ }
+ if(flags&PRINTFLIKE){
+ switch(c){
+ case '%':
+ mask|=USEPERC;
+ fused|=1;
+ break;
+ case 'o':
+ case 'x':
+ case 'X':
+ case 'c':
+ at&=NQ; /* fall through */
+ case 'i':
+ case 'd':
+ fused|=1;
+ if(at==LLONG&&fflags!=LL){error(214);return ok;}
+ if(at==LONG&&fflags!='l'){error(214);return ok;}
+ if(fflags=='l'&&at!=LONG){error(214);return ok;}
+ if(at<CHAR||at>LLONG){error(214);return ok;}
+ if(c=='o') mask|=USEOCT;
+ if(c=='x') mask|=USEHEXL;
+ if(c=='X') mask|=USEHEXU;
+ if(c=='i') mask|=USEINT;
+ if(c=='d') mask|=USEDEC;
+ if(c=='c') mask|=USECHAR;
+ mask|=lflag;
+ break;
+ case 'u':
+ mask|=USEUNS;
+ fused|=1;
+ if(al->arg->flags==CEXPR) at|=UNSIGNED;
+ if(at==(UNSIGNED|LLONG)&&fflags!=LL){error(214);return ok;}
+ if(at==(UNSIGNED|LONG)&&fflags!='l'){error(214);return ok;}
+ if(fflags=='l'&&at!=(UNSIGNED|LONG)){error(214);return ok;}
+ if(at<(UNSIGNED|CHAR)||at>(UNSIGNED|LLONG)){error(214);return ok;}
+ mask|=lflag;
+ break;
+ case 's':
+ mask|=USESTR;
+ fused|=1;
+ if(!ISPOINTER(at)||(t->next->flags&NQ)!=CHAR){error(214);return ok;}
+ break;
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ mask|=USEFLOAT;
+ fused|=7;
+ if(fflags=='L'){
+ if(at!=LDOUBLE){error(214); return ok;}
+ }else{
+ if(at!=FLOAT&&at!=DOUBLE){error(214);return ok;}
+ }
+ break;
+ case 'p':
+ mask|=USESPEC;
+ fused|=3;
+ if(!ISPOINTER(at)||(t->next->flags)!=VOID){error(214);return ok;}
+ break;
+ case 'n':
+ mask|=USECNT;
+ fused|=3;
+ if(!ISPOINTER(at)){error(214);return ok;}
+ at=t->next->flags&NU;
+ if(fflags==HH&&at!=CHAR){error(214);return ok;}
+ if(fflags=='h'&&at!=SHORT){error(214);return ok;}
+ if(fflags==' '&&at!=INT){error(214);return ok;}
+ if(fflags=='l'&&at!=LONG){error(214);return ok;}
+ if(fflags==LL&&at!=LLONG){error(214);return ok;}
+ break;
+ default:
+ error(214);return ok;
+ }
+ }else{
+ if(c=='s') mask|=USESTR;
+ if(c=='c') mask|=USECHAR;
+ if(c=='n') mask|=USECNT;
+ if(c=='d') mask|=USEDEC;
+ if(c=='i') mask|=USEINT;
+ if(c=='o') mask|=USEOCT;
+ if(c=='x') mask|=USEHEXL;
+ if(c=='u') mask|=USEUNS;
+
+ switch(c){
+ case '%':
+ mask|=USEPERC;
+ fused|=1;
+ break;
+ case '[':
+ mask|=USEREXP;
+ fused|=3;
+ do{
+ c=(int)zm2l(zc2zm(cl->other->val.vchar));
+ c=CHARBACK(c);
+ cl=cl->next;
+ if(!cl){error(214);return ok;}
+ }while(c!=']'); /* fall through */
+ case 's':
+ case 'c':
+ fused|=1;
+ if((at&NQ)!=CHAR){error(214);return(ok);}
+ break;
+ case 'n':
+ fused|=3; /* fall through */
+ case 'd':
+ case 'i':
+ case 'o':
+ fused|=1;
+ if(fflags==HH&&at!=CHAR){error(214);return ok;}
+ if(fflags=='h'&&at!=SHORT){error(214);return ok;}
+ if(fflags==' '&&at!=INT){error(214);return ok;}
+ if(fflags=='l'&&at!=LONG){error(214);return ok;}
+ if(fflags==LL&&at!=LLONG){error(214);return ok;}
+ break;
+ case 'x':
+ case 'u':
+ fused|=1;
+ if(fflags==HH&&at!=CHAR){error(214);return ok;}
+ if(fflags=='h'&&at!=(UNSIGNED|SHORT)){error(214);return ok;}
+ if(fflags==' '&&at!=(UNSIGNED|INT)){error(214);return ok;}
+ if(fflags=='l'&&at!=(UNSIGNED|LONG)){error(214);return ok;}
+ if(fflags==LL&&at!=(UNSIGNED|LLONG)){error(214);return ok;}
+ break;
+ case 'e':
+ case 'f':
+ case 'g':
+ mask|=USEFLOAT;
+ fused|=7;
+ if(fflags==' '&&at!=FLOAT){error(214);return ok;}
+ if(fflags=='l'&&at!=DOUBLE){error(214);return ok;}
+ if(fflags=='L'&&at!=LDOUBLE){error(214);return ok;}
+ break;
+ case 'p':
+ mask|=USESPEC;
+ fused|=3;
+ if(!ISPOINTER(at)||(t->next->flags&NQ)!=VOID){error(214);return ok;}
+ break;
+ default:
+ error(214);return ok;
+ }
+ }
+ if(c!='%') al=al->next;
+ }
+ if(al){ error(214);return ok;} /* zu viele */
+ if(DEBUG&1) printf("fused=%d\n",fused);
+ if(mask_opt){
+ Var *v;char repl[MAXI+16];
+ if(mask){
+ sprintf(repl,"%s.%lu",s,1L);
+ v=find_var(repl,0);
+ if(!v){
+ type *t;
+ v=find_var(s,0);
+ if(!v) ierror(0);
+ v=add_var(repl,clone_typ(v->vtyp),EXTERN,0);
+ }
+ }
+ if(mask)
+ sprintf(repl,"%s.%lu",(flags&PRINTFLIKE)?"vfprintf":"vfscanf",mask);
+ else
+ sprintf(repl,"%s",(flags&PRINTFLIKE)?"vfprintf":"vfscanf");
+ needs(repl);
+ p->left->left->o.v=v;
+ if(DEBUG&1) printf("repl=%s\n",repl);
+ }else if(fused!=7&&s){
+ /* Wenn kein Format benutzt wird, kann man printf, */
+ /* scanf etc. durch aehnliches ersetzen. */
+ Var *v;char repl[MAXI+6]="__v";
+ if(fused==3) fused=2;
+ repl[3]=fused+'0';repl[4]=0;
+ strcat(repl,s);
+ if(DEBUG&1) printf("repl=%s\n",repl);
+ while(fused<=2){
+ v=find_var(repl,0);
+ if(v&&v->storage_class==EXTERN){
+ p->left->left->o.v=v;
+ break;
+ }
+ fused++;repl[3]++;
+ }
+ }
+ return ok;
+ }
+ }
+ i++;al=al->next;
+ }
+ if(i>=sd->count) return ok;
+ if((*sd->sl)[i].styp&&((*sd->sl)[i].styp->flags&NQ)!=VOID){error(83);/*printf("sd->count=%d\n",sd->count);*/}
+ return ok;
+ }
+ if(f==COND){
+ if(!ISARITH(p->left->ntyp->flags)&&!ISPOINTER(p->left->ntyp->flags)){
+ error(29);
+ return 0;
+ }
+ if(p->left->flags==CEXPR&&!p->left->sidefx){
+ int null;np merk;
+ if(DEBUG&1) printf("constant conditional-expression simplified\n");
+ eval_constn(p->left);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
+ null=1;
+ else
+ null=0;
+ free_expression(p->left);
+ merk=p->right;
+ if(null){
+ free_expression(p->right->left);
+ *p=*p->right->right;
+ }else{
+ free_expression(p->right->right);
+ *p=*p->right->left;
+ }
+ if(merk->ntyp) freetyp(merk->ntyp);
+ free(merk);
+ return 1;
+ }
+ if(const_expr){error(46);return 0;}
+ p->ntyp=clone_typ(p->right->ntyp);
+ return 1;
+ }
+ if(f==COLON){
+ /* Hier fehlt noch korrekte Behandlung der Typattribute */
+ if(ISARITH(p->left->ntyp->flags)&&ISARITH(p->right->ntyp->flags)){
+ p->ntyp=arith_typ(p->left->ntyp,p->right->ntyp);
+ return 1;
+ }
+ if(compatible_types(p->left->ntyp,p->right->ntyp,NQ)){
+ p->ntyp=clone_typ(p->left->ntyp);
+ return 1;
+ }
+ if(ISPOINTER(p->left->ntyp->flags)&&ISPOINTER(p->right->ntyp->flags)){
+ if((p->left->ntyp->next->flags&NQ)==VOID){
+ if(nullpointer(p->left))
+ p->ntyp=clone_typ(p->right->ntyp);
+ else
+ p->ntyp=clone_typ(p->left->ntyp);
+ return 1;
+ }
+ if((p->right->ntyp->next->flags&NQ)==VOID){
+ if(nullpointer(p->right))
+ p->ntyp=clone_typ(p->left->ntyp);
+ else
+ p->ntyp=clone_typ(p->right->ntyp);
+ return 1;
+ }
+ }
+ if(ISPOINTER(p->left->ntyp->flags)&&p->right->flags==CEXPR){
+ eval_constn(p->right);
+ if(zmeqto(vmax,l2zm(0L))&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){
+ p->ntyp=clone_typ(p->left->ntyp);
+ return 1;
+ }
+ }
+ if(ISPOINTER(p->right->ntyp->flags)&&p->left->flags==CEXPR){
+ eval_constn(p->left);
+ if(zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){
+ p->ntyp=clone_typ(p->right->ntyp);
+ return 1;
+ }
+ }
+ error(31);
+ return 0;
+ }
+ if(f) printf("type_testing fuer diesen Operator (%d) noch nicht implementiert\n",f);
+ return 0;
+}
+
+np makepointer(np p)
+/* Fuehrt automatische Zeigererzeugung fuer Baumwurzel durch */
+/* Durch mehrmaligen Aufruf von type_expression() ineffizient */
+{
+ struct_declaration *sd;
+ if(ISARRAY(p->ntyp->flags)||ISFUNC(p->ntyp->flags)){
+ np new=new_node();
+ if(ISARRAY(p->ntyp->flags)){
+ new->flags=ADDRESSA;
+ new->ntyp=clone_typ(p->ntyp);
+ new->ntyp->flags=POINTER_TYPE(new->ntyp->next);
+ }else{
+ new->flags=ADDRESS;
+ new->ntyp=new_typ();
+ new->ntyp->flags=POINTER_TYPE(p->ntyp);
+ new->ntyp->next=clone_typ(p->ntyp);
+ }
+ new->left=p;
+ new->right=0;
+ new->lvalue=0; /* immer korrekt ? */
+ new->sidefx=p->sidefx;
+/* type_expression(new);*/
+ return new;
+ }else
+ return p;
+}
+
+void simple_alg_opt(np p)
+{
+ int c=0,f,t=0;
+ zldouble d1,d2;
+ zumax u1,u2;zmax s1,s2;
+ Var *v;
+
+ if(!p) return;
+
+ f=p->flags;
+
+ if(f==IDENTIFIER&&(v=find_var(p->identifier,0))&&(v->vtyp->flags&NQ)==ENUM){
+ /* enumerations auch als Konstante (int) behandeln */
+ p->flags=CEXPR;
+ if(!v->clist) ierror(0);
+ p->val=v->clist->val;
+ if(!p->ntyp) p->ntyp=new_typ();
+ p->ntyp->flags=CONST|INT;
+ return;
+ }
+
+
+ if(p->left)
+ simple_alg_opt(p->left);
+ else
+ return;
+ if(p->right)
+ simple_alg_opt(p->right);
+
+ if(p->left->flags==CEXPR||p->left->flags==PCEXPR){
+ eval_constn(p->left);
+ d1=vldouble;u1=vumax;s1=vmax;c|=1;
+ }
+ if(p->right&&(p->right->flags==CEXPR||p->right->flags==PCEXPR)){
+ eval_constn(p->right);
+ d2=vldouble;u2=vumax;s2=vmax;c|=2;
+ }
+
+ if(p->ntyp) t=p->ntyp->flags;
+
+ if(c==3&&((f>=OR&&f<=AND)||(f>=LSHIFT&&f<=MOD))){
+ if(DEBUG&1) printf("did simple_alg constant folding\n");
+ if(!t) t=arith_flag(p->left->ntyp->flags,p->right->ntyp->flags);
+ if(DEBUG&1) printf("did simple constant folding\n");
+
+ if(f==AND&&ISINT(t)){
+ vumax=zumand(u1,u2);
+ vmax=zmand(s1,s2);
+ }
+ if(f==OR&&ISINT(t)){
+ vumax=zumor(u1,u2);
+ vmax=zmor(s1,s2);
+ }
+ if(f==XOR&&ISINT(t)){
+ vumax=zumxor(u1,u2);
+ vmax=zmxor(s1,s2);
+ }
+ if(f==ADD){
+ vumax=zumadd(u1,u2);
+ vmax=zmadd(s1,s2);
+ vldouble=zldadd(d1,d2);
+ }
+ if(f==SUB){
+ vumax=zumsub(u1,u2);
+ vmax=zmsub(s1,s2);
+ vldouble=zldsub(d1,d2);
+ }
+ if(f==MULT||f==PMULT){
+ vumax=zummult(u1,u2);
+ vmax=zmmult(s1,s2);
+ vldouble=zldmult(d1,d2);
+ if(f==PMULT) p->flags=PCEXPR;
+ }
+ if(f==DIV){
+ if(zmeqto(l2zm(0L),s2)&&zumeqto(ul2zum(0UL),u2)&&zldeqto(d2zld(0.0),d2)){
+ error(84);
+ vmax=l2zm(0L);vumax=ul2zum(0UL);vldouble=d2zld(0.0);
+ }else{
+ if(!zumeqto(ul2zum(0UL),u2)) vumax=zumdiv(u1,u2);
+ if(!zmeqto(l2zm(0L),s2)) vmax=zmdiv(s1,s2);
+ if(!zldeqto(d2zld(0.0),d2)) vldouble=zlddiv(d1,d2);
+ }
+ }
+ if(f==MOD&&ISINT(t)){
+ if(zmeqto(l2zm(0L),s2)&&zumeqto(ul2zum(0UL),u2)){
+ error(84);
+ vmax=l2zm(0L);vumax=zm2zum(vmax);
+ }else{
+ if(!zumeqto(ul2zum(0UL),u2)) vumax=zummod(u1,u2);
+ if(!zmeqto(l2zm(0L),s2)) vmax=zmmod(s1,s2);
+ }
+ }
+ if(f==LSHIFT&&ISINT(t)){
+ vumax=zumlshift(u1,u2);
+ vmax=zmlshift(s1,s2);
+ }
+ if(f==RSHIFT&&ISINT(t)){
+ vumax=zumrshift(u1,u2);
+ vmax=zmrshift(s1,s2);
+ }
+ }else if(c==1&&f==MINUS){
+ if(!t) t=arith_flag(p->left->ntyp->flags,p->left->ntyp->flags);
+ vmax=zmsub(Z0,s1);
+ vumax=zumsub(ZU0,u1);
+ vldouble=zldsub(d2zld(0.0),d1);
+ }else if(c==1&&f==KOMPLEMENT){
+ if(!t) t=arith_flag(p->left->ntyp->flags,p->left->ntyp->flags);
+ if(!ISINT(t)) return;
+ vmax=zmkompl(s1);
+ vumax=zumkompl(u1);
+ }else if(c==1&&f==NEGATION){
+ if(!p->left->ntyp) return;
+ t=INT;
+ if(!ISINT(p->left->ntyp->flags)){
+ if(zldeqto(d1,d2zld(0.0))) vmax=Z1; else vmax=Z0;
+ }else if(p->left->ntyp->flags&UNSIGNED){
+ if(zumeqto(u1,ZU0)) vmax=Z1; else vmax=Z0;
+ }else
+ if(zmeqto(s1,Z0)) vmax=Z1; else vmax=Z0;
+ }else
+ return;
+
+ p->flags=CEXPR;
+ if(p->left&&!p->left->sidefx) {free_expression(p->left);p->left=0;}
+ if(p->right&&p->right->sidefx) {free_expression(p->right);p->right=0;}
+
+ if(ISFLOAT(t)){
+ gval.vldouble=vldouble;
+ eval_const(&gval,LDOUBLE);
+ }else{
+ if(t&UNSIGNED){
+ gval.vumax=vumax;
+ eval_const(&gval,(UNSIGNED|MAXINT));
+ }else{
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ }
+ }
+ insert_const(&p->val,t);
+ if(!p->ntyp){p->ntyp=new_typ();p->ntyp->flags=t;}
+}
+
+
+int alg_opt(np p,type *ttyp)
+/* fuehrt algebraische Vereinfachungen durch */
+/* hier noch genau testen, was ANSI-gemaess erlaubt ist etc. */
+/* v.a. Floating-Point ist evtl. kritisch */
+{
+ int c=0,f,komm,null1,null2,eins1,eins2;np merk;
+ zldouble d1,d2;zumax u1,u2;zmax s1,s2;
+ f=p->flags;
+
+ /* do not optimze pointer-pointer */
+ if(f==SUB&&ISPOINTER(p->left->ntyp->flags)&&ISPOINTER(p->right->ntyp->flags))
+ return 1;
+
+ /* kommutativ? */
+ if(f==ADD||f==MULT||f==PMULT||(f>=OR&&f<=AND)) komm=1; else komm=0;
+ /* Berechnet Wert, wenn beides Konstanten sind */
+ if(p->left->flags==CEXPR||p->left->flags==PCEXPR){
+ eval_constn(p->left);
+ d1=vldouble;u1=vumax;s1=vmax;c|=1;
+ }
+ if(p->right->flags==CEXPR||p->right->flags==PCEXPR){
+ eval_constn(p->right);
+ d2=vldouble;u2=vumax;s2=vmax;c|=2;
+ }
+ if(c==3){
+ p->flags=CEXPR;
+ if(DEBUG&1) printf("did simple constant folding\n");
+ if(!p->left->sidefx) {free_expression(p->left);p->left=0;}
+ if(!p->right->sidefx) {free_expression(p->right);p->right=0;}
+ if(f==AND){
+ vumax=zumand(u1,u2);
+ vmax=zmand(s1,s2);
+ }
+ if(f==OR){
+ vumax=zumor(u1,u2);
+ vmax=zmor(s1,s2);
+ }
+ if(f==XOR){
+ vumax=zumxor(u1,u2);
+ vmax=zmxor(s1,s2);
+ }
+ if(f==ADD){
+ vumax=zumadd(u1,u2);
+ vmax=zmadd(s1,s2);
+ vldouble=zldadd(d1,d2);
+ }
+ if(f==SUB){
+ vumax=zumsub(u1,u2);
+ vmax=zmsub(s1,s2);
+ vldouble=zldsub(d1,d2);
+ }
+ if(f==MULT||f==PMULT){
+ vumax=zummult(u1,u2);
+ vmax=zmmult(s1,s2);
+ vldouble=zldmult(d1,d2);
+ if(f==PMULT) p->flags=PCEXPR;
+ }
+ if(f==DIV){
+ if(zmeqto(l2zm(0L),s2)&&zumeqto(ul2zum(0UL),u2)&&zldeqto(d2zld(0.0),d2)){
+ error(84);
+ vmax=l2zm(0L);vumax=ul2zum(0UL);vldouble=d2zld(0.0);
+ }else{
+ if(!zumeqto(ul2zum(0UL),u2)) vumax=zumdiv(u1,u2);
+ if(!zmeqto(l2zm(0L),s2)) vmax=zmdiv(s1,s2);
+ if(!zldeqto(d2zld(0.0),d2)) vldouble=zlddiv(d1,d2);
+ }
+ }
+ if(f==MOD){
+ if(zmeqto(l2zm(0L),s2)&&zumeqto(ul2zum(0UL),u2)){
+ error(84);
+ vmax=l2zm(0L);vumax=zm2zum(vmax);
+ }else{
+ if(!zumeqto(ul2zum(0UL),u2)) vumax=zummod(u1,u2);
+ if(!zmeqto(l2zm(0L),s2)) vmax=zmmod(s1,s2);
+ }
+ }
+ if(f==LSHIFT){
+ vumax=zumlshift(u1,u2);
+ vmax=zmlshift(s1,s2);
+ }
+ if(f==RSHIFT){
+ vumax=zumrshift(u1,u2);
+ vmax=zmrshift(s1,s2);
+ }
+ if(ISFLOAT(p->ntyp->flags)){
+ gval.vldouble=vldouble;
+ eval_const(&gval,LDOUBLE);
+ }else{
+ if(p->ntyp->flags&UNSIGNED){
+ gval.vumax=vumax;
+ eval_const(&gval,(UNSIGNED|MAXINT));
+ }else{
+ gval.vmax=vmax;
+ eval_const(&gval,MAXINT);
+ }
+ }
+ insert_constn(p);
+ return 1;
+ }
+ /* Konstanten nach rechts, wenn moeglich */
+ if(c==1&&komm){
+ if(DEBUG&1) printf("exchanged commutative constant operand\n");
+ merk=p->left;p->left=p->right;p->right=merk;
+ c=2;
+ d2=d1;u2=u1;s2=s1;
+ }
+ /* Vertauscht die Knoten, um Konstanten */
+ /* besser zusammenzufassen (bei allen Type erlaubt?) */
+ /* Hier muss noch einiges kontrolliert werden */
+ if(komm&&c==2&&p->flags==p->left->flags&&(ISINT(p->ntyp->flags)||c_flags[21]&USEDFLAG)){
+ if(p->left->right->flags==CEXPR||p->left->right->flags==PCEXPR){
+ np merk;
+ merk=p->right;p->right=p->left->left;p->left->left=merk;
+ if(DEBUG&1) printf("Vertausche Add-Nodes\n");
+ dontopt=0;
+ return type_expression2(p,ttyp);
+ }
+ }
+ null1=null2=eins1=eins2=0;
+ if(c&1){
+ if(zldeqto(d1,d2zld(0.0))&&zumeqto(u1,ul2zum(0UL))&&zmeqto(s1,l2zm(0L))) null1=1;
+ if(zldeqto(d1,d2zld(1.0))&&zumeqto(u1,ul2zum(1UL))&&zmeqto(s1,l2zm(1L))) eins1=1;
+ if(!(p->ntyp->flags&UNSIGNED)&&zldeqto(d1,d2zld(-1.0))&&zmeqto(s1,l2zm(-1L))) eins1=-1;
+ }
+ if(c&2){
+ if(zldeqto(d2,d2zld(0.0))&&zumeqto(u2,ul2zum(0UL))&&zmeqto(s2,l2zm(0L))) null2=1;
+ if(zldeqto(d2,d2zld(1.0))&&zumeqto(u2,ul2zum(1UL))&&zmeqto(s2,l2zm(1L))) eins2=1;
+ if(!(p->ntyp->flags&UNSIGNED)&&zldeqto(d2,d2zld(-1.0))&&zmeqto(s2,l2zm(-1L))) eins2=-1;
+ }
+ if(c==2){
+ /* a+0=a-0=a^0=a>>0=a<<0=a*1=a/1=a */
+ if(((eins2==1&&(f==MULT||f==PMULT||f==DIV))||(null2&&(f==ADD||f==SUB||f==OR||f==XOR||f==LSHIFT||f==RSHIFT)))&&!p->right->sidefx){
+ if(DEBUG&1){if(f==MULT||f==PMULT||f==DIV) printf("a*/1->a\n"); else printf("a+-^0->a\n");}
+ free_expression(p->right);
+ merk=p->left;
+ *p=*p->left;
+/* freetyp(merk->ntyp); das war Fehler */
+ free(merk);
+ dontopt=0;
+ return type_expression2(p,ttyp);
+ }
+ /* a*0=0 */
+ if(null2&&(f==MULT||f==PMULT||f==AND||f==DIV||f==MOD)){
+ if(DEBUG&1) printf("a*&/%%0->0\n");
+ if(null2&&(f==DIV||f==MOD)) error(84);
+ if(p->flags==PMULT) p->flags=PCEXPR; else p->flags=CEXPR;
+ gval.vint=zm2zi(l2zm(0L));
+ eval_const(&gval,INT);
+ /* hier nur int,long,float,double moeglich, hoffe ich */
+ insert_constn(p);
+ if(!p->left->sidefx){free_expression(p->left);p->left=0;} else make_cexpr(p->left);
+ if(!p->right->sidefx){free_expression(p->right);p->right=0;} else make_cexpr(p->right);
+
+/* return(type_expression2(p,ttyp)); */
+ return 1;
+ }
+ if(eins2==-1&&(f==MULT||f==PMULT||f==DIV)&&!p->right->sidefx){
+ if(DEBUG&1) printf("a*/(-1)->-a\n");
+ free_expression(p->right);
+ p->right=0;
+ p->flags=MINUS;
+ dontopt=0;
+ return type_expression2(p,ttyp);
+ }
+ /* check volatile */
+ if(0) /* TODO: make this efficient */
+ {
+ type st={0};
+ if(!zmeqto(sizetab[CHAR],sizetab[SHORT])){
+ //if(f==AND&&(!ttyp||(ttyp->flags&NQ)>CHAR)&&shortcut(AND,CHAR)&&zumleq(u2,t_max[CHAR]))
+ //st.flags=CHAR;
+ if(f==AND&&(!ttyp||(ttyp->flags&NQ)>CHAR)/*&&(p->ntyp->flags&UNSIGNED)*/&&shortcut(AND,UNSIGNED|CHAR)&&zumleq(u2,tu_max[CHAR]))
+ st.flags=UNSIGNED|CHAR;
+ }
+ if(!zmeqto(sizetab[SHORT],sizetab[INT])){
+ //if(f==AND&&(!ttyp||(ttyp->flags&NQ)>SHORT)&&shortcut(AND,SHORT)&&zumleq(s2,t_max[SHORT]))
+ //st.flags=SHORT;
+ if(f==AND&&(!ttyp||(ttyp->flags&NQ)>SHORT)/*&&(p->ntyp->flags&UNSIGNED)*/&&shortcut(AND,UNSIGNED|SHORT)&&zumleq(u2,tu_max[SHORT]))
+ st.flags=UNSIGNED|SHORT;
+ }
+ //if(!ttyp&&(p->left->ntyp->flags&NQ)>INT) st.flags=0;
+ if(st.flags){
+ int ret;type *otyp;np n;
+ if(!p->ntyp) ierror(0);
+ otyp=clone_typ(p->ntyp);
+ n=new_node();
+ n->left=p->left;
+ n->right=0;
+ n->flags=CAST;
+ n->ntyp=clone_typ(&st);
+ eval_const(&p->right->val,p->right->ntyp->flags);
+ p->right->ntyp->flags=st.flags;
+ insert_const(&p->right->val,st.flags);
+ p->left=n;
+ n=new_node();
+ *n=*p;
+ p->left=n;
+ p->right=0;
+ p->flags=CAST;
+ p->ntyp=otyp;
+ ret=type_expression2(p->left,&st);
+
+ return ret;
+ }
+ }
+
+ }
+ if(c==1){
+ /* 0-a=-a */
+ if(f==SUB&&null1&&!p->left->sidefx){
+ if(DEBUG&1) printf("0-a->-a\n");
+ free_expression(p->left);
+ p->flags=MINUS;
+ p->left=p->right;
+ p->right=0;
+ dontopt=0;
+ return type_expression2(p,ttyp);
+ }
+ /* 0/a=0 */
+ if(null1&&(f==DIV||f==MOD||f==LSHIFT||f==RSHIFT)){
+ if(DEBUG&1) printf("0/%%<<>>a->0\n");
+ p->flags=CEXPR;
+ gval.vint=zm2zi(l2zm(0L));
+ eval_const(&gval,INT);
+ insert_constn(p);
+ if(!p->left->sidefx){free_expression(p->left);p->left=0;}else make_cexpr(p->left);
+ if(!p->right->sidefx){free_expression(p->right);p->right=0;} else make_cexpr(p->right);
+ dontopt=0;
+ return type_expression2(p,ttyp);
+ }
+ }
+ return 1;
+}
+void make_cexpr(np p)
+/* Macht aus einem Knoten, der durch constant-folding ueberfluessig */
+/* wurde, eine PCEXPR, sofern er keine Nebenwirkungen von sich aus */
+/* erzeugt. Hier noch ueberpruefen, ob CEXPR besser waere. */
+/* Fuehrt rekursiven Abstieg durch. Ist das so korrekt? */
+{
+ int f=p->flags;
+ if(f!=ASSIGN&&f!=ASSIGNOP&&f!=CALL&&f!=POSTINC&&f!=POSTDEC&&f!=PREINC&&f!=PREDEC&&f!=LAND&&f!=LOR){
+ p->flags=PCEXPR;
+ if(p->left) make_cexpr(p->left);
+ if(p->right) make_cexpr(p->right);
+ }
+}
+int test_assignment(type *zt,np q)
+/* testet, ob q an Typ z zugewiesen werden darf */
+{
+ type *qt=q->ntyp;
+ if(ISARITH(zt->flags)&&ISARITH(qt->flags)){
+ if(ISINT(zt->flags)&&ISINT(qt->flags)&&
+ !zmleq(sizetab[qt->flags&NQ],sizetab[zt->flags&NQ])&&q->flags!=CEXPR){
+#ifdef HAVE_MISRA
+/* removed */
+#endif
+ error(166);
+ }
+ if(q->flags==CEXPR){
+ zmax ms,ns;zumax mu,nu;
+ eval_constn(q);
+ ms=vmax;mu=vumax;
+ insert_const(&gval,zt->flags&~UNSIGNED);
+ eval_const(&gval,zt->flags&~UNSIGNED);
+ ns=vmax;
+ eval_constn(q);
+ insert_const(&gval,zt->flags|UNSIGNED);
+ eval_const(&gval,zt->flags|UNSIGNED);
+ nu=vumax;
+ if(!zumeqto(nu,mu)&&!zmeqto(ns,ms))
+ error(363);
+ else{
+ if(zt->flags&UNSIGNED){
+ if(!zumeqto(nu,mu))
+ error(362);
+ }else{
+ if(!zmeqto(ns,ms))
+ error(362);
+ }
+ }
+ }
+ return 1;
+ }
+ if((ISSTRUCT(zt->flags)&&ISSTRUCT(qt->flags))||
+ (ISUNION(zt->flags)&&ISUNION(qt->flags))){
+ if(!compatible_types(zt,qt,NU)){
+ error(38);
+ return 0;
+ }else
+ return 1;
+ }
+ if(ISVECTOR(zt->flags)&&(zt->flags&NU)==(qt->flags&NU)){
+ return 1;
+ }
+ if(ISPOINTER(zt->flags)&&ISPOINTER(qt->flags)){
+ if((zt->next->flags&NQ)==VOID&&!ISFUNC(qt->next->flags)) return 1;
+ if((qt->next->flags&NQ)==VOID&&!ISFUNC(qt->next->flags)) return 1;
+ if(!compatible_types(zt->next,qt->next,(c_flags[7]&USEDFLAG)?NU:NQ)){
+ if(!ecpp){
+ error(85);
+ }
+#ifdef HAVE_ECPP
+/* 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
+ }else{
+ if((qt->next->flags&CONST)&&!(zt->next->flags&CONST))
+ error(91);
+ if((qt->next->flags&VOLATILE)&&!(zt->next->flags&VOLATILE))
+ error(100);
+ if((qt->next->flags&RESTRICT)&&!(zt->next->flags&RESTRICT))
+ error(298);
+ if(qt->next->next&&zt->next->next&&!compatible_types(zt->next->next,qt->next->next,NU))
+ error(110);
+ }
+ return 1;
+ }
+ if(ISPOINTER(zt->flags)&&q->flags==CEXPR){
+ eval_constn(q);
+ if(!(zldeqto(d2zld(0.0),vldouble)&&zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)))
+ error(113);
+ return 1;
+ }
+ error(39);
+ return 0;
+}
+#ifdef HAVE_ECPP
+/* 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 */
+/* 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/ucpp/README b/ucpp/README
new file mode 100755
index 0000000..64ce2ac
--- /dev/null
+++ b/ucpp/README
@@ -0,0 +1,752 @@
+ucpp-1.0 is a C preprocessor mostly compliant to ISO-C99.
+
+Author: Thomas Pornin <thomas.pornin@ens.fr>
+Main site: http://www.di.ens.fr/~pornin/ucpp/
+
+
+
+INTRODUCTION
+------------
+
+A C preprocessor is a part of a C compiler responsible for macro
+replacement, conditional compilation and inclusion of header files.
+It is often found as a stand-alone program on Unix systems.
+
+Ucpp is such a preprocessor; it is designed to be quick and light,
+but anyway fully compliant to the ISO standard 9899:1999, also known
+as C99. Ucpp can be compiled as a stand-alone program, or linked to
+some other code; in the latter case, ucpp will output tokens, one
+at a time, on demand, as an integrated lexer.
+
+Ucpp operates in two modes:
+-- lexer mode: ucpp is linked to some other code and outputs a stream of
+tokens (each call to the lex() function will give one token)
+-- non-lexer mode: ucpp preprocesses text and outputs the resulting text
+on a file descriptor; if linked to some other code, the cpp() function
+must be called repeatedly, otherwise ucpp is a stand-alone binary.
+
+
+
+INSTALLATION
+------------
+
+1. Uncompress the archive file and extract the source files.
+
+2. Edit tune.h. Here is a short explanation of compile-time options:
+
+ LOW_MEM
+ Enable memory-saving functions; this is for low-end and old systems,
+ but seems to be good for larger systems too. Keep it.
+ NO_LIBC_BUF
+ NO_UCPP_BUF
+ Two options used to disable the two bufferings inside ucpp. Define
+ both options for maximum memory saving but you will probably want
+ to keep libc buffering if you want decent performance. Define none
+ on large systems (modern 32 or 64-bit systems).
+ UCPP_MMAP
+ With this option, if ucpp internal buffering is active, ucpp will
+ try to mmap() the input files. This might give a slight performance
+ improvement, but will work only on a limited set of architectures.
+ PRAGMA_TOKENIZE
+ Make ucpp generate tokenized PRAGMA tokens on #pragma and _Pragma();
+ tokenization is made this way: tokens are assembled as a null
+ terminated array of unsigned chars; if a token has a string value
+ (as defined by the STRING_TOKEN macro), the value follows the token,
+ terminated by PRAGMA_TOKEN_END (by default, a newline character cast
+ to unsigned char). Whitespace tokens are skipped. The "name" value
+ of the PRAGMA token is a pointer to that array. This setting is
+ irrelevant in non-lexer mode.
+ PRAGMA_DUMP
+ In non-lexer mode, keep #pragma in output; non-void _Pragma() are
+ translated to the equivalent #pragma. Irrelevant in lexer mode.
+ NO_PRAGMA_IN_DIRECTIVE
+ Do not evaluate _Pragma() inside #if, #include, #include_next and #line
+ directives; instead, emit an error (since the remaining _Pragma will
+ surely imply a syntax error).
+ INMACRO_FLAG
+ In lexer mode, set the inmacro flag to 1 if the current token comes
+ from a macro replacement, 0 otherwise. macro_count maintains an
+ increasing counter of such replacements. CONTEXT tokens count as
+ one macro replacement each. #pragma, and _Pragma() that do not come
+ from a macro replacement, also count as one macro replacement each.
+ This setting is irrelevant in non-lexer mode.
+ STD_INCLUDE_PATH
+ Default include path in stand-alone ucpp.
+ STD_MACROS
+ Default predefined macros in stand-alone ucpp.
+ STD_ASSERT
+ Default assertions in stand-alone ucpp.
+ NATIVE_INTMAX
+ NATIVE_UINTMAX
+ SIMUL_UINTMAX
+ WCHAR_SIGNEDNESS
+ Those options define how #if expressions are evaluated; see the
+ cross-compilation section of this file for more info.
+ DEFAULT_LEXER_FLAGS
+ DEFAULT_CPP_FLAGS
+ Default flags in respectively lexer and non-lexer modes.
+ POSIX_JMP
+ Define this if your architecture defines sigsetjmp() and
+ siglongjmp(); it is known to (very slightly) improve performance
+ on AIX systems.
+ MAX_CHAR_VAL
+ Ucpp will consider characters whose value is equal or above
+ MAX_CHAR_VAL as outside the C source charset (so they will be
+ treated just like '@', for instance). For ASCII systems, 128
+ is fine. 256 is a safer value, but uses more (static) memory.
+ For performance reasons, use a power of two. If MAX_CHAR_VAL is
+ correctly adjusted, ucpp should be compatible with any character
+ set.
+ UNBREAKABLE_SPACE
+ If you want an extra-whitespace character, define this macro to that
+ character. For instance, define this to 160 on an ISO-8859-1 system
+ if you want the 'unbreakable space' to be considered as whitespace.
+ SEMPER_FIDELIS
+ With this option set, ucpp, when used as a lexer, will pass
+ whitespace tokens to its caller, and those tokens will have their
+ true content; this is intended for reconstruction of the source
+ line. Beware that some comments may have embedded newlines.
+ COPY_LINE_LENGTH
+ Ucpp can maintain a copy of the current source line, up to that
+ length. Irrelevant to stand-alone version.
+ *_MEMG
+ Those settings modify ucpp behaviour, wrt memory allocations. With
+ higher values, ucpp will perform less malloc() calls and will run
+ faster, but it will use more memory. Reduce INPUT_BUF_MEMG and
+ OUTPUT_BUF_MEMG on low-memory systems, if you kept ucpp buffering
+ (see NO_UCPP_BUF option).
+
+3. Edit the Makefile. You should define the variables CC and FLAGS;
+ there are the following options:
+
+ -DAUDIT
+ Enable internal sanity checks; this slows down a bit ucpp. Do not
+ define unless you plan to debug ucpp.
+ -DMEM_CHECK
+ With this setting, ucpp will check for the return value of malloc()
+ and exit with a diagnostic when out of memory. MEM_CHECK is implied
+ by AUDIT.
+ -DINLINE=foobar
+ The ucpp code uses "inline" qualifier for some functions; by
+ default, that qualifier is macro-replaced with nothing. Define
+ INLINE to the correct replacement for your compiler, if supported.
+ Note that all "inline" functions in ucpp are also "static". For any
+ C99-compliant compiler, the GNU compiler (gcc), and the Compaq C
+ compiler under Linux/Alpha, no -DINLINE is needed (see tune.h for
+ details).
+
+4. Compile by typing "make". This should produce the ucpp executable
+ file.
+
+5. Install wherever you want the binary and the man page ucpp.1.
+
+6. If you do not have the make utility, compile each file seperately
+ and link them together. The exact details depend on your compiler.
+ You must define the macro STAND_ALONE when compiling cpp.c (there
+ is such a definition, commented out, in cpp.c, line 34).
+
+There is no "configure" script since:
+-- I do not like the very idea of a "configure" script.
+-- Ucpp is written in ANSI-C and should be fairly portable.
+-- There is no such thing as "standard" settings for a C preprocessor.
+ The predefined system macros, standard assertions,... must be tuned
+ by the sysadmin.
+-- The primary goal of ucpp is to be included in compilers. The
+ stand-alone version is mainly a debugging tool.
+
+Please note that you need an ISO-C90 (formerly ANSI) C compiler suite
+(including the standard library) to compile ucpp. If your compiler is
+not C99 (or later), read the cross-compilation section in this README
+file.
+
+The C90 and C99 standards state that external linkage names might
+be considered equal or different based upon only their first 6
+characters; this rule might make ucpp not to compile on a conformant C
+implementation. I have yet to see such an implementation, however.
+
+If you want to use ucpp as an integrated preprocessor and lexer, see the
+section REUSE. Compiling ucpp as a library is an exercise left to the
+reader.
+
+With the LOW_MEM code enabled, ucpp can run on a Minix-86 or Msdos
+16-bit small-memory-model machine. It will not be fully compliant
+on such an architecture to C99, since C99 states that at least one
+source code with 4095 simultaneously defined macros must be processed;
+ucpp will be limited to about 1500 macros (at most) due to memory
+restrictions. At least ucpp can preprocess its own code in these
+conditions. LOW_MEM is on by default because it seems to improve
+performance on large systems.
+
+
+
+LICENSE
+-------
+
+The copyright notice and license is at the beginning of the Makefile and
+each source file. It is basically a BSD license, without the advertising
+subclause (which BSD dropped recently anyway) and with no reference to
+Berkeley (since the code is all mine, written from scratch). Informally,
+this means that you can reuse and redistribute the code as you want,
+provided that you states in the documentation (or any substantial part
+of the software) of redistributed code that I am the original author.
+(If you press a cdrom with 200 software packages, I do not insist on
+having my name on the cover of the cdrom -- just keep a Readme file
+somewhere on the cdrom, with the copyright notice included)
+
+As a courteous gesture, if you reuse my code, please drop me a mail.
+It raises my self-esteem.
+
+
+
+REUSE
+-----
+
+The code has been thought as part of a bigger project; it might be
+used as an integrated lexer, that will read files, process them as a
+C preprocessor, and output a stream of C tokens. To include this code
+into a project, compile with STAND_ALONE undefined.
+
+To use the preprocessor and lexer, several steps should be performed.
+See the file 'sample.c' for an example.
+
+1. call init_cpp(). This function initializes the lexer automaton.
+
+2. set the following global variables:
+ no_special_macros
+ non-zero if the special macros (__FILE__ and others)
+ should not be defined. This is a global flag since
+ it affects the redefinition of such macros (which are
+ allowed if the special macros are not defined)
+ c99_compliant
+ if non-zero, define __STDC_VERSION__ to 199901L; this
+ is the default; otherwise, do not define __STDC_VERSION__.
+ Note that ucpp will accept to undefine __STDC_VERSION__
+ with a #undef directive.
+ c99_hosted
+ if strictly positive, define __STDC_HOSTED__ to 1.
+ If zero, define __STDC_HOSTED__ to 0. If negative,
+ do not define __STDC_HOSTED__. The default is 1.
+ emit_defines and emit_assertions should be set to 0 for
+ the step 3.
+
+3. call init_tables(). This function initializes the macro table
+ and other things; it will intialize assertions if it has a non-zero
+ argument.
+
+4. call init_include_path(). This function will reset the include
+ path to the list of paths given as argument.
+
+5. set the following global variables
+ emit_dependencies
+ set to 1 if dependencies should be emitted during
+ preprocessing
+ set to 2 if dependencies should also be emitted for
+ system include files
+ emit_defines
+ set to non-zero if #define macro definitions should be
+ emitted when macros are defined
+ emit_assertions
+ set to non-zero if #define macro definitions should be
+ emitted when macros are defined
+ emit_output
+ the FILE * where the above items are sent if one of the
+ three emit_ variables is set to non zero
+ transient_characters
+ this is for some cross-compilation; see the relevant
+ part in this README file for details
+
+6. call set_init_filename() with the initial filename as argument;
+ the second argument indicates whether the filename is real or
+ conventional ("real" means "an fopen() on it will work").
+
+7. initialize your struct lexer_state:
+ call init_lexer_state()
+ call init_lexer_mode() if the preprocessor is supposed to
+ output a list of tokens, otherwise set the flags field
+ to DEFAULT_CPP_FLAGS and set the output field to the
+ FILE * where output should be sent
+ (init_lexer_mode(), if called at all, must be called after
+ init_lexer_state())
+ adjust the flags field; here is the meaning of flags:
+
+WARN_STANDARD
+ emit the standard warnings
+WARN_ANNOYING
+ emit the useless and annoying warnings
+WARN_TRIGRAPHS
+ count trigraphs encountered; it is up to the caller to emit
+ a warning if some trigraphs were indeed encountered; the count
+ is stored in the count_trigraphs field of the struct lexer_state
+WARN_TRIGRAPHS_MORE
+ emit a warning for every trigraph encountered
+WARN_PRAGMA
+ emit a warning for each non-void _Pragma encountered in non-lexer
+ mode (because these are not dumped in the output) and for each
+ #pragma too, if ucpp was compiled without PRAGMA_DUMP
+FAIL_SHARP
+ emit errors on '#' tokens beginning a line and not followed
+ by a valid cpp directive
+CCHARSET
+ emit errors when non-C characters are encountered; if this flag
+ is not set, each non-C character will be considered as a BUNCH
+ token (since C99 states that non-C characters are allowed as
+ long as they "disappear" during preprocessing [through macro
+ replacement and stringification for instance], this flag must
+ not be set, for maximum C99 compliance)
+DISCARD_COMMENTS
+ do not keep comments in output (irrelevant in lexer mode)
+CPLUSPLUS_COMMENTS
+ understand new style comments (//) (mandatory for C99)
+LINE_NUM
+ emit #line directives when entering a file, if not in lexer mode;
+ emit CONTEXT token in lexer mode for #line and new files
+GCC_LINE_NUM
+ if LINE_NUM is set, emit gcc-like directives instead of #line
+HANDLE_ASSERTIONS
+ understand assertions in #if expressions (and #assert, #unassert)
+HANDLE_PRAGMA
+ make PRAGMA tokens for #pragma; irrelevant in non-lexer mode
+ (handling of some pragmas is required in C99 but is not of
+ the competence of the preprocessor; without this flag, ucpp will
+ ignore the contents of #pragma and _Pragma directives)
+MACRO_VAARG
+ understand macros with a variable number of arguments (mandatory
+ for C99)
+UTF8_SOURCE
+ understand UTF-8 encoding: multibyte characters are considered
+ equivalent to letters as far as syntax is concerned (they can
+ be used in identifiers)
+LEXER
+ act as a lexer, outputting tokens
+TEXT_OUTPUT
+ this flag should be set to 0 if ucpp works as a lexer, 1 otherwise.
+ It is somehow redundant with the LEXER flag, but the presence of
+ those two different flags is needed in ucpp.
+KEEP_OUTPUT
+ in non-lexer mode, emit the result of preprocessing
+COPY_LINE
+ maintain a copy of the last read line in the copy_line field of
+ the struct lexer_state ; see below for how to use this buffer
+HANDLE_TRIGRAPHS
+ understand trigraphs, such as ??/ for \. This option should be
+ set by default, except for some legacy code.
+
+ There are other flags, but they are for private usage of ucpp.
+
+8. adjust the input field in the lexer_state to the FILE * from where
+ source file is read. If you use the UCPP_MMAP compile-time option,
+ and your input file is eligible to mmap(), then you can call
+ fopen_mmap_file() to open it, then set_input_file() to set ls->input
+ and some other internal options. Do not call set_input_file() unless
+ you just called fopen_mmap_file() just before on the same file.
+
+9. call add_incpath() to add an include path, define_macro() and
+ undef_macro() to add or remove macros, make_assertion() and
+ destroy_assertion() to add or remove assertions.
+
+10. call enter_file() (this is needed only in non-lexer mode, or if
+ LINE_NUM is set).
+
+
+Afterwards:
+-- if you are in lexer mode, call lex(); each call will make the ctok
+ field point to the next token. A non-zero return value is an error.
+ lex() skips whitespace tokens. The memory used by the string value
+ of some tokens (identifiers, numbers...) is automatically freed,
+ so copy the contents of each such token if you want to keep it
+ (tokens with a string content are identified by the STRING_TOKEN
+ macro applied to their type).
+ When lex() returned a non-zero value: if it is CPPERR_EOF, then
+ end-of-input was reached. Otherwise, it is a genuine error and
+ ls->ctok is an undefined token; skip it and call lex() again to
+ ignore the error.
+
+-- otherwise, call cpp(); each call will analyze one or more tokens
+ (one token if it did not found a cpp directive, or a macro name).
+ A positive return value is an error.
+
+For both functions, if the return value is CPPERR_EOF (which is a
+strictly positive value), then it means that the end of file was
+reached. Call check_cpp_errors() after end of file for pending errors
+(unfinished #if constructions for instance). In non-lexer mode,
+call flush_output().
+
+In the struct lexer_state, the following fields might be read:
+ line the current input line number
+ oline the current output line number (in non-lexer mode)
+ flags the flags described above
+ count_trigraphs the number of trigraphs encountered
+ inmacro the current token comes from a macro
+ macro_count the current macro counter
+"flags" is an unsigned long and might be modified; the three others
+are of long type.
+
+
+To perform another preprocessing: use free_lexer_state() to release
+memory used by the buffers referenced in lexer_state, and go back to
+step 2. The different tables (macros, assertions...) should be reset to
+their respective initial contents. (Warning: this is currently untested)
+
+
+The COPY_LINE buffer: the struct lexer_state contains two interesting
+fields, copy_line[] and cli. If the COPY_LINE flag is on, each read
+line is stored in this buffer, up to (at most) COPY_LINE_LENGTH - 1
+characters (COPY_LINE_LENGTH is defined in tune.h). The last character
+of the buffer is always a zero, and if the line was read entirely, it is
+zero terminated; the trailing newline is not included.
+
+The purpose of this buffer is error-reporting. When an error occurs
+(cpp() returns a strictly positive value, or lex() returns a non-zero
+value), if your struct lexer_state is called ls, use this code:
+
+ if (ls.cli != 0) ls.copy_line[ls.cli] = 0;
+
+This will add a trailing 0 if the line was not read entirely.
+
+
+
+COMPATIBILITY NOTES
+-------------------
+
+The C language has a lengthening history. Nowadays, C comes in three
+flavours:
+
+-- Traditional C, aka "K&R". This is the language first described by
+Brian Kernighan and Dennis Ritchie, and implemented in the first C
+compiler that was ever coded. There are actually several dialects of
+K&R, and all of them are considered as deprecated.
+
+-- ISO 9899:1990, aka C90, aka C89, aka ANSI-C. Formalized by ANSI
+in 1989 and adopted by ISO the next year, it is the C flavour many C
+compilers understand. It is mostly backward compatible with K&R C, but
+with enhancements, clarifications and several new features.
+
+-- ISO 9899:1999, aka C99. This is an evolution on C90, almost fully
+backward compatible with C90 (exhibitting a code that makes a difference
+is a tricky exercise). C99 introduces many new and useful features,
+however, including in the preprocessor.
+
+There was also a normative addendum in 1995, that added a few features
+to C90 (for instance, digraphs) that are also present in C99.
+
+
+Ucpp implements the C99 standard, but can be used in a stricter mode,
+to enforce C90 compatibility (it will, however, still recognize some
+constructions that are not in plain C90).
+
+Ucpp also knows several extensions to C99:
+
+-- Assertions: this is an extension to the defined() operator, with
+ its own namespace. Assertions seem to be used in several places,
+ therefore ucpp knows about them. It is recommended to enable
+ assertions by default on Solaris systems.
+-- Unicode: the C99 norm specifies that extended characters, from
+ the ISO-10646 charset (aka "unicode") can be used in identifiers
+ with the notations \u and \U. ucpp also accepts (with the proper
+ flag) the UTF-8 encoding in the source file for such characters.
+-- #include_next directive: it works as a #include, but will look
+ for files only in the directories specified in the include path
+ after the one the current file was found. This is a GNU-ism that
+ is useful for writing transparent wrappers around header files.
+
+Assertions and unicode are activated by specific flags; the #include_next
+support is always active.
+
+The ucpp code itself should be compatible with any ISO-C90 compiler.
+The cpp.c file is rather big (~ 53kB), it might confuse old 16-bit C
+compilers; the macro.c file is somewhat large also (~ 43kB).
+
+The evaluation of #if expressions is subject to some subtleties, see the
+section "cross-compilation".
+
+The lexer code makes no assumption about the source character set, but
+the following: source characters (those which have a syntactic value in
+C; comment and string literal contents are not concerned) must have a
+strictly positive value that is strictly lower than MAX_CHAR_VAL. The
+strict positivity is already assured by the C standard, so you just need
+to adjust MAX_CHAR_VAL.
+
+Ucpp has been tested succesfully on ASCII/ISO-8859-1 and EBCDIC systems.
+Beware that UTF-8 is NOT compatible with EBCDIC.
+
+Pragma handling: when used in non-lexer mode, ucpp tries to output
+a source text that, read again, will give the exact same stream of
+tokens. This is not completely true with regards to line numbering in
+some tricky macro replacements, but it should work correctly otherwise,
+especially with pragma directives if the compile-time option PRAGMA_DUMP
+was set: #pragma are dumped, non-void _Pragma() are converted to the
+corresponding #pragma and dumped also.
+
+Ucpp does not macro-replace the contents of #pragma and _Pragma();
+If you want a macro-replaced pragma, use this:
+
+#define pragma_(x) _Pragma(#x)
+#define pragma(x) pragma_(x)
+
+Anyway, pragmas do not nest (an _Pragma() cannot be evaluated if it is
+inside a #pragma or another _Pragma).
+
+
+I wrote ucpp according to what is found in "The Language C" from Brian
+Kernighan and Dennis Ritchie (2nd edition) and the C99 standard; but I
+could have misinterpreted some points. On some tricky points I got help
+from the helpful people from the comp.std.c newsgroup. For assertions
+and #include_next, I mimicked the behaviour of GNU cpp, as is stated
+in the GNU cpp info documentation. An open question is related to the
+following code:
+
+#define undefined !
+#define makeun(x) un ## x
+#if makeun(defined foo)
+qux
+#else
+bar
+#endif
+
+Ucpp will replace 'defined foo' with 0 first (since foo is not defined),
+then it will replace the macro makeun, and the expression will become
+'un0', which is replaced by 0 since this is a remaining identifier. The
+expression evaluates to false, and 'bar' is emitted.
+However, some other preprocessors will replace makeun first, considering
+that it is not part of a 'defined' operator application; this will
+produce the macro 'undefined', which is replaced, and the expression
+becomes '!foo'. 'foo' is replaced by 0, the expression evaluates to
+true, and 'qux' is emitted.
+
+My opinion is that the behaviour is undefined, because use of the
+'defined' operator does not match an allowed form prior to macro
+replacement (I mean, its syntax matches, but its use is reconverted
+to inexistant and therefore is not anymore matching). Other people
+think that the behaviour is well-specified, and contrary to what ucpp
+does. The only thing clear to me is that the wording of the standard
+(paragraph 6.10.1.3) is unclear.
+
+Since the ucpp behaviour makes ucpp code simpler and cleaner, and
+that it is unlikely that any real-life code would ever be disturbed
+by that interpretation of the standard, ucpp will keep its current
+behaviour until convincing evidence of my misinterpretation of the
+standard is given to me. The problem can only occur is one uses ## to
+make a 'defined' operator disappear from a #if expression (everybody
+agrees that the generation of a 'defined' operator triggers undefined
+behaviour).
+
+
+About _Pragma: the standard is not clear about when this operator is
+evaluated, and if it is allowed inside #if directives and such. For
+ucpp, I coded _Pragma as a special macro with lazy replacement: it will
+be evaluated wherever a macro could be replaced, and only at the end of
+the macro replacement (for practical purposes, _Pragma can be considered
+as a macro taking one argument, and being replaced by nothing, except
+for some tricky uses of the # and ## operators). This means that, by
+default, ucpp will evaluate _Pragma inside some directives (mainly, #if,
+#include, #include_next and #line), but it can be taught not to do so by
+defining NO_PRAGMA_IN_DIRECTIVE in tune.h.
+
+
+
+CROSS-COMPILATION
+-----------------
+
+If compiled with a C99 development suite, ucpp should be fully
+C99-compliant on the host platform (up to my own understanding of the
+standard -- remember that this software is distributed as-is, without
+any guarantee). However, if a pre-C99 compiler is used, or if the
+target machine is not the host machine (for instance when you build a
+cross-compiler), the evaluation of #if expressions is subject to some
+cross-compiling issues:
+
+
+-- character constants: when evaluating expressions, character constants
+are interpreted in the source character set context; this is allowed
+by the standard but this can lead to problems with code that expects
+this interpretation to match the one made in the C code. To ease
+cross-compilation, you can define a conversion array, and make the
+global variable transient_characters point to it. The array should
+contain 256 int; transient_characters[x] is the value of the character
+whose value is x in the source character set.
+
+This facility is provided for inclusion of ucpp inside another code;
+if you want a stand-alone ucpp with that conversion, hard-code the
+conversion table into eval.c and make transient_characters[] statically
+point to it. Alternatively, you could provide an option syntax to
+provide such a table on command-line, if you feel like it.
+
+
+-- wide character constants signedness: by default, ucpp makes wide
+characters as signed as what plain chars are on the build host. To
+force wide character constant signedness, define WCHAR_SIGNEDNESS to 0
+(for unsigned) or 1 (for signed). Beware, however, that "native" wide
+character constants, even signed, are considered positive. Non-wide
+character constants are, according to the C99 standard, of type int, and
+therefore always signed.
+
+
+-- evaluation type: C90 states that all constants in #if expressions
+are considered as either long or unsigned long, and that the evaluation
+is performed with operands of that size. In C99, the situation is
+equivalent, except that the types used are intmax_t and uintmax_t, as
+defined in <stdint.h>.
+
+Ucpp can use two expression evaluators: one uses native integer types
+(one signed and one unsigned), the other evaluator emulates big integer
+numbers by representing them with two "unsigned long". By default, it
+will use the first evaluator, using (u)intmax_t as native types if the
+compiler is C99-compliant, or (unsigned) long otherwise. If you want
+another behaviour, modify the relevant section in tune.h. Here are
+examples of definitions:
+
+/* evaluate natively with type "long long" */
+#define NATIVE_UINTMAX unsigned long long
+#define NATIVE_INTMAX long long
+
+/* evaluate natively with type "long" (even if bigger is available) */
+#define MATIVE_UINTMAX unsigned long
+#define MATIVE_INTMAX long
+
+/* evaluate with bignum evaluation */
+#undef NATIVE_UINTMAX
+#define SIMUL_UINTMAX
+
+The bignum evaluation handles signed integers in two's complement
+representation, whether this is the native integer representation or
+not. The code makes the non-standard assumption that unsigned long are
+represented unpadded in memory, that is, unsigned long are made up of
+exactly sizeof(unsigned long) * CHAR_BIT bits. I have never heard of any
+architecture where this assumption would be false.
+
+
+
+FUTURE EVOLUTIONS
+-----------------
+
+Ucpp is quite complete now. There was a longstanding project of
+"traditional" preprocessing, but I dropped it because it would not
+map cleanly on the token-based ucpp structure. Maybe I will code a
+string-based preprocessor one day; it would certainly use some of the
+code from lexer.c, eval.c, mem.c and hash.c. However, making such a tool
+is almost irrelevant nowadays. If one wants to handle such project,
+using ucpp as code base, I would happily provide some help, if needed.
+
+
+
+CHANGES
+-------
+
+From 0.9 to 1.0:
+
+* bugfix: crash after erroneous #assert
+* changed ERR_SHARP to FAIL_SHARP, EMUL_UINTMAX to SIMUL_UINTMAX
+* made "inline" default on gcc and DEC ccc (Linux/Alpha)
+* semantic of -I is now Unix-like (added directories are looked first)
+* added -J flag (to add include directories after the system ones)
+* cleaned up non-ascii issues
+* bugfix: missing brace in no-LOW_MEM code
+* bugfix: argument number check in variadic macros
+* bugfix: crash in non-lexer mode after some cases of unreplaced macro
+* bugfix: _Pragma() handling wrt # and ##
+* made evaluation of _Pragma() optional in #if, #include and #line
+* bugfix: re-dump of multiline #pragma
+* added the inmacro and macro_count flags
+* added mmap() support
+* added option to retain whitespace content in lexer mode
+
+From 0.8 to 0.9:
+
+* added check for division by 0 in #if evaluation
+* added check for non-standard line numbers
+* added check for trailing garbage in most directives
+* corrected signedness of char constants (always int, therefore always signed)
+* made LOW_MEM code, so that ucpp runs smoothly on low memory architectures
+* multiple bugfixes (using the GNU cpp testsuite)
+* added handling of _Pragma (as a macro)
+* added tokenization of pragma directives
+* added conservation of pragma directives in text output
+* produced Msdos 16-bit small memory model executable
+* produced Minix-86 executable
+
+From 0.7 to 0.8:
+
+* added some support for Amiga systems
+* fixed extra spacing in stringified tokens
+* fixed bug related to %:% and tolerated rogue sharps
+* namespace cleanup
+* bugfix for macro redefinition
+* added warning for evaluated comma operators in #if (ISO requirement)
+* -Dfoo now defines foo with content 1 (and not void content)
+* trigraphs can be disabled (for incorrect but legacy code)
+* fixed semantics for #include "file" (local directory)
+* fixed detection of protected files
+* produced a Msdos 16-bit executable
+
+From 0.6 to 0.7:
+
+* officially changed the goal to full C99 compliance
+* added the CONTEXT token and let NEWLINE tokens go
+* added report_context() for error reporting
+* enforced matching of #if/#endif (file-global nesting level = 0)
+* added support of C99 digraphs
+* added UTF-8 encoding support
+* added universal character names
+* rewrote #if expressions (sizes fixed, bignum, signed/unsigned fixed)
+* fixed incomplete evaluation of #if expressions
+* added transient_characters[]
+
+From 0.5 to 0.6:
+
+* disappearance of error_nonl()
+* added extra optional warnings for trigraphs
+* some bugfixes, especially in lexer mode
+* handled MacIntosh files correctly
+
+From 0.4 to 0.5:
+
+* nicer #pragma handling (a token can be emitted)
+* bugfix in lexer mode after #line and #error
+* sample.c an example of code linked with ucpp
+* made #if expressions conforming to standard signed/unsigned handling
+* added the copy_line[] buffer feature
+
+From 0.3 to 0.4:
+
+* relaxed interpretation of '#include foo' when foo ends up, after macro
+ substitution, with a '<bar>' content
+* corrected the 'double-dot' bug
+* corrected two bugs related to the treatment of macro aborted calls (due
+ to lack of arguments)
+* some namespaces cleanup, to ease integration into other code
+* documented the way to include ucpp into another program
+* made newlines embedded into strings illegal (and reported as such)
+
+From 0.2 to 0.3:
+
+* added support for system predefined macros
+* made several bugfixes
+* checked C99 compliance for most of the features
+* ucpp now accepts non-C characters on standard when used stand-alone
+* removed many useless spaces in the output
+
+From 0.1 to 0.2:
+
+* added support for assertions
+* added support for macros with variable arguments
+* split the pharaonic cpp.c file into many
+* made several bugfixes
+* relaxed the behaviour with regards to the void arguments
+* made C++-like comments an option
+
+
+
+THANKS TO
+---------
+
+Volker Barthelmann, Neil Booth, Stéphane Ecolivet, Antoine Leca, Cyrille
+Lefevre, Dave Rivers, Loic Tortay and Laurent Wacrenier, for suggestions
+and beta-testing.
+
+Paul Eggert, Douglas A. Gwyn, Clive D.W. Feather, and the other guys from
+comp.std.c, for explanations about the standard.
+
+Dave Brolley, Jamie Lokier and Neil Booth, for discussion about tricky
+points on nesting macros.
+
+Brian Kernighan and Dennis Ritchie, for bringing C to mortal Men.
diff --git a/ucpp/assert.c b/ucpp/assert.c
new file mode 100755
index 0000000..51f5710
--- /dev/null
+++ b/ucpp/assert.c
@@ -0,0 +1,397 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <limits.h>
+#include <time.h>
+#include "ucppi.h"
+#include "mem.h"
+#include "hash.h"
+#include "tune.h"
+
+/*
+ * Assertion support. Each assertion is indexed by its predicate, and
+ * the list of 'questions' which yield a true answer.
+ */
+
+static struct HT *assertions;
+
+static struct assert *new_assertion(void)
+{
+ struct assert *a = getmem(sizeof(struct assert));
+
+ a->nbval = 0;
+ return a;
+}
+
+static void del_assertion(void *va)
+{
+ struct assert *a = va;
+ size_t i, j;
+
+ if (a->name) freemem(a->name);
+ for (i = 0; i < a->nbval; i ++) {
+ for (j = 0; j < a->val[i].nt; j ++)
+ if (S_TOKEN(a->val[i].t[j].type))
+ freemem(a->val[i].t[j].name);
+ if (a->val[i].nt) freemem(a->val[i].t);
+ }
+ if (a->nbval) freemem(a->val);
+}
+
+/*
+ * print the contents of a token list
+ */
+static void print_token_fifo(struct token_fifo *tf)
+{
+ size_t i;
+
+ for (i = 0; i < tf->nt; i ++)
+ if (ttMWS(tf->t[i].type)) fputc(' ', emit_output);
+ else fputs(token_name(tf->t + i), emit_output);
+}
+
+/*
+ * print all assertions related to a given name
+ */
+static void print_assert(void *va)
+{
+ struct assert *a = va;
+ size_t i;
+
+ for (i = 0; i < a->nbval; i ++) {
+ fprintf(emit_output, "#assert %s(", a->name);
+ print_token_fifo(a->val + i);
+ fprintf(emit_output, ")\n");
+ }
+}
+
+/*
+ * compare two token_fifo, return 0 if they are identical, 1 otherwise.
+ * All whitespace tokens are considered identical, but sequences of
+ * whitespace are not shrinked.
+ */
+int cmp_token_list(struct token_fifo *f1, struct token_fifo *f2)
+{
+ size_t i;
+
+ if (f1->nt != f2->nt) return 1;
+ for (i = 0; i < f1->nt; i ++) {
+ if (ttMWS(f1->t[i].type) && ttMWS(f2->t[i].type)) continue;
+ if (f1->t[i].type != f2->t[i].type) return 1;
+ if (f1->t[i].type == MACROARG
+ && f1->t[i].line != f2->t[i].line) return 1;
+ if (S_TOKEN(f1->t[i].type)
+ && strcmp(f1->t[i].name, f2->t[i].name)) return 1;
+ }
+ return 0;
+}
+
+/*
+ * for #assert
+ * Assertions are not part of the ISO-C89 standard, but they are sometimes
+ * encountered, for instance in Solaris standard include files.
+ */
+int handle_assert(struct lexer_state *ls)
+{
+ int ina = 0, ltww;
+ struct token t;
+ struct token_fifo *atl = 0;
+ struct assert *a;
+ int ret = -1;
+ long l = ls->line;
+ int nnp;
+ size_t i;
+
+ while (!next_token(ls)) {
+ if (ls->ctok->type == NEWLINE) break;
+ if (ttMWS(ls->ctok->type)) continue;
+ if (ls->ctok->type == NAME) {
+ if (!(a = getHT(assertions, &(ls->ctok->name)))) {
+ a = new_assertion();
+ a->name = sdup(ls->ctok->name);
+ ina = 1;
+ }
+ goto handle_assert_next;
+ }
+ error(l, "illegal assertion name for #assert");
+ goto handle_assert_warp_ign;
+ }
+ goto handle_assert_trunc;
+
+handle_assert_next:
+ while (!next_token(ls)) {
+ if (ls->ctok->type == NEWLINE) break;
+ if (ttMWS(ls->ctok->type)) continue;
+ if (ls->ctok->type != LPAR) {
+ error(l, "syntax error in #assert");
+ goto handle_assert_warp_ign;
+ }
+ goto handle_assert_next2;
+ }
+ goto handle_assert_trunc;
+
+handle_assert_next2:
+ atl = getmem(sizeof(struct token_fifo));
+ atl->art = atl->nt = 0;
+ for (nnp = 1, ltww = 1; nnp && !next_token(ls);) {
+ if (ls->ctok->type == NEWLINE) break;
+ if (ltww && ttMWS(ls->ctok->type)) continue;
+ ltww = ttMWS(ls->ctok->type);
+ if (ls->ctok->type == LPAR) nnp ++;
+ else if (ls->ctok->type == RPAR) {
+ if (!(-- nnp)) goto handle_assert_next3;
+ }
+ t.type = ls->ctok->type;
+ if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
+ aol(atl->t, atl->nt, t, TOKEN_LIST_MEMG);
+ }
+ goto handle_assert_trunc;
+
+handle_assert_next3:
+ while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+ if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
+ warning(l, "trailing garbage in #assert");
+ }
+ }
+ if (atl->nt && ttMWS(atl->t[atl->nt - 1].type) && (-- atl->nt) == 0)
+ freemem(atl->t);
+ if (atl->nt == 0) {
+ error(l, "void assertion in #assert");
+ freemem(atl);
+ return ret;
+ }
+ for (i = 0; i < a->nbval && cmp_token_list(atl, a->val + i); i ++);
+ if (i != a->nbval) {
+ /* we already have it */
+ ret = 0;
+ goto handle_assert_error;
+ }
+
+ /* This is a new assertion. Let's keep it. */
+ aol(a->val, a->nbval, *atl, TOKEN_LIST_MEMG);
+ if (ina) putHT(assertions, a);
+ if (emit_assertions) {
+ fprintf(emit_output, "#assert %s(", a->name);
+ print_token_fifo(atl);
+ fputs(")\n", emit_output);
+ }
+ return 0;
+
+handle_assert_trunc:
+ error(l, "unfinished #assert");
+handle_assert_error:
+ if (atl && atl->nt) {
+ for (i = 0; i < atl->nt; i ++)
+ if (S_TOKEN(atl->t[i].type)) freemem(atl->t[i].name);
+ freemem(atl->t);
+ }
+ return ret;
+handle_assert_warp_ign:
+ while (!next_token(ls) && ls->ctok->type != NEWLINE);
+ return ret;
+}
+
+/*
+ * for #unassert
+ */
+int handle_unassert(struct lexer_state *ls)
+{
+ int ltww;
+ struct token t;
+ struct token_fifo *atl = 0;
+ struct assert *a;
+ int ret = -1;
+ long l = ls->line;
+ int nnp;
+ size_t i;
+
+ while (!next_token(ls)) {
+ if (ls->ctok->type == NEWLINE) break;
+ if (ttMWS(ls->ctok->type)) continue;
+ if (ls->ctok->type == NAME) {
+ if (!(a = getHT(assertions, &(ls->ctok->name)))) {
+ ret = 0;
+ goto handle_unassert_warp;
+ }
+ goto handle_unassert_next;
+ }
+ error(l, "illegal assertion name for #unassert");
+ goto handle_unassert_warp;
+ }
+ goto handle_unassert_trunc;
+
+handle_unassert_next:
+ while (!next_token(ls)) {
+ if (ls->ctok->type == NEWLINE) break;
+ if (ttMWS(ls->ctok->type)) continue;
+ if (ls->ctok->type != LPAR) {
+ error(l, "syntax error in #unassert");
+ goto handle_unassert_warp;
+ }
+ goto handle_unassert_next2;
+ }
+ if (emit_assertions) fprintf(emit_output, "#unassert %s\n", a->name);
+ delHT(assertions, a);
+ return 0;
+
+handle_unassert_next2:
+ atl = getmem(sizeof(struct token_fifo));
+ atl->art = atl->nt = 0;
+ for (nnp = 1, ltww = 1; nnp && !next_token(ls);) {
+ if (ls->ctok->type == NEWLINE) break;
+ if (ltww && ttMWS(ls->ctok->type)) continue;
+ ltww = ttMWS(ls->ctok->type);
+ if (ls->ctok->type == LPAR) nnp ++;
+ else if (ls->ctok->type == RPAR) {
+ if (!(-- nnp)) goto handle_unassert_next3;
+ }
+ t.type = ls->ctok->type;
+ if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
+ aol(atl->t, atl->nt, t, TOKEN_LIST_MEMG);
+ }
+ goto handle_unassert_trunc;
+
+handle_unassert_next3:
+ while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+ if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
+ warning(l, "trailing garbage in #unassert");
+ }
+ }
+ if (atl->nt && ttMWS(atl->t[atl->nt - 1].type) && (-- atl->nt) == 0)
+ freemem(atl->t);
+ if (atl->nt == 0) {
+ error(l, "void assertion in #unassert");
+ freemem(atl);
+ return ret;
+ }
+ for (i = 0; i < a->nbval && cmp_token_list(atl, a->val + i); i ++);
+ if (i != a->nbval) {
+ /* we have it, undefine it */
+ if (i < (a->nbval - 1))
+ mmvwo(a->val + i, a->val + i + 1, (a->nbval - i - 1)
+ * sizeof(struct token_fifo));
+ a->nbval --;
+ if (emit_assertions) {
+ fprintf(emit_output, "#unassert %s(", a->name);
+ print_token_fifo(atl);
+ fputs(")\n", emit_output);
+ }
+ }
+ ret = 0;
+ goto handle_unassert_finish;
+
+handle_unassert_trunc:
+ error(l, "unfinished #unassert");
+handle_unassert_finish:
+ if (atl && atl->nt) {
+ for (i = 0; i < atl->nt; i ++)
+ if (S_TOKEN(atl->t[i].type)) freemem(atl->t[i].name);
+ freemem(atl->t);
+ }
+ return ret;
+handle_unassert_warp:
+ while (!next_token(ls) && ls->ctok->type != NEWLINE);
+ return ret;
+}
+
+/*
+ * Add the given assertion (as string).
+ */
+int make_assertion(char *aval)
+{
+ struct lexer_state lls;
+ size_t n = strlen(aval) + 1;
+ char *c = sdup(aval);
+ int ret;
+
+ *(c + n - 1) = '\n';
+ init_buf_lexer_state(&lls, 0);
+ lls.flags = DEFAULT_LEXER_FLAGS;
+ lls.input = 0;
+ lls.input_string = (unsigned char *)c;
+ lls.pbuf = 0;
+ lls.ebuf = n;
+ lls.line = -1;
+ ret = handle_assert(&lls);
+ freemem(c);
+ free_lexer_state(&lls);
+ return ret;
+}
+
+/*
+ * Remove the given assertion (as string).
+ */
+int destroy_assertion(char *aval)
+{
+ struct lexer_state lls;
+ size_t n = strlen(aval) + 1;
+ char *c = sdup(aval);
+ int ret;
+
+ *(c + n - 1) = '\n';
+ init_buf_lexer_state(&lls, 0);
+ lls.flags = DEFAULT_LEXER_FLAGS;
+ lls.input = 0;
+ lls.input_string = (unsigned char *)c;
+ lls.pbuf = 0;
+ lls.ebuf = n;
+ lls.line = -1;
+ ret = handle_unassert(&lls);
+ freemem(c);
+ free_lexer_state(&lls);
+ return ret;
+}
+
+/*
+ * initialize the assertion table
+ */
+void init_assertions(void)
+{
+ if (assertions) killHT(assertions);
+ assertions = newHT(128, cmp_struct, hash_struct, del_assertion);
+}
+
+/*
+ * retrieve an assertion from the hash table
+ */
+struct assert *get_assertion(char *name)
+{
+ return getHT(assertions, &name);
+}
+
+/*
+ * print already defined assertions
+ */
+void print_assertions(void)
+{
+ scanHT(assertions, print_assert);
+}
diff --git a/ucpp/cpp.c b/ucpp/cpp.c
new file mode 100644
index 0000000..4dcca13
--- /dev/null
+++ b/ucpp/cpp.c
@@ -0,0 +1,2265 @@
+/*
+ * C and T preprocessor, and integrated lexer
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*vb*/
+#ifdef HAVE_MISRA
+void misra(int,...);
+#endif
+extern void handle_deps(char *,int);
+
+#define VERS_MAJ 1
+#define VERS_MIN 0
+/* uncomment the following if you cannot set it with a compiler flag */
+/* #define STAND_ALONE */
+
+#include "tune.h"
+#ifdef UCPP_MMAP
+#ifndef _POSIX_SOURCE
+#define _POSIX_SOURCE 1
+#endif
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <stddef.h>
+#include <limits.h>
+#include <time.h>
+#include "ucppi.h"
+#include "mem.h"
+#include "hash.h"
+#ifdef UCPP_MMAP
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#endif
+
+/*
+ * The standard path where includes are looked for.
+ */
+#ifdef STAND_ALONE
+static char *include_path_std[] = { STD_INCLUDE_PATH, 0 };
+#endif
+static char **include_path;
+static size_t include_path_nb = 0;
+
+int no_special_macros = 0;
+int emit_dependencies = 0, emit_defines = 0, emit_assertions = 0;
+FILE *emit_output;
+
+#ifdef STAND_ALONE
+static char *system_macros_def[] = { STD_MACROS, 0 };
+static char *system_assertions_def[] = { STD_ASSERT, 0 };
+#endif
+
+char *current_filename, *current_long_filename = 0;
+static int current_incdir = -1;
+
+#ifndef NO_UCPP_ERROR_FUNCTIONS
+/*
+ * "ouch" is the name for an internal ucpp error. If AUDIT is not defined,
+ * no code calling this function will be generated; a "ouch" may still be
+ * emitted by getmem() (in mem.c) if MEM_CHECK is defined, but this "ouch"
+ * does not use this function.
+ */
+#endif /* NO_UCPP_ERROR_FUNCTIONS */
+
+/*
+ * Some memory allocations are manually garbage-collected; essentially,
+ * strings duplicated in the process of macro replacement. Each such
+ * string is referenced in the garbage_fifo, which is cleared when all
+ * nested macros have been resolved.
+ */
+
+struct garbage_fifo {
+ char **garbage;
+ size_t ngarb, memgarb;
+};
+
+/*
+ * throw_away() marks a string to be collected later
+ */
+void throw_away(struct garbage_fifo *gf, char *n)
+{
+ wan(gf->garbage, gf->ngarb, n, gf->memgarb);
+}
+
+/*
+ * free marked strings
+ */
+void garbage_collect(struct garbage_fifo *gf)
+{
+ size_t i;
+
+ for (i = 0; i < gf->ngarb; i ++) freemem(gf->garbage[i]);
+ gf->ngarb = 0;
+}
+
+static void init_garbage_fifo(struct garbage_fifo *gf)
+{
+ gf->garbage = getmem((gf->memgarb = GARBAGE_LIST_MEMG)
+ * sizeof(char *));
+ gf->ngarb = 0;
+}
+
+/*
+ * order is important: it must match the token-constants declared as an
+ * enum in the header file.
+ */
+char *operators_name[] = {
+ " ", "\n", " ",
+ "0000", "name", "bunch", "pragma", "context",
+ "\"dummy string\"", "'dummy char'",
+ "/", "/=", "-", "--", "-=", "->", "+", "++", "+=", "<", "<=", "<<",
+ "<<=", ">", ">=", ">>", ">>=", "=", "==",
+#ifdef CAST_OP
+ "=>",
+#endif
+ "~", "!=", "&", "&&", "&=", "|", "||", "|=", "%", "%=", "*", "*=",
+ "^", "^=", "!", "~=", "{", "}", "[", "]", "(", ")", ",", "?", ";",
+ ":", ".", "...", "#", "##", " ", "ouch", "<:", ":>", "<%", "%>",
+ "%:", "%:%:"
+};
+
+/* the ascii representation of a token */
+#ifdef SEMPER_FIDELIS
+#define tname(x) (ttWHI((x).type) ? " " : S_TOKEN((x).type) \
+ ? (x).name : operators_name[(x).type])
+#else
+#define tname(x) (S_TOKEN((x).type) ? (x).name \
+ : operators_name[(x).type])
+#endif
+
+char *token_name(struct token *t)
+{
+ return tname(*t);
+}
+
+/*
+ * To speed up deeply nested and repeated inclusions, we:
+ * -- use a hash table to remember where we found each file
+ * -- remember when the file is protected by a #ifndef/#define/#endif
+ * construction; we can then avoid including several times a file
+ * when this is not necessary.
+ * -- remember in which directory, in the include path, the file was found.
+ */
+struct found_file {
+ char *name; /* first field */
+ char *long_name;
+ char *protect;
+ int incdir;
+};
+
+static struct HT *found_files = 0, *found_files_loc = 0;
+
+static struct found_file *new_found_file(void)
+{
+ struct found_file *ff = getmem(sizeof(struct found_file));
+
+ ff->protect = 0;
+ ff->incdir = -1;
+ return ff;
+}
+
+static void del_found_file(void *m)
+{
+ struct found_file *ff = (struct found_file *)m;
+
+ freemem(ff->name);
+ freemem(ff->long_name);
+ if (ff->protect) freemem(ff->protect);
+}
+
+/*
+ * To keep up with the #ifndef/#define/#endif protection mechanism
+ * detection.
+ */
+struct protect protect_detect;
+static struct protect *protect_detect_stack = 0;
+
+/*
+ * "current_filename" is used for error reporting, and the __FILE__ macro
+ */
+static void set_current_filename(char *x)
+{
+ current_filename = x;
+}
+
+void set_init_filename(char *x, int real_file)
+{
+ set_current_filename(sdup(x));
+ current_long_filename = 0;
+ current_incdir = -1;
+ if (real_file) {
+ protect_detect.macro = 0;
+ protect_detect.state = 1;
+ protect_detect.ff = new_found_file();
+ protect_detect.ff->name = sdup(x);
+ protect_detect.ff->long_name = sdup(x);
+ putHT(found_files_loc, protect_detect.ff);
+ } else {
+ protect_detect.state = 0;
+ }
+}
+
+static void init_found_files(void)
+{
+ if (found_files) killHT(found_files);
+ found_files = newHT(128, cmp_struct, hash_struct, del_found_file);
+ if (found_files_loc) killHT(found_files_loc);
+ found_files_loc = newHT(128, cmp_struct, hash_struct, del_found_file);
+}
+
+/*
+ * convert a Unix-style path for the host architecture
+ */
+#if defined(MSDOS) || defined(ATARI) || defined(_WIN32)
+static char *convert_path(char *path)
+{
+ /* on msdos systems, replace all / by \ */
+ char *c, *newp = sdup(path);
+
+ for (c = newp; *c; c ++) if (*c == '/') *c = '\\';
+ return newp;
+}
+
+#elif defined AMIGA
+static char *convert_path(char *path)
+{
+ char *newp = getmem(1 + strlen(path));
+ char *s = path, *d = newp;
+
+ if (*s == '.') { /* convert "." to "" */
+ if (*(s+1) == '\0')
+ s++;
+ }
+ while (*s) {
+ if (*s == '.') {
+ if (*(s+1) == '/') {
+ s += 2; /* "./" is discarded */
+ continue;
+ }
+ else if (*(s+1) == '.') {
+ if (*(s+2) == '/')
+ s += 2; /* "../" is converted to "/" */
+ }
+ }
+ *d++ = *s++;
+ }
+ *d = '\0';
+
+ return newp;
+}
+
+#else /* no conversion */
+static char *convert_path(char *path)
+{
+ return sdup(path);
+}
+#endif
+
+/*
+ * Set the lexer state at the beginning of a file.
+ */
+static void reinit_lexer_state(struct lexer_state *ls, int wb)
+{
+#ifndef NO_UCPP_BUF
+ ls->input_buf = wb ? getmem(INPUT_BUF_MEMG) : 0;
+#ifdef UCPP_MMAP
+ ls->from_mmap = 0;
+#endif
+#endif
+ ls->ebuf = ls->pbuf = 0;
+ ls->nlka = 0;
+ ls->macfile = 0;
+ ls->discard = 1;
+ ls->last = 0; /* we suppose '\n' is not 0 */
+ ls->line = 1;
+ ls->ltwnl = 1;
+ ls->oline = 1;
+ ls->pending_token = 0;
+ ls->cli = 0;
+ ls->copy_line[COPY_LINE_LENGTH - 1] = 0;
+ ls->ifnest = 0;
+ ls->condf[0] = ls->condf[1] = 0;
+}
+
+/*
+ * Initialize the struct lexer_state, with optional input and output buffers.
+ */
+void init_buf_lexer_state(struct lexer_state *ls, int wb)
+{
+ reinit_lexer_state(ls, wb);
+#ifndef NO_UCPP_BUF
+ ls->output_buf = wb ? getmem(OUTPUT_BUF_MEMG) : 0;
+#endif
+ ls->sbuf = 0;
+
+ ls->ctok = getmem(sizeof(struct token));
+ ls->ctok->name = getmem(ls->tknl = TOKEN_NAME_MEMG);
+ ls->pending_token = 0;
+
+ ls->flags = 0;
+ ls->count_trigraphs = 0;
+ ls->gf = getmem(sizeof(struct garbage_fifo));
+ init_garbage_fifo(ls->gf);
+ ls->condcomp = 1;
+ ls->condnest = 0;
+#ifdef INMACRO_FLAG
+ ls->inmacro = 0;
+ ls->macro_count = 0;
+#endif
+}
+
+/*
+ * Initialize the (complex) struct lexer_state.
+ */
+void init_lexer_state(struct lexer_state *ls)
+{
+ init_buf_lexer_state(ls, 1);
+}
+
+/*
+ * Restore what is needed from a lexer_state. This is used for #include.
+ */
+static void restore_lexer_state(struct lexer_state *ls,
+ struct lexer_state *lsbak)
+{
+#ifndef NO_UCPP_BUF
+ freemem(ls->input_buf);
+ ls->input_buf = lsbak->input_buf;
+#ifdef UCPP_MMAP
+ ls->from_mmap = lsbak->from_mmap;
+ ls->input_buf_sav = lsbak->input_buf_sav;
+#endif
+#endif
+ ls->input = lsbak->input;
+ ls->ebuf = lsbak->ebuf;
+ ls->pbuf = lsbak->pbuf;
+ ls->nlka = lsbak->nlka;
+ ls->macfile = lsbak->macfile;
+ ls->discard = lsbak->discard;
+ ls->line = lsbak->line;
+ ls->oline = lsbak->oline;
+ ls->ifnest = lsbak->ifnest;
+ ls->condf[0] = lsbak->condf[0];
+ ls->condf[1] = lsbak->condf[1];
+}
+
+/*
+ * file_context (and the two functions push_ and pop_) are used to save
+ * all that is needed when including a file.
+ */
+static struct file_context {
+ struct lexer_state ls;
+ char *name, *long_name;
+ int incdir;
+} *ls_stack;
+static size_t ls_depth = 0;
+
+static void push_file_context(struct lexer_state *ls)
+{
+ struct file_context fc;
+
+ if (ls_depth > 1023)
+ error(ls->line - 1, "too many nested includes");
+ fc.name = current_filename;
+ fc.long_name = current_long_filename;
+ fc.incdir = current_incdir;
+ mmv(&(fc.ls), ls, sizeof(struct lexer_state));
+ aol(ls_stack, ls_depth, fc, LS_STACK_MEMG);
+ ls_depth --;
+ aol(protect_detect_stack, ls_depth, protect_detect, LS_STACK_MEMG);
+ protect_detect.macro = 0;
+}
+
+static void pop_file_context(struct lexer_state *ls)
+{
+#ifdef AUDIT
+ if (ls_depth <= 0) ouch("prepare to meet thy creator");
+#endif
+ restore_lexer_state(ls, &(ls_stack[-- ls_depth].ls));
+ if (protect_detect.macro) freemem(protect_detect.macro);
+ protect_detect = protect_detect_stack[ls_depth];
+ set_current_filename(ls_stack[ls_depth].name);
+ current_long_filename = ls_stack[ls_depth].long_name;
+ current_incdir = ls_stack[ls_depth].incdir;
+}
+
+/*
+ * report_context() returns the list of successive includers of the
+ * current file, ending with a dummy entry with a negative line number.
+ * The caller is responsible for freeing the returned pointer.
+ */
+struct stack_context *report_context(void)
+{
+ struct stack_context *sc;
+ size_t i;
+
+ sc = getmem((ls_depth + 1) * sizeof(struct stack_context));
+ for (i = 0; i < ls_depth; i ++) {
+ sc[i].name = ls_stack[ls_depth - i - 1].name;
+ sc[i].long_name = ls_stack[ls_depth - i - 1].long_name;
+ sc[i].line = ls_stack[ls_depth - i - 1].ls.line - 1;
+ }
+ sc[ls_depth].line = -1;
+ return sc;
+}
+
+/*
+ * init_lexer_mode() is used to end initialization of a struct lexer_state
+ * if it must be used for a lexer
+ */
+void init_lexer_mode(struct lexer_state *ls)
+{
+ ls->flags = DEFAULT_LEXER_FLAGS;
+ ls->output_fifo = getmem(sizeof(struct token_fifo));
+ ls->output_fifo->art = ls->output_fifo->nt = 0;
+ ls->toplevel_of = ls->output_fifo;
+ ls->save_ctok = ls->ctok;
+}
+
+/*
+ * release memory used by a struct lexer_state
+ */
+void free_lexer_state(struct lexer_state *ls)
+{
+#ifndef NO_UCPP_BUF
+ if (ls->input_buf) freemem(ls->input_buf);
+ if (ls->output_buf) freemem(ls->output_buf);
+#endif
+ freemem(ls->ctok->name);
+ freemem(ls->ctok);
+ if (!(ls->flags & LEXER)) garbage_collect(ls->gf);
+ freemem(ls->gf);
+}
+
+/*
+ * Print line information.
+ */
+static void print_line_info(struct lexer_state *ls, unsigned long flags)
+{
+ char *fn = current_long_filename ?
+ current_long_filename : current_filename;
+ char *b, *d;
+
+ b = getmem(50 + strlen(fn));
+ if (flags & GCC_LINE_NUM) {
+ sprintf(b, "# %ld \"%s\"\n", ls->line, fn);
+ } else {
+ sprintf(b, "#line %ld \"%s\"\n", ls->line, fn);
+ }
+ for (d = b; *d; d ++) put_char(ls, (unsigned char)(*d));
+ freemem(b);
+}
+
+/*
+ * Enter a file; this implies the possible emission of a #line directive.
+ * The flags used are passed as second parameter instead of being
+ * extracted from the struct lexer_state.
+ *
+ * As a command-line option, gcc-like directives (with only a '#',
+ * without 'line') may be produced.
+ */
+void enter_file(struct lexer_state *ls, unsigned long flags)
+{
+ char *fn = current_long_filename ?
+ current_long_filename : current_filename;
+
+ if (!(flags & LINE_NUM)) return;
+ if ((flags & LEXER) && !(flags & TEXT_OUTPUT)) {
+ struct token t;
+
+ t.type = CONTEXT;
+ t.line = ls->line;
+ t.name = fn;
+ print_token(ls, &t, 0);
+ return;
+ }
+ print_line_info(ls, flags);
+ ls->oline --; /* emitted #line troubled oline */
+}
+
+#ifdef UCPP_MMAP
+/*
+ * We open() the file, then fdopen() it and fseek() to its end. If the
+ * fseek() worked, we try to mmap() the file, up to the point where we
+ * arrived.
+ * On an architecture where end-of-lines are multibytes and translated
+ * into single '\n', bad things could happen. We strongly hope that, if
+ * we could fseek() to the end but could not mmap(), then we can get back.
+ */
+static void *find_file_map;
+static size_t map_length;
+
+FILE *fopen_mmap_file(char *name)
+{
+ FILE *f;
+ int fd;
+ long l;
+
+ find_file_map = 0;
+ fd = open(name, O_RDONLY, 0);
+ if (fd < 0) return 0;
+ l = lseek(fd, 0, SEEK_END);
+ f = fdopen(fd, "r");
+ if (!f) {
+ close(fd);
+ return 0;
+ }
+ if (l < 0) return f; /* not seekable */
+ map_length = l;
+ if ((find_file_map = mmap(0, map_length, PROT_READ,
+ MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+ /* we could not mmap() the file; get back */
+ find_file_map = 0;
+ if (fseek(f, 0, SEEK_SET)) {
+ /* bwaah... can't get back. This file is cursed. */
+ fclose(f);
+ return 0;
+ }
+ }
+ return f;
+}
+
+void set_input_file(struct lexer_state *ls, FILE *f)
+{
+ ls->input = f;
+ if (find_file_map) {
+ ls->from_mmap = 1;
+ ls->input_buf_sav = ls->input_buf;
+ ls->input_buf = find_file_map;
+ ls->pbuf = 0;
+ ls->ebuf = map_length;
+ } else {
+ ls->from_mmap = 0;
+ }
+}
+#endif
+
+/*
+ * Find a file by looking through the include path.
+ * return value: a FILE * on the file, opened in "r" mode, or 0.
+ *
+ * find_file_error will contain:
+ * FF_ERROR on error (file not found or impossible to read)
+ * FF_PROTECT file is protected and therefore useless to read
+ * FF_KNOWN file is already known
+ * FF_UNKNOWN file was not already known
+ */
+static int find_file_error;
+
+enum { FF_ERROR, FF_PROTECT, FF_KNOWN, FF_UNKNOWN };
+
+static FILE *find_file(char *name, int localdir)
+{
+ FILE *f;
+ int i, incdir = -1;
+ size_t nl = strlen(name);
+ char *s = 0;
+ struct found_file *ff = 0;
+ int lf = 0;
+
+ find_file_error = FF_ERROR;
+ protect_detect.state = -1;
+ protect_detect.macro = 0;
+ if (localdir) {
+ int i;
+ char *rfn = current_long_filename ? current_long_filename
+ : current_filename;
+
+ for (i = strlen(rfn) - 1; i >= 0; i --)
+#if defined(MSDOS) || defined(ATARI) || defined(_WIN32)
+ if (rfn[i] == '\\') break;
+#elif defined AMIGA
+ if (rfn[i] == '/' || rfn[i] == ':') break;
+#else
+ if (rfn[i] == '/') break;
+#endif
+
+#if defined(MSDOS) || defined(ATARI) || defined(_WIN32)
+ if (i >= 0 && *name != '\\' && (nl < 2 || name[1] != ':'))
+#elif defined AMIGA
+ if (i >= 0 && strchr(name,':') == 0)
+#else
+ if (i >= 0 && *name != '/')
+#endif
+ {
+ /*
+ * current file is somewhere else, and the provided
+ * file name is not absolute, so we must adjust the
+ * base for looking for the file; besides,
+ * found_files and found_files_loc are irrelevant
+ * for this search.
+ */
+ s = getmem(i + 2 + nl);
+ mmv(s, rfn, i + 1);
+ mmv(s + i + 1, name, nl);
+ s[i + 1 + nl] = 0;
+ ff = getHT(found_files_loc, &s);
+ } else ff = getHT(found_files_loc, &name);
+
+ if (!ff) {
+#ifdef UCPP_MMAP
+ if (f = fopen_mmap_file(s ? s : name)) {
+#else
+ if (f = fopen(s ? s : name, "r")) {
+#endif
+ lf = 1;
+ protect_detect.ff = new_found_file();
+ goto found_file;
+ }
+ }
+ }
+
+ if (!ff) ff = getHT(found_files, s ? &s : &name);
+ if (ff) {
+ if (ff->protect && get_macro(ff->protect)) {
+ /* file is protected, do not include it */
+ find_file_error = FF_PROTECT;
+ return 0;
+ }
+ protect_detect.ff = ff;
+#ifdef UCPP_MMAP
+ f = fopen_mmap_file(ff->long_name);
+#else
+ f = fopen(ff->long_name, "r");
+#endif
+ if (!f) return 0;
+ goto found_file_2;
+ } else {
+ protect_detect.ff = new_found_file();
+ }
+ /*
+ * This is the first time we find the file, or it was not protected.
+ */
+ if (s) freemem(s);
+ for (i = 0; i < include_path_nb; i ++) {
+ size_t ni = strlen(include_path[i]);
+
+ s = getmem(ni + nl + 2);
+ mmv(s, include_path[i], ni);
+#ifdef AMIGA
+ /* contributed by Volker Barthelmann */
+ if (ni > 0 && s[ni - 1] != ':' && s[ni - 1] != '/') {
+ s[ni] = '/';
+ mmv(s + ni + 1, name, nl + 1);
+ } else {
+ mmv(s + ni, name, nl + 1);
+ }
+#else
+ s[ni] = '/';
+ mmv(s + ni + 1, name, nl + 1);
+#endif
+ incdir = i;
+#ifdef UCPP_MMAP
+ f = fopen_mmap_file(s);
+#else
+ f = fopen(s, "r");
+#endif
+ if (f) goto found_file;
+ freemem(s);
+ }
+ return 0;
+found_file:
+ if (f && ((emit_dependencies == 1 && lf)
+ || emit_dependencies == 2)) {
+ fprintf(emit_output, " %s", s ? s : name);
+ }
+ if (!ff) {
+ struct found_file *nff = protect_detect.ff;
+
+ nff->name = sdup(name);
+ nff->long_name = s ? s : sdup(name);
+ nff->incdir = incdir;
+#if 0
+ putHT(lf ? found_files_loc : found_files, nff);
+#endif
+ s = 0;
+ find_file_error = FF_UNKNOWN;
+ ff = nff;
+ } else find_file_error = FF_KNOWN;
+found_file_2:
+ if (s) freemem(s);
+ current_long_filename = ff->long_name;
+#ifdef NO_LIBC_BUF
+ setbuf(f, 0);
+#endif
+ current_incdir = ff->incdir;
+ return f;
+}
+
+/*
+ * Find the named file by looking through the end of the include path.
+ * This one is not as optimized as find_file() since it is rarely used.
+ */
+static FILE *find_file_next(char *name)
+{
+ int i;
+ size_t nl = strlen(name);
+ FILE *f;
+
+ for (i = current_incdir + 1; i < include_path_nb; i ++) {
+ char *s;
+ size_t ni = strlen(include_path[i]);
+
+ s = getmem(ni + nl + 2);
+ mmv(s, include_path[i], ni);
+#ifdef AMIGA
+ /* contributed by Volker Barthelmann */
+ if (ni > 0 && s[ni - 1] != ':' && s[ni - 1] != '/') {
+ s[ni] = '/';
+ mmv(s + ni + 1, name, nl + 1);
+ } else {
+ mmv(s + ni, name, nl + 1);
+ }
+#else
+ s[ni] = '/';
+ mmv(s + ni + 1, name, nl + 1);
+#endif
+
+#ifdef UCPP_MMAP
+ f = fopen_mmap_file(s);
+#else
+ f = fopen(s, "r");
+#endif
+ if (f) {
+ if (emit_dependencies == 2) {
+ fprintf(emit_output, " %s", s ? s : name);
+ }
+ current_long_filename = s;
+ current_incdir = i;
+ return f;
+ }
+ freemem(s);
+ }
+ return 0;
+}
+
+/*
+ * The #if directive. This function parse the expression, performs macro
+ * expansion (and handles the "defined" operator), and call eval_expr.
+ * return value: 1 if the expression is true, 0 if it is false, -1 on error.
+ */
+static int handle_if(struct lexer_state *ls)
+{
+ struct token_fifo tf, tf1, tf2, tf3, *save_tf;
+ long l = ls->line;
+ unsigned long z;
+ int ret = 0, ltww = 1;
+
+ /* first, get the whole line */
+ tf.art = tf.nt = 0;
+ while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+ struct token t;
+
+ if (ltww && ttMWS(ls->ctok->type)) continue;
+ ltww = ttMWS(ls->ctok->type);
+ t.type = ls->ctok->type;
+ t.line = l;
+ if (S_TOKEN(ls->ctok->type)) {
+ t.name = sdup(ls->ctok->name);
+ throw_away(ls->gf, t.name);
+ }
+ aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
+ }
+ if (ltww && tf.nt) if ((-- tf.nt) == 0) freemem(tf.t);
+ if (tf.nt == 0) {
+ error(l, "void condition for a #if/#elif");
+ return -1;
+ }
+ /* handle the "defined" operator */
+ tf1.art = tf1.nt = 0;
+ while (tf.art < tf.nt) {
+ struct token *ct, rt;
+ struct macro *m;
+ size_t nidx, eidx;
+
+ ct = tf.t + (tf.art ++);
+ if (ct->type == NAME && !strcmp(ct->name, "defined")) {
+ if (tf.art >= tf.nt) goto store_token;
+ nidx = tf.art;
+ if (ttMWS(tf.t[nidx].type))
+ if (++ nidx >= tf.nt) goto store_token;
+ if (tf.t[nidx].type == NAME) {
+ eidx = nidx;
+ goto check_macro;
+ }
+ if (tf.t[nidx].type != LPAR) {
+#ifdef HAVE_MISRA
+ misra_neu(100,19,14,0);
+#endif
+ goto store_token;}
+ if (++ nidx >= tf.nt) goto store_token;
+ if (ttMWS(tf.t[nidx].type))
+ if (++ nidx >= tf.nt) goto store_token;
+ if (tf.t[nidx].type != NAME) {
+#ifdef HAVE_MISRA
+ misra_neu(100,19,14,0);
+#endif
+ goto store_token;}
+ eidx = nidx + 1;
+ if (eidx >= tf.nt) goto store_token;
+ if (ttMWS(tf.t[eidx].type))
+ if (++ eidx >= tf.nt) goto store_token;
+ if (tf.t[eidx].type != RPAR) goto store_token;
+ goto check_macro;
+ }
+ store_token:
+ aol(tf1.t, tf1.nt, *ct, TOKEN_LIST_MEMG);
+ continue;
+
+ check_macro:
+ m = get_macro(tf.t[nidx].name);
+ rt.type = NUMBER;
+ rt.name = m ? "1L" : "0L";
+ aol(tf1.t, tf1.nt, rt, TOKEN_LIST_MEMG);
+ tf.art = eidx + 1;
+ }
+ freemem(tf.t);
+ if (tf1.nt == 0) {
+ error(l, "void condition (after expansion) for a #if/#elif");
+ return -1;
+ }
+
+ /* perform all macro substitutions */
+ tf2.art = tf2.nt = 0;
+ save_tf = ls->output_fifo;
+ ls->output_fifo = &tf2;
+ while (tf1.art < tf1.nt) {
+ struct token *ct;
+
+ ct = tf1.t + (tf1.art ++);
+ if (ct->type == NAME) {
+ struct macro *m = get_macro(ct->name);
+
+ if (m) {
+ if (substitute_macro(ls, m, &tf1, 0,
+#ifdef NO_PRAGMA_IN_DIRECTIVE
+ 1,
+#else
+ 0,
+#endif
+ ct->line)) {
+ ls->output_fifo = save_tf;
+ return -1;
+ }
+ continue;
+ }
+ } else if ((ct->type == SHARP || ct->type == DIG_SHARP)
+ && (ls->flags & HANDLE_ASSERTIONS)) {
+ /* we have an assertion; parse it */
+ int nnp, ltww = 1;
+ size_t i = tf1.art;
+ struct token_fifo atl;
+ char *aname;
+ struct assert *a;
+ int av = 0;
+ struct token rt;
+
+ atl.art = atl.nt = 0;
+ while (i < tf1.nt && ttMWS(tf1.t[i].type)) i ++;
+ if (i >= tf1.nt) goto assert_error;
+ if (tf1.t[i].type != NAME) goto assert_error;
+ aname = tf1.t[i ++].name;
+ while (i < tf1.nt && ttMWS(tf1.t[i].type)) i ++;
+ if (i >= tf1.nt) goto assert_generic;
+ if (tf1.t[i].type != LPAR) goto assert_generic;
+ i ++;
+ for (nnp = 1; nnp && i < tf1.nt; i ++) {
+ if (ltww && ttMWS(tf1.t[i].type)) continue;
+ if (tf1.t[i].type == LPAR) nnp ++;
+ else if (tf1.t[i].type == RPAR
+ && (-- nnp) == 0) {
+ tf1.art = i + 1;
+ break;
+ }
+ ltww = ttMWS(tf1.t[i].type);
+ aol(atl.t, atl.nt, tf1.t[i], TOKEN_LIST_MEMG);
+ }
+ if (nnp) goto assert_error;
+ if (ltww && atl.nt && (-- atl.nt) == 0) freemem(atl.t);
+ if (atl.nt == 0) goto assert_error;
+
+ /* the assertion is in aname and atl; check it */
+ a = get_assertion(aname);
+ if (a) for (i = 0; i < a->nbval; i ++)
+ if (!cmp_token_list(&atl, a->val + i)) {
+ av = 1;
+ break;
+ }
+ rt.type = NUMBER;
+ rt.name = av ? "1" : "0";
+ aol(tf2.t, tf2.nt, rt, TOKEN_LIST_MEMG);
+ continue;
+
+ assert_generic:
+ tf1.art = i;
+ rt.type = NUMBER;
+ rt.name = get_assertion(aname) ? "1" : "0";
+ aol(tf2.t, tf2.nt, rt, TOKEN_LIST_MEMG);
+ continue;
+
+ assert_error:
+ error(l, "syntax error for assertion in #if");
+ ls->output_fifo = save_tf;
+ return -1;
+ }
+ aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG);
+ }
+ ls->output_fifo = save_tf;
+ freemem(tf1.t);
+ if (tf2.nt == 0) {
+ error(l, "void condition (after expansion) for a #if/#elif");
+ return -1;
+ }
+
+ /*
+ * suppress whitespace and replace rogue identifiers by 0
+ */
+ tf3.art = tf3.nt = 0;
+ while (tf2.art < tf2.nt) {
+ struct token *ct = tf2.t + (tf2.art ++);
+
+ if (ttMWS(ct->type)) continue;
+ if (ct->type == NAME) {
+ /*
+ * a rogue identifier; we replace it with "0".
+ */
+ struct token rt;
+#ifdef HAVE_MISRA
+ misra_neu(97,19,11,0);
+#endif
+
+ rt.type = NUMBER;
+ rt.name = "0";
+ aol(tf3.t, tf3.nt, rt, TOKEN_LIST_MEMG);
+ continue;
+ }
+ aol(tf3.t, tf3.nt, *ct, TOKEN_LIST_MEMG);
+ }
+ freemem(tf2.t);
+
+ if (tf3.nt == 0) {
+ error(l, "void condition (after expansion) for a #if/#elif");
+ return -1;
+ }
+ eval_line = l;
+ z = eval_expr(&tf3, &ret, (ls->flags & WARN_STANDARD) != 0);
+ freemem(tf3.t);
+ if (ret) return -1;
+ return (z != 0);
+}
+
+/*
+ * A #include was found; parse the end of line, replace macros if
+ * necessary.
+ *
+ * If nex is set to non-zero, the directive is considered as a #include_next
+ * (extension to C99)
+ */
+static int handle_include(struct lexer_state *ls, unsigned long flags, int nex)
+{
+ int c, string_fname = 0;
+ char *fname;
+ size_t fname_ptr = 0;
+ long l = ls->line;
+ int x, y;
+ FILE *f;
+ struct token_fifo tf, tf2, *save_tf;
+ size_t nl;
+ int tgd;
+
+#define left_angle(t) ((t) == LT || (t) == LEQ || (t) == LSH \
+ || (t) == ASLSH || (t) == DIG_LBRK || (t) == LBRA)
+#define right_angle(t) ((t) == GT || (t) == RSH || (t) == ARROW \
+ || (t) == DIG_RBRK || (t) == DIG_RBRA)
+
+#ifdef HAVE_MISRA
+ extern int misracheck,misratok;
+
+ if(misracheck&&misratok) misra_neu(87,19,1,0);
+#endif
+ tf.t=0; /*vb*/
+ while ((c = grap_char(ls)) >= 0 && c != '\n') {
+ if (space_char(c)) {
+ discard_char(ls);
+ continue;
+ }
+ if (c == '<') {
+ discard_char(ls);
+ while ((c = grap_char(ls)) >= 0) {
+ discard_char(ls);
+ if (c == '\n') goto include_error;
+ if (c == '>') break;
+ aol(fname, fname_ptr, (char)c, FNAME_MEMG);
+ }
+ aol(fname, fname_ptr, (char)0, FNAME_MEMG);
+ string_fname = 0;
+ goto do_include;
+ } else if (c == '"') {
+ discard_char(ls);
+ while ((c = grap_char(ls)) >= 0) {
+ discard_char(ls);
+ if (c == '\n') goto include_error;
+ if (c == '"') break;
+ aol(fname, fname_ptr, (char)c, FNAME_MEMG);
+ }
+ aol(fname, fname_ptr, (char)0, FNAME_MEMG);
+ string_fname = 1;
+ goto do_include;
+ }
+ goto include_macro;
+ }
+
+include_error:
+ error(l, "invalid '#include'");
+ return 1;
+
+include_macro:
+#ifdef HAVE_MISRA
+ misra(90);
+#endif
+ tf.art = tf.nt = 0;
+ while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+ if (!ttMWS(ls->ctok->type)) {
+ struct token t;
+
+ t.type = ls->ctok->type;
+ t.line = l;
+ if (S_TOKEN(ls->ctok->type)) {
+ t.name = sdup(ls->ctok->name);
+ throw_away(ls->gf, t.name);
+ }
+ aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
+ }
+ }
+ tf2.art = tf2.nt = 0;
+ save_tf = ls->output_fifo;
+ ls->output_fifo = &tf2;
+ while (tf.art < tf.nt) {
+ struct token *ct;
+
+ ct = tf.t + (tf.art ++);
+ if (ct->type == NAME) {
+ struct macro *m = get_macro(ct->name);
+ if (m) {
+ if (substitute_macro(ls, m, &tf, 0,
+#ifdef NO_PRAGMA_IN_DIRECTIVE
+ 1,
+#else
+ 0,
+#endif
+ ct->line)) {
+ ls->output_fifo = save_tf;
+ return -1;
+ }
+ continue;
+ }
+ }
+ aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG);
+ }
+ freemem(tf.t);
+ ls->output_fifo = save_tf;
+ for (x = 0; x < tf2.nt && ttWHI(tf2.t[x].type); x ++);
+ for (y = tf2.nt - 1; y >= 0 && ttWHI(tf2.t[y].type); y --);
+ if (x >= tf2.nt) goto include_macro_err;
+ if (tf2.t[x].type == STRING) {
+ if (y != x) goto include_macro_err;
+ if (tf2.t[x].name[0] == 'L') {
+ if (ls->flags & WARN_STANDARD)
+ warning(l, "wide string for #include");
+ fname = sdup(tf2.t[x].name);
+ nl = strlen(fname);
+ *(fname + nl - 1) = 0;
+ mmvwo(fname, fname + 2, nl - 2);
+ } else {
+ fname = sdup(tf2.t[x].name);
+ nl = strlen(fname);
+ *(fname + nl - 1) = 0;
+ mmvwo(fname, fname + 1, nl - 1);
+ }
+ string_fname = 1;
+ } else if (left_angle(tf2.t[x].type) && right_angle(tf2.t[y].type)) {
+ int i, j;
+
+ if (ls->flags & WARN_ANNOYING) warning(l, "reconstruction "
+ "of <foo> in #include");
+ for (j = 0, i = x; i <= y; i ++) if (!ttWHI(tf2.t[i].type))
+ j += strlen(tname(tf2.t[i]));
+ fname = getmem(j + 1);
+ for (j = 0, i = x; i <= y; i ++) {
+ if (ttWHI(tf2.t[i].type)) continue;
+ strcpy(fname + j, tname(tf2.t[i]));
+ j += strlen(tname(tf2.t[i]));
+ }
+ *(fname + j - 1) = 0;
+ mmvwo(fname, fname + 1, j);
+ string_fname = 0;
+ } else goto include_macro_err;
+ freemem(tf2.t);
+ goto do_include_next;
+
+include_macro_err:
+ error(l, "macro expansion did not produce a valid filename "
+ "for #include");
+ if (tf2.nt) freemem(tf2.t);
+ return 1;
+
+do_include:
+ tgd = 1;
+ while (!next_token(ls)) {
+ if (tgd && !ttWHI(ls->ctok->type)
+ && (ls->flags & WARN_STANDARD)) {
+ warning(l, "trailing garbage in #include");
+ tgd = 0;
+ }
+ if (ls->ctok->type == NEWLINE) break;
+ }
+
+ /* the increment of ls->line is intended so that the line
+ numbering is reported correctly in report_context() even if
+ the #include is at the end of the line with no trailing newline */
+ if (ls->ctok->type != NEWLINE) ls->line ++;
+do_include_next:
+ if (!(ls->flags & LEXER) && (ls->flags & KEEP_OUTPUT))
+ put_char(ls, '\n');
+ push_file_context(ls);
+ reinit_lexer_state(ls, 1);
+#ifdef HAVE_MISRA
+ if(misracheck){
+ char *p;
+ for(p=fname;*p;p++)
+ if(*p=='\''||*p=='\\'||*p=='\"'||(*p=='/'&&p[1]=='*'))
+ misra_neu(88,19,2,-1);
+ }
+#endif
+ {
+ char *conv_fname = convert_path(fname);
+ freemem(fname);
+ fname = conv_fname;
+ }
+ f = nex ? find_file_next(fname) : find_file(fname, string_fname);
+ if (!f) {
+ pop_file_context(ls);
+ if (find_file_error == FF_ERROR) {
+ error(l, "file '%s' not found", fname);
+ return 1;
+ }
+ /* file was found, but it is useless to include it again */
+ return 0;
+ }
+#ifdef UCPP_MMAP
+ set_input_file(ls, f);
+#else
+ ls->input = f;
+#endif
+#ifdef HAVE_MISRA
+ if (!strcmp("signal.h",fname)) misra_neu(123,20,8,-1);
+ if (!strcmp("stdio.h",fname)) misra_neu(124,20,9,-1);
+ if (!strcmp("time.h",fname)) misra(127,20,12,-1);
+#endif
+ set_current_filename(fname);
+ handle_deps(current_long_filename,string_fname);
+ enter_file(ls, flags);
+ return 0;
+
+#undef left_angle
+#undef right_angle
+}
+
+/*
+ * for #line directives
+ */
+static int handle_line(struct lexer_state *ls, unsigned long flags)
+{
+ char *fname;
+ long l = ls->line;
+ struct token_fifo tf, tf2, *save_tf;
+ size_t nl, j;
+ unsigned long z;
+
+ tf.art = tf.nt = 0;
+ while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+ if (!ttMWS(ls->ctok->type)) {
+ struct token t;
+
+ t.type = ls->ctok->type;
+ t.line = l;
+ if (S_TOKEN(ls->ctok->type)) {
+ t.name = sdup(ls->ctok->name);
+ throw_away(ls->gf, t.name);
+ }
+ aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
+ }
+ }
+ tf2.art = tf2.nt = 0;
+ save_tf = ls->output_fifo;
+ ls->output_fifo = &tf2;
+ while (tf.art < tf.nt) {
+ struct token *ct;
+
+ ct = tf.t + (tf.art ++);
+ if (ct->type == NAME) {
+ struct macro *m = get_macro(ct->name);
+ if (m) {
+ if (substitute_macro(ls, m, &tf, 0,
+#ifdef NO_PRAGMA_IN_DIRECTIVE
+ 1,
+#else
+ 0,
+#endif
+ ct->line)) {
+ ls->output_fifo = save_tf;
+ return -1;
+ }
+ continue;
+ }
+ }
+ aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG);
+ }
+ freemem(tf.t);
+ for (tf2.art = 0; tf2.art < tf2.nt && ttWHI(tf2.t[tf2.art].type);
+ tf2.art ++);
+ ls->output_fifo = save_tf;
+ if (tf2.art == tf2.nt || (tf2.t[tf2.art].type != NUMBER
+ && tf2.t[tf2.art].type != CHAR)) {
+ error(l, "not a valid number for #line");
+ goto line_macro_err;
+ }
+ for (j = 0; tf2.t[tf2.art].name[j]; j ++)
+ if (tf2.t[tf2.art].name[j] < '0'
+ || tf2.t[tf2.art].name[j] > '9')
+ if (ls->flags & WARN_STANDARD)
+ warning(l, "non-standard line number in #line");
+ if (catch(eval_exception)) goto line_macro_err;
+ z = strtoconst(tf2.t[tf2.art].name);
+ if (j > 10 || z > 2147483647U) {
+ error(l, "out-of-bound line number for #line");
+ goto line_macro_err;
+ }
+ ls->oline = ls->line = z;
+ if ((++ tf2.art) < tf2.nt) {
+ int i;
+
+ for (i = tf2.art; i < tf2.nt && ttMWS(tf2.t[i].type); i ++);
+ if (i < tf2.nt) {
+ if (tf2.t[i].type != STRING) {
+ error(l, "not a valid filename for #line");
+ goto line_macro_err;
+ }
+ if (tf2.t[i].name[0] == 'L') {
+ if (ls->flags & WARN_STANDARD) {
+ warning(l, "wide string for #line");
+ }
+ fname = sdup(tf2.t[i].name);
+ nl = strlen(fname);
+ *(fname + nl - 1) = 0;
+ mmvwo(fname, fname + 2, nl - 2);
+ } else {
+ fname = sdup(tf2.t[i].name);
+ nl = strlen(fname);
+ *(fname + nl - 1) = 0;
+ mmvwo(fname, fname + 1, nl - 1);
+ }
+ set_current_filename(fname);
+ }
+ for (i ++; i < tf2.nt && ttMWS(tf2.t[i].type); i ++);
+ if (i < tf2.nt && (ls->flags & WARN_STANDARD)) {
+ warning(l, "trailing garbage in #line");
+ }
+ }
+ freemem(tf2.t);
+ enter_file(ls, flags);
+ return 0;
+
+line_macro_err:
+ if (tf2.nt) freemem(tf2.t);
+ return 1;
+}
+
+/*
+ * a #error or #warning directive: we emit the message without any
+ * modification (except the usual backslash+newline and trigraphs)
+ */
+static void handle_error(struct lexer_state *ls,int warnflag)
+{
+ int c;
+ size_t p = 0, lp = 128;
+ long l = ls->line;
+ unsigned char *buf = getmem(lp);
+
+ while ((c = grap_char(ls)) >= 0 && c != '\n') {
+ discard_char(ls);
+ wan(buf, p, (unsigned char)c, lp);
+ }
+ wan(buf, p, 0, lp);
+ if (warnflag)
+ warning(l, "#warning%s", buf);
+ else
+ error(l, "#error%s", buf);
+ freemem(buf);
+}
+
+/*
+ * convert digraph tokens to their standard equivalent.
+ */
+static int undig(int type)
+{
+ static int ud[6] = { LBRK, RBRK, LBRA, RBRA, SHARP, DSHARP };
+
+ return ud[type - DIG_LBRK];
+}
+
+#ifdef PRAGMA_TOKENIZE
+/*
+ * Make a compressed representation of a token list; the contents of
+ * the token_fifo are freed. Values equal to 0 are replaced by
+ * PRAGMA_TOKEN_END (by default, (unsigned char)'\n') and the compressed
+ * string is padded by a 0 (so that it may be * handled like a string).
+ * Digraph tokens are replaced by their non-digraph equivalents.
+ */
+struct comp_token_fifo compress_token_list(struct token_fifo *tf)
+{
+ struct comp_token_fifo ct;
+ size_t l;
+
+ for (l = 0, tf->art = 0; tf->art < tf->nt; tf->art ++) {
+ l ++;
+ if (S_TOKEN(tf->t[tf->art].type))
+ l += strlen(tf->t[tf->art].name) + 1;
+ }
+ ct.t = getmem((ct.length = l) + 1);
+ for (l = 0, tf->art = 0; tf->art < tf->nt; tf->art ++) {
+ int tt = tf->t[tf->art].type;
+
+ if (tt == 0) tt = PRAGMA_TOKEN_END;
+ if (tt > DIGRAPH_TOKENS && tt < DIGRAPH_TOKENS_END)
+ tt = undig(tt);
+ ct.t[l ++] = tt;
+ if (S_TOKEN(tt)) {
+ char *tn = tf->t[tf->art].name;
+ size_t sl = strlen(tn);
+
+ mmv(ct.t + l, tn, sl);
+ l += sl;
+ ct.t[l ++] = PRAGMA_TOKEN_END;
+ freemem(tn);
+ }
+ }
+ ct.t[l] = 0;
+ if (tf->nt) freemem(tf->t);
+ ct.rp = 0;
+ return ct;
+}
+#endif
+
+/*
+ * A #pragma directive: we make a PRAGMA token containing the rest of
+ * the line.
+ *
+ * We strongly hope that we are called only in LEXER mode.
+ */
+static void handle_pragma(struct lexer_state *ls)
+{
+ unsigned char *buf;
+ struct token t;
+ long l = ls->line;
+
+#ifdef PRAGMA_TOKENIZE
+ struct token_fifo tf;
+
+ tf.art = tf.nt = 0;
+ while (!next_token(ls) && ls->ctok->type != NEWLINE)
+ if (!ttMWS(ls->ctok->type)) break;
+ if (ls->ctok->type != NEWLINE) {
+ do {
+ struct token t;
+
+ t.type = ls->ctok->type;
+ if (ttMWS(t.type)) continue;
+ if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
+ aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
+ } while (!next_token(ls) && ls->ctok->type != NEWLINE);
+ }
+ if (tf.nt == 0) {
+ /* void pragma are silently ignored */
+ return;
+ }
+ buf = (compress_token_list(&tf)).t;
+#else
+ int c, x = 1, y = 32;
+
+ while ((c = grap_char(ls)) >= 0 && c != '\n') {
+ discard_char(ls);
+ if (!space_char(c)) break;
+ }
+ /* void #pragma are ignored */
+ if (c == '\n') return;
+ buf = getmem(y);
+ buf[0] = c;
+ while ((c = grap_char(ls)) >= 0 && c != '\n') {
+ discard_char(ls);
+ wan(buf, x, c, y);
+ }
+ for (x --; x >= 0 && space_char(buf[x]); x --);
+ x ++;
+ wan(buf, x, 0, y);
+#endif
+ t.type = PRAGMA;
+ t.line = l;
+ t.name = (char *)buf;
+ aol(ls->output_fifo->t, ls->output_fifo->nt, t, TOKEN_LIST_MEMG);
+ throw_away(ls->gf, (char *)buf);
+}
+
+/*
+ * We saw a # at the beginning of a line (or preceeded only by whitespace).
+ * We check the directive name and act accordingly.
+ */
+static int handle_cpp(struct lexer_state *ls, int sharp_type)
+{
+#define condfset(x) do { \
+ ls->condf[(x) / 32] |= 1UL << ((x) % 32); \
+ } while (0)
+#define condfclr(x) do { \
+ ls->condf[(x) / 32] &= ~(1UL << ((x) % 32)); \
+ } while (0)
+#define condfval(x) ((ls->condf[(x) / 32] & (1UL << ((x) % 32))) != 0)
+
+ long l = ls->line;
+ unsigned long save_flags = ls->flags;
+ int ret = 0;
+
+ save_flags = ls->flags;
+ ls->flags |= LEXER;
+ while (!next_token(ls)) {
+ int t = ls->ctok->type;
+
+ switch (t) {
+ case COMMENT:
+ if (ls->flags & WARN_ANNOYING) {
+ warning(l, "comment in the middle of "
+ "a cpp directive");
+ }
+ /* fall through */
+ case NONE:
+ continue;
+ case NEWLINE:
+ /* null directive */
+ if (ls->flags & WARN_ANNOYING) {
+ /* truly an annoying warning; null directives
+ are rare but may increase readability of
+ some source files, and they are legal */
+ warning(l, "null cpp directive");
+ }
+ if (!(ls->flags & LEXER)) put_char(ls, '\n');
+ goto handle_exit2;
+ case NAME:
+ break;
+ default:
+ if (ls->flags & FAIL_SHARP) {
+ if (ls->condcomp) {
+ error(l, "rogue '#'");
+ ret = 1;
+ } else {
+ if (ls->flags & WARN_STANDARD) {
+ warning(l, "rogue '#' in code "
+ "compiled out");
+ ret = 0;
+ }
+ }
+ ls->flags = save_flags;
+ goto handle_warp_ign;
+ } else {
+ struct token u;
+
+ u.type = sharp_type;
+ u.line = l;
+ ls->flags = save_flags;
+ print_token(ls, &u, 0);
+ print_token(ls, ls->ctok, 0);
+ if (ls->flags & WARN_ANNOYING) {
+ warning(l, "rogue '#' dumped");
+ }
+ goto handle_exit3;
+ }
+ }
+ if (ls->condcomp) {
+ if (!strcmp(ls->ctok->name, "define")) {
+ ret = handle_define(ls);
+ goto handle_exit;
+ } else if (!strcmp(ls->ctok->name, "undef")) {
+ ret = handle_undef(ls);
+ goto handle_exit;
+ } else if (!strcmp(ls->ctok->name, "if")) {
+ if ((++ ls->ifnest) > 63) goto too_many_if;
+ condfclr(ls->ifnest - 1);
+ ret = handle_if(ls);
+ if (ret > 0) ret = 0;
+ else if (ret == 0) {
+ ls->condcomp = 0;
+ ls->condmet = 0;
+ ls->condnest = ls->ifnest - 1;
+ }
+ else ret = 1;
+ goto handle_exit;
+ } else if (!strcmp(ls->ctok->name, "ifdef")) {
+ if ((++ ls->ifnest) > 63) goto too_many_if;
+ condfclr(ls->ifnest - 1);
+
+ ret = handle_ifdef(ls);
+ if (ret > 0) ret = 0;
+ else if (ret == 0) {
+ ls->condcomp = 0;
+ ls->condmet = 0;
+ ls->condnest = ls->ifnest - 1;
+ }
+ else ret = 1;
+ goto handle_exit;
+ } else if (!strcmp(ls->ctok->name, "ifndef")) {
+ if ((++ ls->ifnest) > 63) goto too_many_if;
+ condfclr(ls->ifnest - 1);
+ ret = handle_ifndef(ls);
+ if (ret > 0) ret = 0;
+ else if (ret == 0) {
+ ls->condcomp = 0;
+ ls->condmet = 0;
+ ls->condnest = ls->ifnest - 1;
+ }
+ else ret = 1;
+ goto handle_exit;
+ } else if (!strcmp(ls->ctok->name, "else")) {
+ if (ls->ifnest == 0
+ || condfval(ls->ifnest - 1)) {
+ error(l, "rogue #else");
+ ret = 1;
+ goto handle_warp;
+ }
+ condfset(ls->ifnest - 1);
+ if (ls->ifnest == 1) protect_detect.state = 0;
+ ls->condcomp = 0;
+ ls->condmet = 1;
+ ls->condnest = ls->ifnest - 1;
+ goto handle_warp;
+ } else if (!strcmp(ls->ctok->name, "elif")) {
+ if (ls->ifnest == 0
+ || condfval(ls->ifnest - 1)) {
+ error(l, "rogue #elif");
+ ret = 1;
+ goto handle_warp_ign;
+ }
+ if (ls->ifnest == 1) protect_detect.state = 0;
+ ls->condcomp = 0;
+ ls->condmet = 1;
+ ls->condnest = ls->ifnest - 1;
+ goto handle_warp_ign;
+ } else if (!strcmp(ls->ctok->name, "endif")) {
+ if (ls->ifnest == 0) {
+ error(l, "unmatched #endif");
+ ret = 1;
+ goto handle_warp;
+ }
+ if ((-- ls->ifnest) == 0
+ && protect_detect.state == 2) {
+ protect_detect.state = 3;
+ }
+ goto handle_warp;
+ } else if (!strcmp(ls->ctok->name, "include")) {
+ ret = handle_include(ls, save_flags, 0);
+ goto handle_exit3;
+ } else if (!strcmp(ls->ctok->name, "include_next")) {
+ ret = handle_include(ls, save_flags, 1);
+ goto handle_exit3;
+ } else if (!strcmp(ls->ctok->name, "pragma")) {
+ if (!(save_flags & LEXER)) {
+#ifdef PRAGMA_DUMP
+ /* dump #pragma in output */
+ struct token u;
+
+ u.type = sharp_type;
+ u.line = l;
+ ls->flags = save_flags;
+ print_token(ls, &u, 0);
+ print_token(ls, ls->ctok, 0);
+ while (ls->flags |= LEXER,
+ !next_token(ls)) {
+ long save_line;
+
+ ls->flags &= ~LEXER;
+ save_line = ls->line;
+ ls->line = l;
+ print_token(ls, ls->ctok, 0);
+ ls->line = save_line;
+ if (ls->ctok->type == NEWLINE)
+ break;
+ }
+ goto handle_exit3;
+#else
+ if (ls->flags & WARN_PRAGMA)
+ warning(l, "#pragma ignored "
+ "and not dumped");
+ goto handle_warp_ign;
+#endif
+ }
+ if (!(ls->flags & HANDLE_PRAGMA))
+ goto handle_warp_ign;
+ handle_pragma(ls);
+ goto handle_exit;
+ } else if (!strcmp(ls->ctok->name, "error")) {
+ ret = 1;
+ handle_error(ls,0);
+ goto handle_exit;
+ } else if (!strcmp(ls->ctok->name, "warning")) {
+ ret = 0;
+ handle_error(ls,1);
+ goto handle_exit;
+ } else if (!strcmp(ls->ctok->name, "line")) {
+ ret = handle_line(ls, save_flags);
+ goto handle_exit;
+ } else if ((ls->flags & HANDLE_ASSERTIONS)
+ && !strcmp(ls->ctok->name, "assert")) {
+ ret = handle_assert(ls);
+ goto handle_exit;
+ } else if ((ls->flags & HANDLE_ASSERTIONS)
+ && !strcmp(ls->ctok->name, "unassert")) {
+ ret = handle_unassert(ls);
+ goto handle_exit;
+ }
+ } else {
+ if (!strcmp(ls->ctok->name, "else")) {
+ if (condfval(ls->ifnest - 1)
+ && (ls->flags & WARN_STANDARD)) {
+ warning(l, "rogue #else in code "
+ "compiled out");
+ }
+ if (ls->condnest == ls->ifnest - 1) {
+ if (!ls->condmet) ls->condcomp = 1;
+ }
+ condfset(ls->ifnest - 1);
+ if (ls->ifnest == 1) protect_detect.state = 0;
+ goto handle_warp;
+ } else if (!strcmp(ls->ctok->name, "elif")) {
+ if (condfval(ls->ifnest - 1)
+ && (ls->flags & WARN_STANDARD)) {
+ warning(l, "rogue #elif in code "
+ "compiled out");
+ }
+ if (ls->condnest != ls->ifnest - 1
+ || ls->condmet)
+ goto handle_warp_ign;
+ if (ls->ifnest == 1) protect_detect.state = 0;
+ ret = handle_if(ls);
+ if (ret > 0) {
+ ls->condcomp = 1;
+ ls->condmet = 1;
+ ret = 0;
+ } else if (ret < 0) ret = 1;
+ goto handle_exit;
+ } else if (!strcmp(ls->ctok->name, "endif")) {
+ if ((-- ls->ifnest) == ls->condnest) {
+ if (ls->ifnest == 0 &&
+ protect_detect.state == 2)
+ protect_detect.state = 3;
+ ls->condcomp = 1;
+ }
+ goto handle_warp;
+ } else if (!strcmp(ls->ctok->name, "if")
+ || !strcmp(ls->ctok->name, "ifdef")
+ || !strcmp(ls->ctok->name, "ifndef")) {
+ if ((++ ls->ifnest) > 63) goto too_many_if;
+ condfclr(ls->ifnest - 1);
+ }
+ goto handle_warp_ign;
+ }
+ /*
+ * Unrecognized directive. We emit either an error or
+ * an annoying warning, depending on a command-line switch.
+ */
+ if (ls->flags & FAIL_SHARP) {
+ error(l, "unknown cpp directive '#%s'",
+ ls->ctok->name);
+ goto handle_warp_ign;
+ } else {
+ struct token u;
+
+ u.type = sharp_type;
+ u.line = l;
+ ls->flags = save_flags;
+ print_token(ls, &u, 0);
+ print_token(ls, ls->ctok, 0);
+ if (ls->flags & WARN_ANNOYING) {
+ warning(l, "rogue '#' dumped");
+ }
+ }
+ }
+ return 1;
+
+handle_warp_ign:
+ while (!next_token(ls)) if (ls->ctok->type == NEWLINE) break;
+ goto handle_exit;
+handle_warp:
+ while (!next_token(ls)) {
+ if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
+ warning(l, "trailing garbage in "
+ "preprocessing directive");
+ }
+ if (ls->ctok->type == NEWLINE) break;
+ }
+handle_exit:
+ if (!(ls->flags & LEXER)) put_char(ls, '\n');
+handle_exit3:
+ if (protect_detect.state == 1) {
+ protect_detect.state = 0;
+ } else if (protect_detect.state == -1) {
+ /* just after the #include */
+ protect_detect.state = 1;
+ }
+handle_exit2:
+ ls->flags = save_flags;
+ return ret;
+too_many_if:
+ error(l, "too many levels of conditional inclusion (max 63)");
+ ret = 1;
+ goto handle_warp;
+#undef condfset
+#undef condfclr
+#undef condfval
+}
+
+/*
+ * This is the main entry function. It maintains count of #, and call the
+ * appropriate functions when it encounters a cpp directive or a macro
+ * name.
+ * return value: positive on error; CPPERR_EOF means "end of input reached"
+ */
+int cpp(struct lexer_state *ls)
+{
+ int r = 0;
+
+ while (next_token(ls)) {
+ if (protect_detect.state == 3) {
+ /* Cool ! A protection mechanism has been detected */
+ protect_detect.ff->protect = protect_detect.macro;
+ protect_detect.macro = 0;
+ }
+ if (ls->ifnest) {
+ error(ls->line, "unterminated #if construction "
+ "(depth %ld)", (long)ls->ifnest);
+ r = CPPERR_NEST;
+ }
+ if (ls_depth == 0) return CPPERR_EOF;
+ fclose(ls->input);
+ freemem(current_filename);
+ pop_file_context(ls);
+ if (!(ls->flags & LEXER) && !ls->ltwnl) put_char(ls, '\n');
+ enter_file(ls, ls->flags);
+ }
+ if (!(ls->ltwnl && (ls->ctok->type == SHARP
+ || ls->ctok->type == DIG_SHARP))
+ && protect_detect.state == 1 && !ttWHI(ls->ctok->type)) {
+ /* the first non-whitespace token encountered is not
+ a sharp introducing a cpp directive */
+ protect_detect.state = 0;
+ }
+ if (protect_detect.state == 3 && !ttWHI(ls->ctok->type)) {
+ /* a non-whitespace token encountered after the #endif */
+ protect_detect.state = 0;
+ }
+ if (ls->condcomp) {
+ if (ls->ltwnl && (ls->ctok->type == SHARP
+ || ls->ctok->type == DIG_SHARP)) {
+ int x = handle_cpp(ls, ls->ctok->type);
+
+ ls->ltwnl = 1;
+ return r ? r : x;
+ }
+ if (ls->ctok->type == NAME) {
+ struct macro *m;
+
+ if ((m = get_macro(ls->ctok->name)) != 0) {
+ int x;
+
+ x = substitute_macro(ls, m, 0, 1, 0,
+ ls->ctok->line);
+ if (!(ls->flags & LEXER))
+ garbage_collect(ls->gf);
+ return r ? r : x;
+ }
+ if (!(ls->flags & LEXER))
+ print_token(ls, ls->ctok, 0);
+ }
+ } else {
+ if (ls->ltwnl && (ls->ctok->type == SHARP
+ || ls->ctok->type == DIG_SHARP)) {
+ int x = handle_cpp(ls, ls->ctok->type);
+
+ ls->ltwnl = 1;
+ return r ? r : x;
+ }
+ }
+ if (ls->ctok->type == NEWLINE) ls->ltwnl = 1;
+ else if (!ttWHI(ls->ctok->type)) ls->ltwnl = 0;
+ return r ? r : -1;
+}
+
+#ifndef STAND_ALONE
+/*
+ * llex() and lex() are the lexing functions, when the preprocessor is
+ * linked to another code. llex() should be called only by lex().
+ */
+static int llex(struct lexer_state *ls)
+{
+ struct token_fifo *tf = ls->output_fifo;
+ int r;
+
+ if (tf->nt != 0) {
+ if (tf->art < tf->nt) {
+#ifdef INMACRO_FLAG
+ if (!ls->inmacro) {
+ ls->inmacro = 1;
+ ls->macro_count ++;
+ }
+#endif
+ ls->ctok = tf->t + (tf->art ++);
+ if (ls->ctok->type > DIGRAPH_TOKENS
+ && ls->ctok->type < DIGRAPH_TOKENS_END) {
+ ls->ctok->type = undig(ls->ctok->type);
+ }
+ return 0;
+ } else {
+#ifdef INMACRO_FLAG
+ ls->inmacro = 0;
+#endif
+ if (tf->nt) freemem(tf->t);
+ tf->art = tf->nt = 0;
+ garbage_collect(ls->gf);
+ ls->ctok = ls->save_ctok;
+ }
+
+ }
+ r = cpp(ls);
+ if (ls->ctok->type > DIGRAPH_TOKENS
+ && ls->ctok->type < LAST_MEANINGFUL_TOKEN) {
+ ls->ctok->type = undig(ls->ctok->type);
+ }
+ if (r > 0) return r;
+ if (r < 0) return 0;
+ return llex(ls);
+}
+
+/*
+ * lex() reads the next token from the processed stream and stores it
+ * into ls->ctok.
+ * return value: non zero on error (including CPPERR_EOF, which is not
+ * quite an error)
+ */
+int lex(struct lexer_state *ls)
+{
+ int r;
+
+ do {
+ r = llex(ls);
+#ifdef SEMPER_FIDELIS
+ } while (!r && !ls->condcomp);
+#else
+ } while (!r && (!ls->condcomp || (ttWHI(ls->ctok->type) &&
+ (!(ls->flags & LINE_NUM) || ls->ctok->type != NEWLINE))));
+#endif
+ return r;
+}
+#endif
+
+/*
+ * check_cpp_errors() must be called when the end of input is reached;
+ * it checks pending errors due to truncated constructs (actually none,
+ * this is reserved for future evolutions).
+ */
+int check_cpp_errors(struct lexer_state *ls)
+{
+ return 0;
+}
+
+/*
+ * init_cpp() initializes everything that should be initialized.
+ * If standard_inc is non-zero, the standard include directories are
+ * added to the search path.
+ */
+void init_cpp(void)
+{
+ init_cppm();
+ init_buf_lexer_state(&dsharp_lexer, 0);
+#ifdef PRAGMA_TOKENIZE
+ init_buf_lexer_state(&tokenize_lexer, 0);
+#endif
+}
+
+/*
+ * (re)init the global tables.
+ * If standard_assertions is non 0, init the assertions table.
+ */
+void init_tables(int with_assertions)
+{
+ time_t t;
+ struct tm *ct;
+
+ time(&t);
+ ct = localtime(&t);
+#ifdef MSDOS
+ /* no function strftime() in TurboC 2.01 */
+ {
+ char *c = asctime(ct);
+
+ compile_time[0] = '"';
+ mmv(compile_time + 1, c + 11, 8);
+ compile_time[9] = '"';
+ compile_time[10] = 0;
+ compile_date[0] = '"';
+ mmv(compile_date + 1, c + 4, 7);
+ mmv(compile_date + 8, c + 20, 4);
+ compile_date[12] = '"';
+ compile_date[13] = 0;
+ }
+#else
+ strftime(compile_time, 12, "\"%H:%M:%S\"", ct);
+ strftime(compile_date, 24, "\"%b %d %Y\"", ct);
+#endif
+ sprintf(compile_adate,"\"(%02d.%02d.%02d)\"",
+ ct->tm_mday,ct->tm_mon+1,ct->tm_year%100);
+ init_macros();
+ if (with_assertions) init_assertions();
+ init_found_files();
+}
+
+/*
+ * Resets the include path.
+ */
+void init_include_path(char *incpath[])
+{
+ if (include_path_nb) {
+ int i;
+
+ for (i = 0; i < include_path_nb; i ++)
+ freemem(include_path[i]);
+ freemem(include_path);
+ include_path_nb = 0;
+ }
+ if (incpath) {
+ int i;
+
+ for (i = 0; incpath[i]; i ++)
+ aol(include_path, include_path_nb, convert_path(incpath[i]), INCPATH_MEMG);
+ }
+}
+
+/*
+ * add_incpath() adds "path" to the standard include path.
+ */
+void add_incpath(char *path)
+{
+ aol(include_path, include_path_nb, convert_path(path), INCPATH_MEMG);
+}
+
+#ifdef STAND_ALONE
+/*
+ * print some help
+ */
+static void usage(char *command_name)
+{
+ fprintf(stderr,
+ "Usage: %s [options] [file]\n"
+ "language options:\n"
+ " -C keep comments in output\n"
+ " -s keep '#' when no cpp directive is recognized\n"
+ " -l do not emit line numbers\n"
+ " -lg emit gcc-like line numbers\n"
+ " -CC disable C++-like comments\n"
+ " -a, -na, -a0 handle (or not) assertions\n"
+ " -V disable macros with extra arguments\n"
+ " -u understand UTF-8 in source\n"
+ " -X enable -a, -u and -Y\n"
+ " -c90 mimic C90 behaviour\n"
+ " -t disable trigraph support\n"
+ "warning options:\n"
+ " -wt emit a final warning when trigaphs are encountered\n"
+ " -wtt emit warnings for each trigaph encountered\n"
+ " -wa emit warnings that are usually useless\n"
+ " -w0 disable standard warnings\n"
+ "directory options:\n"
+ " -I directory add 'directory' before the standard include path\n"
+ " -J directory add 'directory' after the standard include path\n"
+ " -zI do not use the standard include path\n"
+ " -M emit Makefile-like dependencies instead of normal "
+ "output\n"
+ " -Ma emit also dependancies for system files\n"
+ " -o file store output in file\n"
+ "macro and assertion options:\n"
+ " -Dmacro predefine 'macro'\n"
+ " -Dmacro=def predefine 'macro' with 'def' content\n"
+ " -Umacro undefine 'macro'\n"
+ " -Afoo(bar) assert foo(bar)\n"
+ " -Bfoo(bar) unassert foo(bar)\n"
+ " -Y predefine system-dependant macros\n"
+ " -Z do not predefine special macros\n"
+ " -d emit defined macros\n"
+ " -e emit assertions\n"
+ "misc options:\n"
+ " -v print version number and settings\n"
+ " -h show this help\n",
+ command_name);
+}
+
+/*
+ * print version and compile-time settings
+ */
+static void version(void)
+{
+ size_t i;
+
+ fprintf(stderr, "ucpp version %d.%d\n", VERS_MAJ, VERS_MIN);
+ fprintf(stderr, "search path:\n");
+ for (i = 0; i < include_path_nb; i ++)
+ fprintf(stderr, " %s\n", include_path[i]);
+}
+
+/*
+ * parse_opt() initializes many things according to the command-line
+ * options.
+ * Return values:
+ * 0 on success
+ * 1 on semantic error (redefinition of a special macro, for instance)
+ * 2 on syntaxic error (unknown options for instance)
+ */
+static int parse_opt(int argc, char *argv[], struct lexer_state *ls)
+{
+ int i, ret = 0;
+ char *filename = 0;
+ int with_std_incpath = 1;
+ int print_version = 0, print_defs = 0, print_asserts = 0;
+ int system_macros = 0, standard_assertions = 1;
+
+ init_lexer_state(ls);
+ ls->flags = DEFAULT_CPP_FLAGS;
+ emit_output = ls->output = stdout;
+ for (i = 1; i < argc; i ++) if (argv[i][0] == '-') {
+ if (!strcmp(argv[i], "-h")) {
+ return 2;
+ } else if (!strcmp(argv[i], "-C")) {
+ ls->flags &= ~DISCARD_COMMENTS;
+ } else if (!strcmp(argv[i], "-CC")) {
+ ls->flags &= ~CPLUSPLUS_COMMENTS;
+ } else if (!strcmp(argv[i], "-a")) {
+ ls->flags |= HANDLE_ASSERTIONS;
+ } else if (!strcmp(argv[i], "-na")) {
+ ls->flags |= HANDLE_ASSERTIONS;
+ standard_assertions = 0;
+ } else if (!strcmp(argv[i], "-a0")) {
+ ls->flags &= ~HANDLE_ASSERTIONS;
+ } else if (!strcmp(argv[i], "-V")) {
+ ls->flags &= ~MACRO_VAARG;
+ } else if (!strcmp(argv[i], "-u")) {
+ ls->flags |= UTF8_SOURCE;
+ } else if (!strcmp(argv[i], "-X")) {
+ ls->flags |= HANDLE_ASSERTIONS;
+ ls->flags |= UTF8_SOURCE;
+ system_macros = 1;
+ } else if (!strcmp(argv[i], "-c90")) {
+ ls->flags &= ~MACRO_VAARG;
+ ls->flags &= ~CPLUSPLUS_COMMENTS;
+ c99_compliant = 0;
+ c99_hosted = -1;
+ } else if (!strcmp(argv[i], "-t")) {
+ ls->flags &= ~HANDLE_TRIGRAPHS;
+ } else if (!strcmp(argv[i], "-wt")) {
+ ls->flags |= WARN_TRIGRAPHS;
+ } else if (!strcmp(argv[i], "-wtt")) {
+ ls->flags |= WARN_TRIGRAPHS_MORE;
+ } else if (!strcmp(argv[i], "-wa")) {
+ ls->flags |= WARN_ANNOYING;
+ } else if (!strcmp(argv[i], "-w0")) {
+ ls->flags &= ~WARN_STANDARD;
+ ls->flags &= ~WARN_PRAGMA;
+ } else if (!strcmp(argv[i], "-s")) {
+ ls->flags &= ~FAIL_SHARP;
+ } else if (!strcmp(argv[i], "-l")) {
+ ls->flags &= ~LINE_NUM;
+ } else if (!strcmp(argv[i], "-lg")) {
+ ls->flags |= GCC_LINE_NUM;
+ } else if (!strcmp(argv[i], "-M")) {
+ ls->flags &= ~KEEP_OUTPUT;
+ emit_dependencies = 1;
+ } else if (!strcmp(argv[i], "-Ma")) {
+ ls->flags &= ~KEEP_OUTPUT;
+ emit_dependencies = 2;
+ } else if (!strcmp(argv[i], "-Y")) {
+ system_macros = 1;
+ } else if (!strcmp(argv[i], "-Z")) {
+ no_special_macros = 1;
+ } else if (!strcmp(argv[i], "-d")) {
+ ls->flags &= ~KEEP_OUTPUT;
+ print_defs = 1;
+ } else if (!strcmp(argv[i], "-e")) {
+ ls->flags &= ~KEEP_OUTPUT;
+ print_asserts = 1;
+ } else if (!strcmp(argv[i], "-zI")) {
+ with_std_incpath = 0;
+ } else if (!strcmp(argv[i], "-I") || !strcmp(argv[i], "-J")) {
+ i ++;
+ } else if (!strcmp(argv[i], "-o")) {
+ if ((++ i) >= argc) {
+ error(-1, "missing filename after -o");
+ return 2;
+ }
+ if (argv[i][0] == '-' && argv[i][1] == 0) {
+ emit_output = ls->output = stdout;
+ } else {
+ ls->output = fopen(argv[i], "w");
+ if (!ls->output) {
+ error(-1, "failed to open for "
+ "writing: %s", argv[i]);
+ return 2;
+ }
+ emit_output = ls->output;
+ }
+ } else if (!strcmp(argv[i], "-v")) {
+ print_version = 1;
+ } else if (argv[i][1] != 'I' && argv[i][1] != 'J'
+ && argv[i][1] != 'D' && argv[i][1] != 'U'
+ && argv[i][1] != 'A' && argv[i][1] != 'B')
+ warning(-1, "unknown option '%s'", argv[i]);
+ } else {
+ if (filename != 0) {
+ error(-1, "spurious filename '%s'", argv[i]);
+ return 2;
+ }
+ filename = argv[i];
+ }
+ init_tables(ls->flags & HANDLE_ASSERTIONS);
+ init_include_path(0);
+ if (filename) {
+#ifdef UCPP_MMAP
+ FILE *f = fopen_mmap_file(filename);
+
+ ls->input = 0;
+ if (f) set_input_file(ls, f);
+#else
+ ls->input = fopen(filename, "r");
+#endif
+ if (!ls->input) {
+ error(-1, "file '%s' not found", filename);
+ return 1;
+ }
+#ifdef NO_LIBC_BUF
+ setbuf(ls->input, 0);
+#endif
+ set_init_filename(filename, 1);
+ } else {
+ ls->input = stdin;
+ set_init_filename("<stdin>", 0);
+ }
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-' && argv[i][1] == 'I')
+ add_incpath(argv[i][2] ? argv[i] + 2 : argv[i + 1]);
+ if (system_macros) for (i = 0; system_macros_def[i]; i ++)
+ ret = ret || define_macro(ls, system_macros_def[i]);
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-' && argv[i][1] == 'D')
+ ret = ret || define_macro(ls, argv[i] + 2);
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-' && argv[i][1] == 'U')
+ ret = ret || undef_macro(ls, argv[i] + 2);
+ if (ls->flags & HANDLE_ASSERTIONS) {
+ if (standard_assertions)
+ for (i = 0; system_assertions_def[i]; i ++)
+ make_assertion(system_assertions_def[i]);
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-' && argv[i][1] == 'A')
+ ret = ret || make_assertion(argv[i] + 2);
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-' && argv[i][1] == 'B')
+ ret = ret || destroy_assertion(argv[i] + 2);
+ } else {
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-'
+ && (argv[i][1] == 'A' || argv[i][1] == 'B'))
+ warning(-1, "assertions disabled");
+ }
+ if (with_std_incpath) {
+ for (i = 0; include_path_std[i]; i ++)
+ add_incpath(include_path_std[i]);
+ }
+ for (i = 1; i < argc; i ++)
+ if (argv[i][0] == '-' && argv[i][1] == 'J')
+ add_incpath(argv[i][2] ? argv[i] + 2 : argv[i + 1]);
+
+ if (print_version) {
+ version();
+ return 1;
+ }
+ if (print_defs) {
+ print_defines();
+ emit_defines = 1;
+ }
+ if (print_asserts && (ls->flags & HANDLE_ASSERTIONS)) {
+ print_assertions();
+ emit_assertions = 1;
+ }
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ struct lexer_state ls;
+ int r, fr = 0;
+
+ init_cpp();
+ if ((r = parse_opt(argc, argv, &ls)) != 0) {
+ if (r == 2) usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ enter_file(&ls, ls.flags);
+ while ((r = cpp(&ls)) < CPPERR_EOF) fr = fr || (r > 0);
+ fr = fr || check_cpp_errors(&ls);
+ if (ls.flags & KEEP_OUTPUT) {
+ /* while (ls.line > ls.oline) put_char(&ls, '\n'); */
+ put_char(&ls, '\n');
+ }
+ if (emit_dependencies) fputc('\n', emit_output);
+#ifndef NO_UCPP_BUF
+ if (!(ls.flags & LEXER)) {
+ flush_output(&ls);
+ }
+#endif
+ if (ls.flags & WARN_TRIGRAPHS && ls.count_trigraphs)
+ warning(0, "%ld trigraphs encountered", ls.count_trigraphs);
+ return fr ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+#endif
diff --git a/ucpp/cpp.h b/ucpp/cpp.h
new file mode 100755
index 0000000..4f0a709
--- /dev/null
+++ b/ucpp/cpp.h
@@ -0,0 +1,316 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef UCPP__CPP__
+#define UCPP__CPP__
+
+/*
+ * Uncomment the following if you want ucpp to use externally provided
+ * error-reporting functions (ucpp_warning(), ucpp_error() and ucpp_ouch())
+ */
+/* #define NO_UCPP_ERROR_FUNCTIONS */
+
+/*
+ * Tokens (do not change the order unless checking operators_name[] in cpp.c)
+ *
+ * It is important that the token NONE is 0
+ * Check the STRING_TOKEN macro
+ */
+#define CPPERR 512
+enum {
+ NONE, /* whitespace */
+ NEWLINE, /* newline */
+ COMMENT, /* comment */
+ NUMBER, /* number constant */
+ NAME, /* identifier */
+ BUNCH, /* non-C characters */
+ PRAGMA, /* a #pragma directive */
+ CONTEXT, /* new file or #line */
+ STRING, /* constant "xxx" */
+ CHAR, /* constant 'xxx' */
+ SLASH, /* / */
+ ASSLASH, /* /= */
+ MINUS, /* - */
+ MMINUS, /* -- */
+ ASMINUS, /* -= */
+ ARROW, /* -> */
+ PLUS, /* + */
+ PPLUS, /* ++ */
+ ASPLUS, /* += */
+ LT, /* < */
+ LEQ, /* <= */
+ LSH, /* << */
+ ASLSH, /* <<= */
+ GT, /* > */
+ GEQ, /* >= */
+ RSH, /* >> */
+ ASRSH, /* >>= */
+ ASGN, /* = */
+ SAME, /* == */
+#ifdef CAST_OP
+ CAST, /* => */
+#endif
+ NOT, /* ~ */
+ NEQ, /* != */
+ AND, /* & */
+ LAND, /* && */
+ ASAND, /* &= */
+ OR, /* | */
+ LOR, /* || */
+ ASOR, /* |= */
+ PCT, /* % */
+ ASPCT, /* %= */
+ STAR, /* * */
+ ASSTAR, /* *= */
+ CIRC, /* ^ */
+ ASCIRC, /* ^= */
+ LNOT, /* ! */
+ ASNOT, /* ~= */
+ LBRA, /* { */
+ RBRA, /* } */
+ LBRK, /* [ */
+ RBRK, /* ] */
+ LPAR, /* ( */
+ RPAR, /* ) */
+ COMMA, /* , */
+ QUEST, /* ? */
+ SEMIC, /* ; */
+ COLON, /* : */
+ DOT, /* . */
+ MDOTS, /* ... */
+ SHARP, /* # */
+ DSHARP, /* ## */
+
+ OPT_NONE, /* optional space to separate tokens in text output */
+
+ DIGRAPH_TOKENS, /* there begin digraph tokens */
+
+ /* for DIG_*, do not change order, unless checking undig() in cpp.c */
+ DIG_LBRK, /* <: */
+ DIG_RBRK, /* :> */
+ DIG_LBRA, /* <% */
+ DIG_RBRA, /* %> */
+ DIG_SHARP, /* %: */
+ DIG_DSHARP, /* %:%: */
+
+ DIGRAPH_TOKENS_END, /* digraph tokens end here */
+
+ LAST_MEANINGFUL_TOKEN, /* reserved words will go there */
+
+ MACROARG, /* special token for representing macro arguments */
+
+ UPLUS = CPPERR, /* unary + */
+ UMINUS /* unary - */
+};
+
+#include <stdio.h>
+#include <setjmp.h>
+#include "tune.h"
+
+struct token {
+ int type;
+ long line;
+ char *name;
+};
+
+struct token_fifo {
+ struct token *t;
+ size_t nt, art;
+};
+
+struct lexer_state {
+ /* input control */
+ FILE *input;
+#ifndef NO_UCPP_BUF
+ unsigned char *input_buf;
+#ifdef UCPP_MMAP
+ int from_mmap;
+ unsigned char *input_buf_sav;
+#endif
+#endif
+ unsigned char *input_string;
+ size_t ebuf;
+ size_t pbuf;
+ int lka[2];
+ int nlka;
+ int macfile;
+ int last;
+ int discard;
+ unsigned long utf8;
+ unsigned char copy_line[COPY_LINE_LENGTH];
+ int cli;
+
+ /* output control */
+
+ FILE *output;
+ struct token_fifo *output_fifo, *toplevel_of;
+#ifndef NO_UCPP_BUF
+ unsigned char *output_buf;
+#endif
+ size_t sbuf;
+
+ /* token control */
+ struct token *ctok;
+ struct token *save_ctok;
+ int tknl;
+ int ltwnl;
+ int pending_token;
+#ifdef INMACRO_FLAG
+ int inmacro;
+ long macro_count;
+#endif
+
+ /* lexer options */
+ long line;
+ long oline;
+ unsigned long flags;
+ long count_trigraphs;
+ struct garbage_fifo *gf;
+ int ifnest;
+ int condnest;
+ int condcomp;
+ int condmet;
+ unsigned long condf[2];
+};
+
+/*
+ * Flags for struct lexer_state
+ */
+/* warning flags */
+#define WARN_STANDARD 0x000001UL /* emit standard warnings */
+#define WARN_ANNOYING 0x000002UL /* emit annoying warnings */
+#define WARN_TRIGRAPHS 0x000004UL /* warn when trigraphs are used */
+#define WARN_TRIGRAPHS_MORE 0x000008UL /* extra-warn for trigraphs */
+#define WARN_PRAGMA 0x000010UL /* warn for pragmas in non-lexer mode */
+
+/* error flags */
+#define FAIL_SHARP 0x000020UL /* emit errors on rogue '#' */
+#define CCHARSET 0x000040UL /* emit errors on non-C characters */
+
+/* emission flags */
+#define DISCARD_COMMENTS 0x000080UL /* discard comments from text output */
+#define CPLUSPLUS_COMMENTS 0x000100UL /* understand C++-like comments */
+#define LINE_NUM 0x000200UL /* emit #line directives in output */
+#define GCC_LINE_NUM 0x000400UL /* same as #line, with gcc-syntax */
+
+/* language flags */
+#define HANDLE_ASSERTIONS 0x000800UL /* understand assertions */
+#define HANDLE_PRAGMA 0x001000UL /* emit PRAGMA tokens in lexer mode */
+#define MACRO_VAARG 0x002000UL /* understand macros with '...' */
+#define UTF8_SOURCE 0x004000UL /* identifiers are in UTF8 encoding */
+#define HANDLE_TRIGRAPHS 0x008000UL /* handle trigraphs */
+
+/* global ucpp behaviour */
+#define LEXER 0x010000UL /* behave as a lexer */
+#define KEEP_OUTPUT 0x020000UL /* emit the result of preprocessing */
+#define COPY_LINE 0x040000UL /* make a copy of the parsed line */
+
+/* internal flags */
+#define READ_AGAIN 0x080000UL /* emit again the last token */
+#define TEXT_OUTPUT 0x100000UL /* output text */
+
+/*
+ * Public function prototypes
+ */
+
+#ifndef NO_UCPP_BUF
+void flush_output(struct lexer_state *);
+#endif
+
+void init_assertions(void);
+int make_assertion(char *);
+int destroy_assertion(char *);
+void print_assertions(void);
+
+void init_macros(void);
+int define_macro(struct lexer_state *, char *);
+int undef_macro(struct lexer_state *, char *);
+void print_defines(void);
+
+void set_init_filename(char *, int);
+void init_cpp(void);
+void init_include_path(char *[]);
+void init_lexer_state(struct lexer_state *);
+void init_lexer_mode(struct lexer_state *);
+void free_lexer_state(struct lexer_state *);
+int lex(struct lexer_state *);
+int check_cpp_errors(struct lexer_state *);
+void add_incpath(char *);
+void init_tables(int);
+void enter_file(struct lexer_state *, unsigned long);
+int cpp(struct lexer_state *);
+
+#ifdef UCPP_MMAP
+FILE *fopen_mmap_file(char *);
+void set_input_file(struct lexer_state *, FILE *);
+#endif
+
+struct stack_context {
+ char *long_name, *name;
+ long line;
+};
+struct stack_context *report_context(void);
+
+extern int no_special_macros, system_macros,
+ emit_dependencies, emit_defines, emit_assertions;
+extern int c99_compliant, c99_hosted;
+extern FILE *emit_output;
+extern char *current_filename, *current_long_filename;
+extern char *operators_name[];
+extern struct protect {
+ char *macro;
+ int state;
+ struct found_file *ff;
+} protect_detect;
+
+void ucpp_ouch(char *, ...);
+void ucpp_error(long, char *, ...);
+void ucpp_warning(long, char *, ...);
+
+extern int *transient_characters;
+
+/*
+ * Errors from CPPERR_EOF and above are not real erros, only show-stoppers.
+ * Errors below CPPERR_EOF are real ones.
+ */
+#define CPPERR_NEST 900
+#define CPPERR_EOF 1000
+
+/*
+ * This macro tells whether the name field of a given token type is
+ * relevant, or not. Irrelevant name field means that it might point
+ * to outerspace.
+ */
+#ifdef SEMPER_FIDELIS
+#define STRING_TOKEN(x) ((x) == NONE || ((x) >= COMMENT && (x) <= CHAR))
+#else
+#define STRING_TOKEN(x) ((x) >= NUMBER && (x) <= CHAR)
+#endif
+
+#endif
diff --git a/ucpp/eval.c b/ucpp/eval.c
new file mode 100755
index 0000000..9319b09
--- /dev/null
+++ b/ucpp/eval.c
@@ -0,0 +1,1087 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <setjmp.h>
+#include <limits.h>
+#include "ucppi.h"
+#include "tune.h"
+#include "mem.h"
+
+JMP_BUF eval_exception;
+long eval_line;
+static int emit_eval_warnings;
+
+/*
+ * If you want to hardcode a conversion table, define a static array
+ * of 256 int, and make transient_characters point to it.
+ */
+int *transient_characters = 0;
+
+#define OCTAL(x) ((x) >= '0' && (x) <= '7')
+#define DECIM(x) ((x) >= '0' && (x) <= '9')
+#define HEXAD(x) (((x) >= '0' && (x) <= '9') \
+ || (x) == 'a' || (x) == 'b' || (x) == 'c' \
+ || (x) == 'd' || (x) == 'e' || (x) == 'f' \
+ || (x) == 'A' || (x) == 'B' || (x) == 'C' \
+ || (x) == 'D' || (x) == 'E' || (x) == 'F')
+#define OVAL(x) ((int)((x) - '0'))
+#define DVAL(x) ((int)((x) - '0'))
+#define HVAL(x) (DECIM(x) ? DVAL(x) \
+ : (x) == 'a' || (x) == 'A' ? 10 \
+ : (x) == 'b' || (x) == 'B' ? 11 \
+ : (x) == 'c' || (x) == 'C' ? 12 \
+ : (x) == 'd' || (x) == 'D' ? 13 \
+ : (x) == 'e' || (x) == 'E' ? 14 : 15)
+
+#if !defined(NATIVE_UINTMAX) && !defined(SIMUL_UINTMAX)
+# if __STDC__ && __STDC_VERSION__ >= 199901L
+# include <stdint.h>
+# define NATIVE_UINTMAX uintmax_t
+# define NATIVE_INTMAX intmax_t
+# else
+# define NATIVE_UINTMAX unsigned long
+# define NATIVE_INTMAX long
+# endif
+#endif
+
+#ifdef NATIVE_UINTMAX
+
+typedef NATIVE_UINTMAX ucppulong;
+typedef NATIVE_INTMAX ucppslong;
+
+#define to_ulong(x) ((ucppulong)(x))
+#define to_slong(x) ((ucppslong)(x))
+
+#define op_star_u(x, y) ((x) * (y))
+
+static inline ucppulong op_slash_u(ucppulong x, ucppulong y)
+{
+ if (y == 0) {
+ error(eval_line, "division by 0");
+ throw(eval_exception);
+ }
+ return x / y;
+}
+
+static inline ucppulong op_pct_u(ucppulong x, ucppulong y)
+{
+ if (y == 0) {
+ error(eval_line, "division by 0");
+ throw(eval_exception);
+ }
+ return x % y;
+}
+
+#define op_plus_u(x, y) ((x) + (y))
+#define op_minus_u(x, y) ((x) - (y))
+#define op_neg_u(x) (-(x))
+#define op_lsh_u(x, y) ((x) << (y))
+#define op_rsh_u(x, y) ((x) >> (y))
+#define op_lt_u(x, y) ((x) < (y))
+#define op_leq_u(x, y) ((x) <= (y))
+#define op_gt_u(x, y) ((x) > (y))
+#define op_geq_u(x, y) ((x) >= (y))
+#define op_same_u(x, y) ((x) == (y))
+#define op_neq_u(x, y) ((x) != (y))
+#define op_and_u(x, y) ((x) & (y))
+#define op_circ_u(x, y) ((x) ^ (y))
+#define op_or_u(x, y) ((x) | (y))
+#define op_lval_u(x) ((x) != 0)
+#define op_lnot_u(x) (!(x))
+#define op_not_u(x) (~(x))
+#define op_uplus_u(x) (x)
+#define op_uminus_u(x) op_neg_u(x)
+
+#define op_star_s(x, y) ((x) * (y))
+
+static inline ucppslong op_slash_s(ucppslong x, ucppslong y)
+{
+ if (y == 0) {
+ error(eval_line, "division by 0");
+ throw(eval_exception);
+ }
+ return x / y;
+}
+
+static inline ucppslong op_pct_s(ucppslong x, ucppslong y)
+{
+ if (y == 0) {
+ error(eval_line, "division by 0");
+ throw(eval_exception);
+ }
+ return x % y;
+}
+
+#define op_plus_s(x, y) ((x) + (y))
+#define op_minus_s(x, y) ((x) - (y))
+#define op_neg_s(x) (-(x))
+#define op_lsh_s(x, y) ((x) << (y))
+#define op_rsh_s(x, y) ((x) >> (y))
+#define op_lt_s(x, y) ((x) < (y))
+#define op_leq_s(x, y) ((x) <= (y))
+#define op_gt_s(x, y) ((x) > (y))
+#define op_geq_s(x, y) ((x) >= (y))
+#define op_same_s(x, y) ((x) == (y))
+#define op_neq_s(x, y) ((x) != (y))
+#define op_and_s(x, y) ((x) & (y))
+#define op_circ_s(x, y) ((x) ^ (y))
+#define op_or_s(x, y) ((x) | (y))
+#define op_lval_s(x) ((x) != 0)
+#define op_lnot_s(x) (!(x))
+#define op_not_s(x) (~(x))
+#define op_uplus_s(x) (x)
+#define op_uminus_s(x) op_neg_s(x)
+
+#define op_promo(x) ((ucppulong)x)
+#define back_ulong(x) ((unsigned long)x)
+
+#else
+
+/*
+ * We suppose that the unsigned long is not padded in its memory
+ * representation, and that it has an even binary length.
+ *
+ * We could explore the size of ULONG_MAX with some dichotomic
+ * trick using a recursive #include, but this would be really ugly.
+ */
+#define LONGSIZE (CHAR_BIT * sizeof(unsigned long))
+#define HALFLONGSIZE (LONGSIZE / 2)
+#define HUL_MASK ((1UL << HALFLONGSIZE) - 1)
+#define UL_MS(x) (((x) >> HALFLONGSIZE) & HUL_MASK)
+#define UL_LS(x) ((x) & HUL_MASK)
+#define SIGNBIT(x) ((x) & (1UL << (LONGSIZE - 1)))
+
+typedef struct {
+ unsigned long msw, lsw;
+} ucppulong;
+
+#define ucppslong ucppulong
+
+static ucppulong to_ulong(unsigned long x)
+{
+ ucppulong y;
+
+ y.msw = 0;
+ y.lsw = x;
+ return y;
+}
+
+static ucppslong to_slong(long x)
+{
+ ucppslong y;
+
+ y.lsw = x;
+ y.msw = x >= 0 ? 0 : (unsigned long)(-1);
+ return y;
+}
+
+static ucppulong op_plus_u(ucppulong x, ucppulong y)
+{
+ ucppulong z;
+
+ z.lsw = x.lsw + y.lsw;
+ z.msw = x.msw + y.msw;
+ if (z.lsw < x.lsw) z.msw ++;
+ return z;
+}
+
+static ucppulong op_neg_u(ucppulong x)
+{
+ ucppulong z;
+
+ z.lsw = ~x.lsw;
+ z.msw = ~x.msw;
+ if (!(++ z.lsw)) z.msw ++;
+ return z;
+}
+
+#define op_minus_u(x, y) op_plus_u(x, op_neg_u(y))
+
+static ucppulong op_lsh_u(ucppulong x, int s)
+{
+ ucppulong z;
+
+ s %= (2 * LONGSIZE);
+ if (s == 0) return x;
+ if (s >= LONGSIZE) {
+ z.lsw = 0;
+ z.msw = x.lsw;
+ return op_lsh_u(z, s - LONGSIZE);
+ }
+ z.lsw = (x.lsw << s);
+ z.msw = (x.msw << s) | (x.lsw >> (LONGSIZE - s));
+ return z;
+}
+
+static ucppulong op_rsh_u(ucppulong x, int s)
+{
+ ucppulong z;
+
+ s %= (2 * LONGSIZE);
+ if (s == 0) return x;
+ if (s >= LONGSIZE) {
+ z.msw = 0;
+ z.lsw = x.msw;
+ return op_rsh_u(z, s - LONGSIZE);
+ }
+ z.lsw = (x.lsw >> s) | (x.msw << (LONGSIZE - s));
+ z.msw = (x.msw >> s);
+ return z;
+}
+
+static int op_lt_u(ucppulong x, ucppulong y)
+{
+ if (x.msw < y.msw) return 1;
+ if (x.msw > y.msw) return 0;
+ if (x.lsw < y.lsw) return 1;
+ return 0;
+}
+
+static int op_leq_u(ucppulong x, ucppulong y)
+{
+ if (x.msw < y.msw) return 1;
+ if (x.msw > y.msw) return 0;
+ if (x.lsw <= y.lsw) return 1;
+ return 0;
+}
+
+#define op_gt_u(x, y) op_lt_u(y, x)
+#define op_geq_u(x, y) op_leq_u(y, x)
+
+static int op_same_u(ucppulong x, ucppulong y)
+{
+ return x.msw == y.msw && x.lsw == y.lsw;
+}
+
+#define op_neq_u(x, y) (!op_same_u(x, y))
+
+static ucppulong op_and_u(ucppulong x, ucppulong y)
+{
+ ucppulong z;
+
+ z.lsw = x.lsw & y.lsw;
+ z.msw = x.msw & y.msw;
+ return z;
+}
+
+static ucppulong op_circ_u(ucppulong x, ucppulong y)
+{
+ ucppulong z;
+
+ z.lsw = x.lsw ^ y.lsw;
+ z.msw = x.msw ^ y.msw;
+ return z;
+}
+
+static ucppulong op_or_u(ucppulong x, ucppulong y)
+{
+ ucppulong z;
+
+ z.lsw = x.lsw | y.lsw;
+ z.msw = x.msw | y.msw;
+ return z;
+}
+
+#define op_lval_u(x) op_neq_u(x, to_ulong(0))
+#define op_lnot_u(x) (!op_lval_u(x))
+
+static ucppulong op_not_u(ucppulong x)
+{
+ ucppulong z;
+
+ z.lsw = ~x.lsw;
+ z.msw = ~x.msw;
+ return z;
+}
+
+#define op_uplus_u(x) (x)
+#define op_uminus_u(x) op_neg_u(x)
+
+static ucppulong umul(unsigned long x, unsigned long y)
+{
+ ucppulong z;
+ unsigned long t00, t01, t10, t11, c = 0, t;
+
+ t00 = UL_LS(x) * UL_LS(y);
+ t01 = UL_LS(x) * UL_MS(y);
+ t10 = UL_MS(x) * UL_LS(y);
+ t11 = UL_MS(x) * UL_MS(y);
+ t = z.lsw = t00;
+ if (t > (z.lsw += (UL_LS(t01) << HALFLONGSIZE))) c ++;
+ t = z.lsw;
+ if (t > (z.lsw += (UL_LS(t10) << HALFLONGSIZE))) c ++;
+ z.msw = t11 + UL_MS(t10) + UL_MS(t01) + c;
+ return z;
+}
+
+static ucppulong op_star_u(ucppulong x, ucppulong y)
+{
+ ucppulong z1, z2;
+
+ z1.lsw = z2.lsw = 0;
+ z1.msw = x.lsw * y.msw;
+ z2.msw = x.msw * y.lsw;
+ return op_plus_u(umul(x.lsw, y.lsw), op_plus_u(z1, z2));
+}
+
+static void udiv(ucppulong x, ucppulong y, ucppulong *q, ucppulong *r)
+{
+ int i, j;
+
+ *q = to_ulong(0);
+ for (i = 2 * LONGSIZE - 1; i >= 0; i --) {
+ if (i >= LONGSIZE && (y.msw & (1UL << (i - LONGSIZE)))) break;
+ if (i < LONGSIZE && (y.lsw & (1UL << i))) break;
+ }
+ if (i < 0) {
+ error(eval_line, "division by 0");
+ throw(eval_exception);
+ }
+ for (j = 2 * LONGSIZE - 1 - i; j >= 0; j --) {
+ ucppulong a = op_lsh_u(y, j);
+
+ if (op_leq_u(a, x)) {
+ x = op_minus_u(x, a);
+ if (j >= LONGSIZE)
+ q->msw |= (1UL << (j - LONGSIZE));
+ else
+ q->lsw |= (1UL << j);
+ }
+ }
+ *r = x;
+}
+
+static ucppulong op_slash_u(ucppulong x, ucppulong y)
+{
+ ucppulong q, r;
+
+ udiv(x, y, &q, &r);
+ return q;
+}
+
+static ucppulong op_pct_u(ucppulong x, ucppulong y)
+{
+ ucppulong q, r;
+
+ udiv(x, y, &q, &r);
+ return r;
+}
+
+
+static ucppslong op_star_s(ucppslong x, ucppslong y)
+{
+ ucppulong a = x, b = y, c;
+ int xn = 0, yn = 0;
+
+ if (SIGNBIT(x.msw)) { a = op_neg_u(x); xn = 1; }
+ if (SIGNBIT(y.msw)) { b = op_neg_u(y); yn = 1; }
+ c = op_star_u(a, b);
+ /* Turbo C seems to miscompile the ?: operators when operands
+ are ulong/slong structures */
+ if (xn ^ yn) return op_neg_u(c);
+ return c;
+}
+
+static void sdiv(ucppslong x, ucppslong y, ucppslong *q, ucppslong *r)
+{
+ ucppulong a = x, b = y, c, d;
+ int xn = 0, yn = 0;
+
+ if (SIGNBIT(x.msw)) { a = op_neg_u(x); xn = 1; }
+ if (SIGNBIT(y.msw)) { b = op_neg_u(y); yn = 1; }
+ udiv(a, b, &c, &d);
+ if (xn ^ yn) *q = op_neg_u(c); else *q = c;
+ if (xn ^ yn) *r = op_neg_u(d); else *r = d;
+}
+
+static ucppslong op_slash_s(ucppslong x, ucppslong y)
+{
+ ucppslong q, r;
+
+ sdiv(x, y, &q, &r);
+ return q;
+}
+
+static ucppslong op_pct_s(ucppslong x, ucppslong y)
+{
+ ucppslong q, r;
+
+ sdiv(x, y, &q, &r);
+ return r;
+}
+
+#define op_plus_s(x, y) op_plus_u(x, y)
+#define op_minus_s(x, y) op_minus_u(x, y)
+#define op_neg_s(x) op_neg_u(x)
+#define op_lsh_s(x, y) op_lsh_u(x, y)
+
+/*
+ * What happens if x represents a negative value, is implementation
+ * specified. We emit a warning, and extend the sign (which is what
+ * most implementations do).
+ */
+static ucppslong op_rsh_s(ucppslong x, int y)
+{
+ int xn = (SIGNBIT(x.msw) != 0);
+ ucppulong q = op_rsh_u(x, y);
+
+ if (xn && y > 0) {
+ if (emit_eval_warnings)
+ warning(eval_line, "right shift of a signed negative "
+ "value in #if");
+ q = op_or_u(q, op_lsh_u(op_not_u(to_ulong(0)),
+ 2 * LONGSIZE - y));
+ }
+ return q;
+}
+
+static int op_lt_s(ucppslong x, ucppslong y)
+{
+ int xn = (SIGNBIT(x.msw) != 0);
+ int yn = (SIGNBIT(y.msw) != 0);
+
+ if (xn && !yn) return 1;
+ if (!xn && yn) return 0;
+ if (xn) return op_lt_u(op_neg_u(y), op_neg_u(x));
+ return op_lt_u(x, y);
+}
+
+static int op_leq_s(ucppslong x, ucppslong y)
+{
+ int xn = (SIGNBIT(x.msw) != 0);
+ int yn = (SIGNBIT(y.msw) != 0);
+
+ if (xn && !yn) return 1;
+ if (!xn && yn) return 0;
+ if (xn) return op_leq_u(op_neg_u(y), op_neg_u(x));
+ return op_leq_u(x, y);
+}
+
+#define op_gt_s(x, y) op_lt_s(y, x)
+#define op_geq_s(x, y) op_leq_s(y, x)
+#define op_same_s(x, y) op_same_u(x, y)
+#define op_neq_s(x, y) (!op_same_s(x, y))
+
+#define op_and_s(x, y) op_and_u(x, y)
+#define op_circ_s(x, y) op_circ_u(x, y)
+#define op_or_s(x, y) op_or_u(x, y)
+
+#define op_lval_s(x) op_neq_s(x, to_slong(0))
+#define op_lnot_s(x) (!op_lval_s(x))
+#define op_not_s(x) op_not_u(x)
+#define op_uplus_s(x) (x)
+#define op_uminus_s(x) op_neg_s(x)
+
+#define op_promo(x) (x)
+#define back_ulong(x) ((x).lsw)
+
+#endif
+
+typedef struct {
+ int sign;
+ union {
+ ucppulong uv;
+ ucppslong sv;
+ } u;
+} ppval;
+
+static int boolval(ppval x)
+{
+ return x.sign ? op_lval_s(x.u.sv) : op_lval_u(x.u.uv);
+}
+
+#if !defined(WCHAR_SIGNEDNESS)
+# if CHAR_MIN == 0
+# define WCHAR_SIGNEDNESS 0
+# else
+# define WCHAR_SIGNEDNESS 1
+# endif
+#endif
+
+/*
+ * Check the suffix, return 1 if it is signed, 0 otherwise.
+ * u, l, ll, ul, lu, ull, llu, and variations with uppercase letters
+ * are legal, no suffix either; other suffixes are not legal.
+ */
+static int pp_suffix(char *d, char *refc)
+{
+ if (!*d) return 1;
+ if (*d == 'u' || *d == 'U') {
+ d ++;
+ if (!*d) return 0;
+ if (*d == 'l' || *d == 'L') {
+ d ++;
+ if (*d == 'l' || *d == 'L') d ++;
+ if (!*d) return 0;
+ goto suffix_error;
+ }
+ goto suffix_error;
+ }
+ if (*d == 'l' || *d == 'L') {
+ d ++;
+ if (*d == 'l' || *d == 'L') d ++;
+ if (!*d) return 1;
+ if (*d == 'u' || *d == 'U') {
+ d ++;
+ if (!*d) return 0;
+ }
+ goto suffix_error;
+ }
+suffix_error:
+ error(eval_line, "invalid integer constant '%s'", refc);
+ throw(eval_exception);
+ return 666;
+}
+
+static ppval pp_decconst(char *c, int sign, char *refc)
+{
+ ppval q;
+
+ q.sign = sign;
+ if (q.sign) {
+ q.u.sv = to_slong(0);
+ for (; DECIM(*c); c ++) {
+ q.u.sv = op_star_s(q.u.sv, to_slong(10));
+ q.u.sv = op_plus_s(q.u.sv, to_slong(DVAL(*c)));
+ }
+ if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+ } else {
+ q.u.uv = to_ulong(0);
+ for (; DECIM(*c); c ++) {
+ q.u.uv = op_star_u(q.u.uv, to_ulong(10));
+ q.u.uv = op_plus_u(q.u.uv, to_ulong(DVAL(*c)));
+ }
+ if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+ }
+ return q;
+const_error:
+ error(eval_line, "invalid integer constant '%s'", refc);
+ throw(eval_exception);
+ return q;
+}
+
+static ppval pp_octconst(char *c, int sign, char *refc)
+{
+ ppval q;
+
+ q.sign = sign;
+ if (q.sign) {
+ q.u.sv = to_slong(0);
+ for (; OCTAL(*c); c ++) {
+ q.u.sv = op_star_s(q.u.sv, to_slong(8));
+ q.u.sv = op_plus_s(q.u.sv, to_slong(OVAL(*c)));
+ }
+ if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+ } else {
+ q.u.uv = to_ulong(0);
+ for (; OCTAL(*c); c ++) {
+ q.u.uv = op_star_u(q.u.uv, to_ulong(8));
+ q.u.uv = op_plus_u(q.u.uv, to_ulong(OVAL(*c)));
+ }
+ if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+ }
+ return q;
+const_error:
+ error(eval_line, "invalid integer constant '%s'", refc);
+ throw(eval_exception);
+ return q;
+}
+
+static ppval pp_hexconst(char *c, int sign, char *refc)
+{
+ ppval q;
+
+ q.sign = sign;
+ if (q.sign) {
+ q.u.sv = to_slong(0);
+ for (; HEXAD(*c); c ++) {
+ q.u.sv = op_star_s(q.u.sv, to_slong(16));
+ q.u.sv = op_plus_s(q.u.sv, to_slong(HVAL(*c)));
+ }
+ if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+ } else {
+ q.u.uv = to_ulong(0);
+ for (; HEXAD(*c); c ++) {
+ q.u.uv = op_star_u(q.u.uv, to_ulong(16));
+ q.u.uv = op_plus_u(q.u.uv, to_ulong(HVAL(*c)));
+ }
+ if (HEXAD(*c) || *c == 'x' || *c == 'X') goto const_error;
+ }
+ return q;
+const_error:
+ error(eval_line, "invalid integer constant '%s'", refc);
+ throw(eval_exception);
+ return q;
+}
+
+static unsigned long pp_char(char *c, char *refc)
+{
+ unsigned long r = 0;
+
+ c ++;
+ if (*c == '\\') {
+ int i;
+
+ c ++;
+ switch (*c) {
+ case 'n': r = '\n'; c ++; break;
+ case 't': r = '\t'; c ++; break;
+ case 'v': r = '\v'; c ++; break;
+ case 'b': r = '\b'; c ++; break;
+ case 'r': r = '\r'; c ++; break;
+ case 'f': r = '\f'; c ++; break;
+ case 'a': r = '\a'; c ++; break;
+ case '\\': r = '\\'; c ++; break;
+ case '\?': r = '\?'; c ++; break;
+ case '\'': r = '\''; c ++; break;
+ case '\"': r = '\"'; c ++; break;
+ case 'u':
+ for (i = 0, c ++; i < 4 && HEXAD(*c); i ++, c ++) {
+ r = (r * 16) + HVAL(*c);
+ }
+ if (i != 4) {
+ error(eval_line, "malformed UCN in %s", refc);
+ throw(eval_exception);
+ }
+ break;
+ case 'U':
+ for (i = 0, c ++; i < 8 && HEXAD(*c); i ++, c ++) {
+ r = (r * 16) + HVAL(*c);
+ }
+ if (i != 8) {
+ error(eval_line, "malformed UCN in %s", refc);
+ throw(eval_exception);
+ }
+ break;
+ case 'x':
+ for (c ++; HEXAD(*c); c ++) r = (r * 16) + HVAL(*c);
+ break;
+ default:
+ if (OCTAL(*c)) {
+ r = OVAL(*(c ++));
+ if (OCTAL(*c)) r = (r * 8) + OVAL(*(c ++));
+ if (OCTAL(*c)) r = (r * 8) + OVAL(*(c ++));
+ } else {
+ error(eval_line, "invalid escape sequence "
+ "'\\%c'", *c);
+ throw(eval_exception);
+ }
+ }
+ } else if (*c == '\'') {
+ error(eval_line, "empty character constant");
+ throw(eval_exception);
+ } else {
+ r = *((unsigned char *)(c ++));
+ }
+
+ if (transient_characters && r < 256) {
+ r = transient_characters[(size_t)r];
+ }
+
+ if (*c != '\'' && emit_eval_warnings) {
+ warning(eval_line, "multicharacter constant");
+ }
+ return r;
+}
+
+static ppval pp_strtoconst(char *refc)
+{
+ ppval q;
+ char *c = refc, *d;
+ int sign = 1;
+
+ if (*c == '\'' || *c == 'L') {
+ q.sign = (*c == 'L') ? WCHAR_SIGNEDNESS : 1;
+ if (*c == 'L') c ++;
+ if (q.sign) {
+ q.u.sv = to_slong(pp_char(c, refc));
+ } else {
+ q.u.uv = to_ulong(pp_char(c, refc));
+ }
+ return q;
+ }
+ for (d = c; *d; d ++) {
+ if (!HEXAD(*d) && *d != 'x' && *d != 'X') {
+ sign = pp_suffix(d, refc);
+ break;
+ }
+ }
+ if (*c == '0') {
+ c ++;
+ if (*c == 'x' || *c == 'X') {
+ /* hexadecimal constant */
+ c ++;
+ return pp_hexconst(c, sign, refc);
+ }
+ return pp_octconst(c, sign, refc);
+ }
+ return pp_decconst(c, sign, refc);
+}
+
+/*
+ * Used by #line directives -- anything beyond what can be put in an
+ * unsigned long, is considered absurd.
+ */
+unsigned long strtoconst(char *c)
+{
+ ppval q = pp_strtoconst(c);
+
+ if (q.sign) q.u.uv = op_promo(q.u.sv);
+ return back_ulong(q.u.uv);
+}
+
+#define OP_UN(x) ((x) == LNOT || (x) == NOT || (x) == UPLUS \
+ || (x) == UMINUS)
+
+static ppval eval_opun(int op, ppval v)
+{
+ if (op == LNOT) {
+ v.sign = 1;
+ v.u.sv = to_slong(op_lnot_s(v.u.sv));
+ return v;
+ }
+ if (v.sign) {
+ switch (op) {
+ case NOT: v.u.sv = op_not_s(v.u.sv); break;
+ case UPLUS: v.u.sv = op_uplus_s(v.u.sv); break;
+ case UMINUS: v.u.sv = op_uminus_s(v.u.sv); break;
+ }
+ } else {
+ switch (op) {
+ case NOT: v.u.uv = op_not_u(v.u.uv); break;
+ case UPLUS: v.u.uv = op_uplus_u(v.u.uv); break;
+ case UMINUS: v.u.uv = op_uminus_u(v.u.uv); break;
+ }
+ }
+ return v;
+}
+
+#define OP_BIN(x) ((x) == STAR || (x) == SLASH || (x) == PCT \
+ || (x) == PLUS || (x) == MINUS || (x) == LSH \
+ || (x) == RSH || (x) == LT || (x) == LEQ \
+ || (x) == GT || (x) == GEQ || (x) == SAME \
+ || (x) == NEQ || (x) == AND || (x) == CIRC \
+ || (x) == OR || (x) == LAND || (x) == LOR \
+ || (x) == COMMA)
+static ppval eval_opbin(int op, ppval v1, ppval v2)
+{
+ ppval r;
+
+ switch (op) {
+ case STAR: case SLASH: case PCT:
+ case PLUS: case MINUS: case AND:
+ case CIRC: case OR:
+ /* promote operands, adjust signedness of result */
+ if (!v1.sign || !v2.sign) {
+ if (v1.sign) {
+ v1.u.uv = op_promo(v1.u.sv);
+ v1.sign = 0;
+ } else if (v2.sign) {
+ v2.u.uv = op_promo(v2.u.sv);
+ v2.sign = 0;
+ }
+ r.sign = 0;
+ } else {
+ r.sign = 1;
+ }
+ break;
+ case LT: case LEQ: case GT:
+ case GEQ: case SAME: case NEQ:
+ /* promote operands */
+ if (!v1.sign || !v2.sign) {
+ if (v1.sign) {
+ v1.u.uv = op_promo(v1.u.sv);
+ v1.sign = 0;
+ } else if (v2.sign) {
+ v2.u.uv = op_promo(v2.u.sv);
+ v2.sign = 0;
+ }
+ }
+ /* fall through */
+ case LAND:
+ case LOR:
+ /* result is signed anyway */
+ r.sign = 1;
+ break;
+ case LSH:
+ case RSH:
+ /* result is as signed as left operand; promote right
+ operand to unsigned (this is not required by the
+ standard) */
+ r.sign = v1.sign;
+ if (v2.sign) {
+ v2.u.uv = op_promo(v2.u.sv);
+ v2.sign = 0;
+ }
+ break;
+ case COMMA:
+ if (emit_eval_warnings) {
+ warning(eval_line, "ISO C forbids evaluated comma "
+ "operators in #if expressions");
+ }
+ r.sign = v2.sign;
+ break;
+#ifdef AUDIT
+ default: ouch("a good operator is a dead operator");
+#endif
+ }
+
+#define SBINOP(x) if (r.sign) r.u.sv = op_ ## x ## _s(v1.u.sv, v2.u.sv); \
+ else r.u.uv = op_ ## x ## _u(v1.u.uv, v2.u.uv);
+
+#define NSSBINOP(x) if (v1.sign) r.u.sv = to_slong(op_ ## x ## _s(v1.u.sv, \
+ v2.u.sv)); else r.u.sv = to_slong(op_ ## x ## _u \
+ (v1.u.uv, v2.u.uv));
+
+#define LBINOP(x) if (v1.sign) r.u.sv = to_slong(op_lval_s(v1.u.sv) x \
+ op_lval_s(v2.u.sv)); else r.u.sv = \
+ to_slong(op_lval_u(v1.u.uv) x op_lval_u(v2.u.uv));
+
+#define ABINOP(x) if (r.sign) r.u.sv = op_ ## x ## _s(v1.u.sv, \
+ back_ulong(v2.u.uv)); else r.u.uv = \
+ op_ ## x ## _u(v1.u.uv, back_ulong(v2.u.uv));
+
+ switch (op) {
+ case STAR: SBINOP(star); break;
+ case SLASH: SBINOP(slash); break;
+ case PCT: SBINOP(pct); break;
+ case PLUS: SBINOP(plus); break;
+ case MINUS: SBINOP(minus); break;
+ case LSH: ABINOP(lsh); break;
+ case RSH: ABINOP(rsh); break;
+ case LT: NSSBINOP(lt); break;
+ case LEQ: NSSBINOP(leq); break;
+ case GT: NSSBINOP(gt); break;
+ case GEQ: NSSBINOP(geq); break;
+ case SAME: NSSBINOP(same); break;
+ case NEQ: NSSBINOP(neq); break;
+ case AND: SBINOP(and); break;
+ case CIRC: SBINOP(circ); break;
+ case OR: SBINOP(or); break;
+ case LAND: LBINOP(&&); break;
+ case LOR: LBINOP(||); break;
+ case COMMA: r = v2; break;
+ }
+ return r;
+}
+
+#define ttOP(x) (OP_UN(x) || OP_BIN(x) || (x) == QUEST || (x) == COLON)
+
+static int op_prec(int op)
+{
+ switch (op) {
+ case LNOT:
+ case NOT:
+ case UPLUS:
+ case UMINUS:
+ return 13;
+ case STAR:
+ case SLASH:
+ case PCT:
+ return 12;
+ case PLUS:
+ case MINUS:
+ return 11;
+ case LSH:
+ case RSH:
+ return 10;
+ case LT:
+ case LEQ:
+ case GT:
+ case GEQ:
+ return 9;
+ case SAME:
+ case NEQ:
+ return 8;
+ case AND:
+ return 7;
+ case CIRC:
+ return 6;
+ case OR:
+ return 5;
+ case LAND:
+ return 4;
+ case LOR:
+ return 3;
+ case QUEST:
+ return 2;
+ case COMMA:
+ return 1;
+ }
+#ifdef AUDIT
+ ouch("an unknown species should have a higher precedence");
+#endif
+ return 666;
+}
+
+/*
+ * Perform the hard work of evaluation.
+ *
+ * This function works because:
+ * -- all unary operators are right to left associative, and with
+ * identical precedence
+ * -- all binary operators are left to right associative
+ * -- there is only one non-unary and non-binary operator: the quest-colon
+ *
+ * If do_eval is 0, the evaluation of operators is not done. This is
+ * for sequence point operators (&&, || and ?:).
+ */
+static ppval eval_shrd(struct token_fifo *tf, int minprec, int do_eval)
+{
+ ppval top;
+ struct token *ct;
+
+ top.sign = 1;
+ if (tf->art == tf->nt) goto trunc_err;
+ ct = tf->t + (tf->art ++);
+ if (ct->type == LPAR) {
+ top = eval_shrd(tf, 0, do_eval);
+ if (tf->art == tf->nt) goto trunc_err;
+ ct = tf->t + (tf->art ++);
+ if (ct->type != RPAR) {
+ error(eval_line, "a right parenthesis was expected");
+ throw(eval_exception);
+ }
+ } else if (ct->type == NUMBER || ct->type == CHAR) {
+ top = pp_strtoconst(ct->name);
+ } else if (OP_UN(ct->type)) {
+ top = eval_opun(ct->type, eval_shrd(tf,
+ op_prec(ct->type), do_eval));
+ goto eval_loop;
+ } else if (ttOP(ct->type)) goto rogue_op_err;
+ else {
+ goto invalid_token_err;
+ }
+
+eval_loop:
+ if (tf->art == tf->nt) {
+ return top;
+ }
+ ct = tf->t + (tf->art ++);
+ if (OP_BIN(ct->type)) {
+ int bp = op_prec(ct->type);
+
+ if (bp > minprec) {
+ ppval tr;
+
+ if ((ct->type == LOR && boolval(top))
+ || (ct->type == LAND && !boolval(top))) {
+ tr = eval_shrd(tf, bp, 0);
+ if (do_eval) {
+ top.sign = 1;
+ if (ct->type == LOR)
+ top.u.sv = to_slong(1);
+ if (ct->type == LAND)
+ top.u.sv = to_slong(0);
+ }
+ } else {
+ tr = eval_shrd(tf, bp, do_eval);
+ if (do_eval)
+ top = eval_opbin(ct->type, top, tr);
+ }
+ goto eval_loop;
+ }
+ } else if (ct->type == QUEST) {
+ int bp = op_prec(QUEST);
+ ppval r1, r2;
+
+ if (bp >= minprec) {
+ int qv = boolval(top);
+
+ r1 = eval_shrd(tf, bp, qv ? do_eval : 0);
+ if (tf->art == tf->nt) goto trunc_err;
+ ct = tf->t + (tf->art ++);
+ if (ct->type != COLON) {
+ error(eval_line, "a colon was expected");
+ throw(eval_exception);
+ }
+ r2 = eval_shrd(tf, bp, qv ? 0 : do_eval);
+ if (do_eval) {
+ if (qv) top = r1; else top = r2;
+ }
+ goto eval_loop;
+ }
+ }
+ tf->art --;
+ return top;
+
+trunc_err:
+ error(eval_line, "truncated constant integral expression");
+ throw(eval_exception);
+rogue_op_err:
+ error(eval_line, "rogue operator '%s' in constant integral "
+ "expression", operators_name[ct->type]);
+ throw(eval_exception);
+invalid_token_err:
+ error(eval_line, "invalid token in constant integral expression");
+ throw(eval_exception);
+}
+
+#define UNARY(x) ((x) != NUMBER && (x) != NAME && (x) != CHAR \
+ && (x) != RPAR)
+
+/*
+ * Evaluate the integer expression contained in the given token_fifo.
+ * Evaluation is made by precedence of operators, as described in the
+ * Dragon Book. The unary + and - are distinguished from their binary
+ * counterparts using the Fortran way: a + or a - is considered unary
+ * if it does not follow a constant, an identifier or a right parenthesis.
+ */
+unsigned long eval_expr(struct token_fifo *tf, int *ret, int ew)
+{
+ size_t sart;
+ ppval r;
+
+ emit_eval_warnings = ew;
+ if (catch(eval_exception)) goto eval_err;
+ /* first, distinguish unary + and - from binary + and - */
+ for (sart = tf->art; tf->art < tf->nt; tf->art ++) {
+ if (tf->t[tf->art].type == PLUS) {
+ if (sart == tf->art || UNARY(tf->t[tf->art - 1].type))
+ tf->t[tf->art].type = UPLUS;
+ } else if (tf->t[tf->art].type == MINUS) {
+ if (sart == tf->art || UNARY(tf->t[tf->art - 1].type))
+ tf->t[tf->art].type = UMINUS;
+ }
+ }
+ tf->art = sart;
+ r = eval_shrd(tf, 0, 1);
+ if (tf->art < tf->nt) {
+ error(eval_line, "trailing garbage in constant integral "
+ "expression");
+ goto eval_err;
+ }
+ *ret = 0;
+ return boolval(r);
+eval_err:
+ *ret = 1;
+ return 0;
+}
diff --git a/ucpp/hash.c b/ucpp/hash.c
new file mode 100755
index 0000000..0e1669c
--- /dev/null
+++ b/ucpp/hash.c
@@ -0,0 +1,301 @@
+/*
+ * Generic hash table routines.
+ * (c) Thomas Pornin 1998, 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <string.h>
+#include "hash.h"
+#include "mem.h"
+
+/*
+ * hash_string() is a sample hash function for strings
+ */
+int hash_string(char *s)
+{
+ unsigned char h = 0;
+
+ for (; *s; s ++) h ^= (unsigned char)(*s);
+ return ((int)h);
+}
+
+/*
+ * struct hash_item is the basic data type to internally handle hash tables
+ */
+struct hash_item {
+ void *data;
+ struct hash_item *next;
+};
+
+/*
+ * This function adds an entry to the struct hash_item list
+ */
+static struct hash_item *add_entry(struct hash_item *blist, void *data)
+{
+ struct hash_item *t = getmem(sizeof(struct hash_item));
+
+ t->data = data;
+ t->next = blist;
+ return t;
+}
+
+/*
+ * This function finds a struct hash_item in a list, using the
+ * comparison function provided as cmpdata (*cmpdata() returns
+ * non-zero if the two parameters are to be considered identical).
+ *
+ * It returns 0 if the item is not found.
+ */
+static struct hash_item *get_entry(struct hash_item *blist, void *data,
+ int (*cmpdata)(void *, void *))
+{
+ while (blist) {
+ if ((*cmpdata)(data, blist->data)) return blist;
+ blist = blist->next;
+ }
+ return 0;
+}
+
+/*
+ * This function acts like get_entry but deletes the found item, using
+ * the provided function deldata(); it returns 0 if the given data was
+ * not found.
+ */
+static struct hash_item *del_entry(struct hash_item *blist, void *data,
+ int (*cmpdata)(void *, void *), void (*deldata)(void *))
+{
+ struct hash_item *prev = 0, *save = blist;
+
+ while (blist) {
+ if ((*cmpdata)(data, blist->data)) {
+ (*deldata)(blist->data);
+ if (prev) prev->next = blist->next;
+ if (save == blist) save = blist->next;
+ freemem(blist);
+ return save;
+ }
+ prev = blist;
+ blist = blist->next;
+ }
+ return 0;
+}
+
+/*
+ * This function creates a new hashtable, with the hashing and comparison
+ * functions given as parameters
+ */
+struct HT *newHT(int n, int (*cmpdata)(void *, void *), int (*hash)(void *),
+ void (*deldata)(void *))
+{
+ struct HT *t = getmem(sizeof(struct HT));
+ int i;
+
+ t->lists = getmem(n * sizeof(struct hash_item *));
+ for (i = 0; i < n; i ++) t->lists[i] = 0;
+ t->nb_lists = n;
+ t->cmpdata = cmpdata;
+ t->hash = hash;
+ t->deldata = deldata;
+ return t;
+}
+
+/*
+ * This function adds a new entry in the hashtable ht; it returns 0
+ * on success, or a pointer to the already present item otherwise.
+ */
+void *putHT(struct HT *ht, void *data)
+{
+ int h;
+ struct hash_item *d;
+
+ h = ((*(ht->hash))(data)) % ht->nb_lists;
+ if ((d = get_entry(ht->lists[h], data, ht->cmpdata)))
+ return d->data;
+ ht->lists[h] = add_entry(ht->lists[h], data);
+ return 0;
+}
+
+/*
+ * This function adds a new entry in the hashtable ht, even if an equal
+ * entry is already there. Exercise caution !
+ * The new entry will "hide" the old one, which means that the new will be
+ * found upon lookup/delete, not the old one.
+ */
+void *forceputHT(struct HT *ht, void *data)
+{
+ int h;
+
+ h = ((*(ht->hash))(data)) % ht->nb_lists;
+ ht->lists[h] = add_entry(ht->lists[h], data);
+ return 0;
+}
+
+/*
+ * This function finds the entry corresponding to *data in the
+ * hashtable ht (using the comparison function given as argument
+ * to newHT)
+ */
+void *getHT(struct HT *ht, void *data)
+{
+ int h;
+ struct hash_item *t;
+
+ h = ((*(ht->hash))(data)) % ht->nb_lists;
+ if ((t = get_entry(ht->lists[h], data, ht->cmpdata)) == 0)
+ return 0;
+ return (t->data);
+}
+
+/*
+ * This function finds and delete the entry corresponding to *data
+ * in the hashtable ht (using the comparison function given as
+ * argument to newHT).
+ */
+
+int delHT(struct HT *ht, void *data)
+{
+ int h;
+
+ h = ((*(ht->hash))(data)) % ht->nb_lists;
+ ht->lists[h] = del_entry(ht->lists[h], data, ht->cmpdata, ht->deldata);
+ return 1;
+}
+
+/*
+ * This function duplicates a given hash table; the data is not copied
+ */
+struct HT *copyHT(struct HT *ht)
+{
+ struct HT *nht = newHT(ht->nb_lists, ht->cmpdata, ht->hash,
+ ht->deldata);
+ struct hash_item *t;
+ int i, j;
+
+ for (i = 0; i < nht->nb_lists; i ++) {
+ j = 0;
+ t = ht->lists[i];
+ while (t) {
+ t = t->next;
+ j ++;
+ }
+ if (j != 0) {
+ nht->lists[i] = getmem(j * sizeof(struct hash_item));
+ mmv(nht->lists[i], ht->lists[i],
+ j * sizeof(struct hash_item));
+ }
+ }
+ return nht;
+}
+
+/*
+ * This function completely eradicates from memory a given hash table,
+ * releasing all objects
+ */
+void killHT(struct HT *ht)
+{
+ int i;
+ struct hash_item *t, *n;
+
+ for (i = 0; i < ht->nb_lists; i ++) for (t = ht->lists[i]; t;) {
+ n = t->next;
+ (*(ht->deldata))(t->data);
+ freemem(t);
+ t = n;
+ }
+ freemem(ht);
+}
+
+/*
+ * This function stores a backup of the hash table, for context stacking
+ */
+void saveHT(struct HT *ht, void **buffer)
+{
+ struct hash_item **b = (struct hash_item **)buffer;
+ int i;
+
+ for (i = 0; i < ht->nb_lists; i ++) b[i] = ht->lists[i];
+}
+
+/*
+ * This function restores the saved state of the hash table.
+ * Do NOT use if some of the entries that were present before the backup
+ * have been removed (even temporarily).
+ */
+void restoreHT(struct HT *ht, void **buffer)
+{
+ struct hash_item **b = (struct hash_item **)buffer;
+ int i;
+
+ for (i = 0; i < ht->nb_lists; i ++) {
+ struct hash_item *t = ht->lists[i], *n;
+
+ while (t != b[i]) {
+ n = t->next;
+ (*(ht->deldata))(t->data);
+ freemem(t);
+ t = n;
+ }
+ ht->lists[i] = b[i];
+ }
+}
+
+/*
+ * This function scans the whole table and calls the given function on
+ * each entry.
+ */
+void scanHT(struct HT *ht, void (*action)(void *))
+{
+ int i;
+
+ for (i = 0; i < ht->nb_lists; i ++) {
+ struct hash_item *t = ht->lists[i];
+
+ while (t) {
+ (*action)(t->data);
+ t = t->next;
+ }
+ }
+}
+
+/*
+ * The two following fonctions are generic for storing structures
+ * uniquely identified by their name, which must be the first
+ * field of the structure.
+ */
+int hash_struct(void *m)
+{
+ char *n = *(char **)m;
+
+ return hash_string(n) & 127;
+}
+
+int cmp_struct(void *m1, void *m2)
+{
+ char *n1 = *(char **)m1, *n2 = *(char **)m2;
+
+ return !strcmp(n1, n2);
+}
diff --git a/ucpp/hash.h b/ucpp/hash.h
new file mode 100755
index 0000000..d15cbca
--- /dev/null
+++ b/ucpp/hash.h
@@ -0,0 +1,58 @@
+/*
+ * (c) Thomas Pornin 1998, 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef UCPP__HASH__
+#define UCPP__HASH__
+
+struct hash_item;
+
+struct HT {
+ struct hash_item **lists;
+ int nb_lists;
+ int (*cmpdata)(void *, void *);
+ int (*hash)(void *);
+ void (*deldata)(void *);
+};
+
+int hash_string(char *);
+struct HT *newHT(int, int (*)(void *, void *), int (*)(void *),
+ void (*)(void *));
+void *putHT(struct HT *, void *);
+void *forceputHT(struct HT *, void *);
+void *getHT(struct HT *, void *);
+int delHT(struct HT *, void *);
+struct HT *copyHT(struct HT *);
+void killHT(struct HT *);
+void saveHT(struct HT *, void **);
+void restoreHT(struct HT *, void **);
+void scanHT(struct HT *, void (*)(void *));
+int hash_struct(void *);
+int cmp_struct(void *, void *);
+
+#endif
diff --git a/ucpp/lexer.c b/ucpp/lexer.c
new file mode 100755
index 0000000..9e5ebae
--- /dev/null
+++ b/ucpp/lexer.c
@@ -0,0 +1,1050 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*vb*/
+#ifdef HAVE_MISRA
+extern int misracheck;
+void misra(int,...);
+void misra_neu(int, int, int, int, ...);
+#endif
+
+#include "tune.h"
+#ifdef UCPP_MMAP
+#ifndef _POSIX_SOURCE
+#define _POSIX_SOURCE 1
+#endif
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <limits.h>
+#include <ctype.h>
+#include "ucppi.h"
+#include "mem.h"
+#ifdef UCPP_MMAP
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#endif
+
+/*
+ * Character classes for description of the automaton.
+ * The characters used for representing classes should not appear
+ * explicitely in an automaton rule.
+ */
+#define SPC ' ' /* whitespace characters */
+#define ALP 'Z' /* A-Z, a-z, _ */
+#define NUM '9' /* 0-9 */
+#define ANY 'Y' /* any character */
+#define VCH 'F' /* void character (for end of input) */
+
+/*
+ * flags and macros to test those flags
+ * STO: the currently read string is a complete token
+ * PUT: the currently read character must be added to the string
+ * FRZ: the currently read character must be kept and read again
+ */
+#define MOD_MK 255
+#define noMOD(x) ((x) & 255)
+#define STO(x) ((x) | 256)
+#define ttSTO(x) ((x) & 256)
+#define FRZ(x) ((x) | 512)
+#define ttFRZ(x) ((x) & 512)
+#define PUT(x) ((x) | 1024)
+#define ttPUT(x) ((x) & 1024)
+
+/* order is important */
+enum {
+ S_START, S_SPACE, S_BANG, S_STRING, S_STRING2, S_COLON,
+ S_SHARP, S_PCT, S_PCT2, S_PCT3, S_AMPER, S_CHAR, S_CHAR2, S_STAR,
+ S_PLUS, S_MINUS, S_DOT, S_DOT2, S_SLASH, S_NUMBER, S_NUMBER2, S_LT,
+ S_LT2, S_EQ, S_GT, S_GT2, S_CIRC, S_PIPE, S_TILDE, S_BACKSLASH,
+ S_COMMENT, S_COMMENT2, S_COMMENT3, S_COMMENT4, S_COMMENT5,
+ S_NAME, S_NAME_BS, S_LCHAR,
+ MSTATE,
+ S_ILL, S_DDOT, S_DDSHARP, S_BS, S_ROGUE_BS, S_BEHEAD, S_DECAY,
+ S_TRUNC, S_TRUNCC, S_OUCH
+};
+
+#define CMT(x) ((x) >= S_COMMENT && (x) <= S_COMMENT5)
+
+#define CMCR 2
+
+/*
+ * This is the description of the automaton. It is not used "as is"
+ * but copied at execution time into a table.
+ *
+ * To my utmost displeasure, there are a few hacks in read_token()
+ * (which uses the transformed automaton) about the special handling
+ * of slashes, sharps, and the letter L.
+ */
+static struct machine_state {
+ int state;
+ unsigned char input[CMCR];
+ int new_state;
+} cppms[] = {
+ /* S_START is the generic beginning state */
+ { S_START, { ANY }, S_ILL },
+#ifdef SEMPER_FIDELIS
+ { S_START, { SPC }, PUT(S_SPACE) },
+#else
+ { S_START, { SPC }, S_SPACE },
+#endif
+ { S_START, { '\n' }, STO(NEWLINE) },
+ { S_START, { '!' }, S_BANG },
+ { S_START, { '"' }, PUT(S_STRING) },
+ { S_START, { '#' }, S_SHARP },
+ { S_START, { '%' }, S_PCT },
+ { S_START, { '&' }, S_AMPER },
+ { S_START, { '\'' }, PUT(S_CHAR) },
+ { S_START, { '(' }, STO(LPAR) },
+ { S_START, { ')' }, STO(RPAR) },
+ { S_START, { '*' }, S_STAR },
+ { S_START, { '+' }, S_PLUS },
+ { S_START, { ',' }, STO(COMMA) },
+ { S_START, { '-' }, S_MINUS },
+ { S_START, { '.' }, PUT(S_DOT) },
+#ifdef SEMPER_FIDELIS
+ { S_START, { '/' }, PUT(S_SLASH) },
+#else
+ { S_START, { '/' }, S_SLASH },
+#endif
+ { S_START, { NUM }, PUT(S_NUMBER) },
+#ifdef HAVE_ECPP
+ { S_START, { '@' }, S_COLON },
+ { S_START, { ':' }, PUT(S_NAME) },
+#else
+ { S_START, { ':' }, S_COLON },
+#endif
+ { S_START, { ';' }, STO(SEMIC) },
+ { S_START, { '<' }, S_LT },
+ { S_START, { '=' }, S_EQ },
+ { S_START, { '>' }, S_GT },
+ { S_START, { '?' }, STO(QUEST) },
+ { S_START, { ALP }, PUT(S_NAME) },
+ { S_START, { 'L' }, PUT(S_LCHAR) },
+ { S_START, { '[' }, STO(LBRK) },
+ { S_START, { ']' }, STO(RBRK) },
+ { S_START, { '^' }, S_CIRC },
+ { S_START, { '{' }, STO(LBRA) },
+ { S_START, { '|' }, S_PIPE },
+ { S_START, { '}' }, STO(RBRA) },
+ { S_START, { '~' }, S_TILDE },
+ { S_START, { '\\' }, S_BACKSLASH },
+
+ /* after a space */
+ { S_SPACE, { ANY }, FRZ(STO(NONE)) },
+#ifdef SEMPER_FIDELIS
+ { S_SPACE, { SPC }, PUT(S_SPACE) },
+#else
+ { S_SPACE, { SPC }, S_SPACE },
+#endif
+
+ /* after a ! */
+ { S_BANG, { ANY }, FRZ(STO(LNOT)) },
+ { S_BANG, { '=' }, STO(NEQ) },
+
+ /* after a " */
+ { S_STRING, { ANY }, PUT(S_STRING) },
+ { S_STRING, { VCH }, FRZ(S_TRUNC) },
+ { S_STRING, { '\n' }, FRZ(S_BEHEAD) },
+ { S_STRING, { '\\' }, PUT(S_STRING2) },
+ { S_STRING, { '"' }, PUT(STO(STRING)) },
+
+ { S_STRING2, { ANY }, PUT(S_STRING) },
+ { S_STRING2, { VCH }, FRZ(S_TRUNC) },
+
+ /* after a # */
+ { S_SHARP, { ANY }, FRZ(STO(SHARP)) },
+ { S_SHARP, { '#' }, STO(DSHARP) },
+
+ /* after a : */
+ { S_COLON, { ANY }, FRZ(STO(COLON)) },
+ { S_COLON, { '>' }, STO(DIG_RBRK) },
+
+ /* after a % */
+ { S_PCT, { ANY }, FRZ(STO(PCT)) },
+ { S_PCT, { '=' }, STO(ASPCT) },
+ { S_PCT, { '>' }, STO(DIG_RBRA) },
+ { S_PCT, { ':' }, S_PCT2 },
+
+ /* after a %: */
+ { S_PCT2, { ANY }, FRZ(STO(DIG_SHARP)) },
+ { S_PCT2, { '%' }, S_PCT3 },
+
+ /* after a %:% */
+ { S_PCT3, { ANY }, FRZ(S_DDSHARP) },
+ { S_PCT3, { ':' }, STO(DIG_DSHARP) },
+
+ /* after a & */
+ { S_AMPER, { ANY }, FRZ(STO(AND)) },
+ { S_AMPER, { '=' }, STO(ASAND) },
+ { S_AMPER, { '&' }, STO(LAND) },
+
+ /* after a ' */
+ { S_CHAR, { ANY }, PUT(S_CHAR) },
+ { S_CHAR, { VCH }, FRZ(S_TRUNC) },
+ { S_CHAR, { '\'' }, PUT(STO(CHAR)) },
+ { S_CHAR, { '\\' }, PUT(S_CHAR2) },
+
+ /* after a \ in a character constant
+ useful only for '\'' */
+ { S_CHAR2, { ANY }, PUT(S_CHAR) },
+ { S_CHAR2, { VCH }, FRZ(S_TRUNC) },
+
+ /* after a * */
+ { S_STAR, { ANY }, FRZ(STO(STAR)) },
+ { S_STAR, { '=' }, STO(ASSTAR) },
+
+ /* after a + */
+ { S_PLUS, { ANY }, FRZ(STO(PLUS)) },
+ { S_PLUS, { '+' }, STO(PPLUS) },
+ { S_PLUS, { '=' }, STO(ASPLUS) },
+
+ /* after a - */
+ { S_MINUS, { ANY }, FRZ(STO(MINUS)) },
+ { S_MINUS, { '-' }, STO(MMINUS) },
+ { S_MINUS, { '=' }, STO(ASMINUS) },
+ { S_MINUS, { '>' }, STO(ARROW) },
+
+ /* after a . */
+ { S_DOT, { ANY }, FRZ(STO(DOT)) },
+ { S_DOT, { NUM }, PUT(S_NUMBER) },
+ { S_DOT, { '.' }, S_DOT2 },
+
+ /* after .. */
+ { S_DOT2, { ANY }, FRZ(S_DDOT) },
+ { S_DOT2, { '.' }, STO(MDOTS) },
+
+ /* after a / */
+ { S_SLASH, { ANY }, FRZ(STO(SLASH)) },
+ { S_SLASH, { '=' }, STO(ASSLASH) },
+#ifdef SEMPER_FIDELIS
+ { S_SLASH, { '*' }, PUT(S_COMMENT) },
+ { S_SLASH, { '/' }, PUT(S_COMMENT5) },
+#else
+ { S_SLASH, { '*' }, S_COMMENT },
+ { S_SLASH, { '/' }, S_COMMENT5 },
+#endif
+ /*
+ * There is a little hack in read_token() to disable
+ * this last rule, if C++ (C99) comments are not enabled.
+ */
+
+ /* after a number */
+ { S_NUMBER, { ANY }, FRZ(STO(NUMBER)) },
+ { S_NUMBER, { ALP, NUM }, PUT(S_NUMBER) },
+ { S_NUMBER, { '.' }, PUT(S_NUMBER) },
+ { S_NUMBER, { 'E', 'e' }, PUT(S_NUMBER2) },
+ { S_NUMBER, { 'P', 'p' }, PUT(S_NUMBER2) },
+
+ { S_NUMBER2, { ANY }, FRZ(STO(NUMBER)) },
+ { S_NUMBER2, { ALP, NUM }, PUT(S_NUMBER) },
+ { S_NUMBER2, { '+', '-' }, PUT(S_NUMBER) },
+
+ /* after a < */
+ { S_LT, { ANY }, FRZ(STO(LT)) },
+ { S_LT, { '=' }, STO(LEQ) },
+ { S_LT, { '<' }, S_LT2 },
+ { S_LT, { ':' }, STO(DIG_LBRK) },
+ { S_LT, { '%' }, STO(DIG_LBRA) },
+
+ { S_LT2, { ANY }, FRZ(STO(LSH)) },
+ { S_LT2, { '=' }, STO(ASLSH) },
+
+ /* after a > */
+ { S_GT, { ANY }, FRZ(STO(GT)) },
+ { S_GT, { '=' }, STO(GEQ) },
+ { S_GT, { '>' }, S_GT2 },
+
+ { S_GT2, { ANY }, FRZ(STO(RSH)) },
+ { S_GT2, { '=' }, STO(ASRSH) },
+
+ /* after a = */
+ { S_EQ, { ANY }, FRZ(STO(ASGN)) },
+ { S_EQ, { '=' }, STO(SAME) },
+#ifdef CAST_OP
+ { S_EQ, { '>' }, STO(CAST) },
+#endif
+
+ /* after a \ */
+ { S_BACKSLASH, { ANY }, FRZ(S_BS) },
+ { S_BACKSLASH, { 'U', 'u' }, FRZ(S_NAME_BS) },
+
+ /* after a letter */
+ { S_NAME, { ANY }, FRZ(STO(NAME)) },
+ { S_NAME, { ALP, NUM }, PUT(S_NAME) },
+ { S_NAME, { '\\' }, S_NAME_BS },
+#ifdef HAVE_ECPP
+ { S_NAME, { ':' }, PUT(S_NAME) },
+#endif
+
+ /* after a \ in an identifier */
+ { S_NAME_BS, { ANY }, FRZ(S_ROGUE_BS) },
+ { S_NAME_BS, { 'u', 'U' }, PUT(S_NAME) },
+
+ /* after a L */
+ { S_LCHAR, { ANY }, FRZ(S_NAME) },
+ { S_LCHAR, { '"' }, PUT(S_STRING) },
+ { S_LCHAR, { '\'' }, PUT(S_CHAR) },
+
+ /* after a ^ */
+ { S_CIRC, { ANY }, FRZ(STO(CIRC)) },
+ { S_CIRC, { '=' }, STO(ASCIRC) },
+
+ /* after a | */
+ { S_PIPE, { ANY }, FRZ(STO(OR)) },
+ { S_PIPE, { '=' }, STO(ASOR) },
+ { S_PIPE, { '|' }, STO(LOR) },
+
+ /* after a ~ */
+ { S_TILDE, { ANY }, FRZ(STO(NOT)) },
+ { S_TILDE, { '=' }, STO(ASNOT) },
+
+ /* after a / and * */
+#ifdef SEMPER_FIDELIS
+ { S_COMMENT, { ANY }, PUT(S_COMMENT) },
+ { S_COMMENT, { VCH }, FRZ(S_TRUNCC) },
+ { S_COMMENT, { '*' }, PUT(S_COMMENT2) },
+
+ { S_COMMENT2, { ANY }, FRZ(S_COMMENT) },
+ { S_COMMENT2, { VCH }, FRZ(S_TRUNCC) },
+ { S_COMMENT2, { '*' }, PUT(S_COMMENT2) },
+ { S_COMMENT2, { '/' }, STO(PUT(COMMENT)) },
+
+ { S_COMMENT5, { ANY }, PUT(S_COMMENT5) },
+ { S_COMMENT5, { VCH }, FRZ(S_DECAY) },
+ { S_COMMENT5, { '\n' }, FRZ(STO(COMMENT)) },
+#else
+ { S_COMMENT, { ANY }, S_COMMENT },
+ { S_COMMENT, { VCH }, FRZ(S_TRUNCC) },
+ { S_COMMENT, { '*' }, S_COMMENT2 },
+
+ { S_COMMENT2, { ANY }, FRZ(S_COMMENT) },
+ { S_COMMENT2, { VCH }, FRZ(S_TRUNCC) },
+ { S_COMMENT2, { '*' }, S_COMMENT2 },
+ { S_COMMENT2, { '/' }, STO(COMMENT) },
+
+ { S_COMMENT5, { ANY }, S_COMMENT5 },
+ { S_COMMENT5, { VCH }, FRZ(S_DECAY) },
+ { S_COMMENT5, { '\n' }, FRZ(STO(COMMENT)) },
+#endif
+
+ /* dummy end of machine description */
+ { 0, { 0 }, 0 }
+};
+
+/*
+ * cppm is the table used to store the automaton: if we are in state s
+ * and we read character c, we apply the action cppm[s][c] (jumping to
+ * another state, or emitting a token).
+ * cppm_vch is the table for the special virtual character "end of input"
+ */
+static int cppm[MSTATE][MAX_CHAR_VAL];
+static int cppm_vch[MSTATE];
+
+/*
+ * init_cppm() fills cppm[][] with the information stored in cppms[].
+ * It must be called before beginning the lexing process.
+ */
+void init_cppm(void)
+{
+ int i, j, k, c;
+ static unsigned char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ static unsigned char lower[] = "abcdefghijklmnopqrstuvwxyz";
+ unsigned char *cp;
+
+ for (i = 0; i < MSTATE; i ++) {
+ for (j = 0; j < MAX_CHAR_VAL; j ++) cppm[i][j] = S_OUCH;
+ cppm_vch[i] = S_OUCH;
+ }
+ for (i = 0; cppms[i].input[0]; i ++) for (k = 0; k < CMCR; k ++) {
+ int s = cppms[i].state;
+ int ns = cppms[i].new_state;
+
+ switch (c = cppms[i].input[k]) {
+ case 0:
+ break;
+ case SPC:
+ /* see space_char() also */
+ cppm[s][' '] = ns;
+ cppm[s]['\t'] = ns;
+ cppm[s]['\v'] = ns;
+ cppm[s]['\f'] = ns;
+#ifdef UNBREAKABLE_SPACE
+ if (MAX_CHAR_VAL > UNBREAKABLE_SPACE)
+ cppm[s][UNBREAKABLE_SPACE] = ns;
+#endif
+ break;
+ case ALP:
+ for (cp = upper; *cp; cp ++) cppm[s][(int)*cp] = ns;
+ for (cp = lower; *cp; cp ++) cppm[s][(int)*cp] = ns;
+ cppm[s]['_'] = ns;
+ break;
+ case NUM:
+ for (j = '0'; j <= '9'; j ++) cppm[s][j] = ns;
+ break;
+ case ANY:
+ for (j = 0; j < MAX_CHAR_VAL; j ++) cppm[s][j] = ns;
+ cppm_vch[s] = ns;
+ break;
+ case VCH:
+ cppm_vch[s] = ns;
+ break;
+ default:
+ cppm[s][c] = ns;
+ break;
+ }
+ }
+}
+
+int space_char(int c)
+{
+ if (c == ' ' || c == '\t' || c == '\v' || c == '\f'
+#ifdef UNBREAKABLE_SPACE
+ || c == UNBREAKABLE_SPACE
+#endif
+ ) return 1;
+ return 0;
+}
+
+#ifndef NO_UCPP_BUF
+/*
+ * our output buffer is full, flush it
+ */
+void flush_output(struct lexer_state *ls)
+{
+ size_t x = ls->sbuf, y = 0, z;
+
+ if (ls->sbuf == 0) return;
+ do {
+ z = fwrite(ls->output_buf + y, 1, x, ls->output);
+ x -= z;
+ y += z;
+ } while (z && x > 0);
+ if (!y) {
+ error(ls->line, "could not flush output (disk full ?)");
+ die();
+ }
+ ls->sbuf = 0;
+}
+#endif
+
+/*
+ * Output one character; flush the buffer if needed.
+ * This function should not be called, except by put_char().
+ */
+static inline void write_char(struct lexer_state *ls, unsigned char c)
+{
+#ifndef NO_UCPP_BUF
+ ls->output_buf[ls->sbuf ++] = c;
+ if (ls->sbuf == OUTPUT_BUF_MEMG) flush_output(ls);
+#else
+ if (putc((int)c, ls->output) == EOF) {
+ error(ls->line, "output write error (disk full ?)");
+ die();
+ }
+#endif
+ if (c == '\n') {
+ ls->oline ++;
+ }
+}
+
+/*
+ * schedule a character for output
+ */
+void put_char(struct lexer_state *ls, unsigned char c)
+{
+ if (ls->flags & KEEP_OUTPUT) write_char(ls, c);
+}
+
+/*
+ * get next raw input character
+ */
+static inline int read_char(struct lexer_state *ls)
+{
+ unsigned char c;
+
+ if (!ls->input) {
+ return ((ls->pbuf ++) < ls->ebuf) ?
+ ls->input_string[ls->pbuf - 1] : -1;
+ }
+ while (1) {
+#ifndef NO_UCPP_BUF
+ if (ls->pbuf == ls->ebuf) {
+#ifdef UCPP_MMAP
+ if (ls->from_mmap) {
+ munmap((void *)ls->input_buf, ls->ebuf);
+ ls->from_mmap = 0;
+ ls->input_buf = ls->input_buf_sav;
+ }
+#endif
+ ls->ebuf = fread(ls->input_buf, 1,
+ INPUT_BUF_MEMG, ls->input);
+ ls->pbuf = 0;
+ }
+ if (ls->ebuf == 0) return -1;
+ c = ls->input_buf[ls->pbuf ++];
+#else
+ int x = getc(ls->input);
+
+ if (x == EOF) return -1;
+ c = x;
+#endif
+ if (ls->flags & COPY_LINE) {
+ if (c == '\n') {
+ ls->copy_line[ls->cli] = 0;
+ ls->cli = 0;
+ } else if (ls->cli < (COPY_LINE_LENGTH - 1)) {
+ ls->copy_line[ls->cli ++] = c;
+ }
+ }
+ if (ls->macfile && c == '\n') {
+ ls->macfile = 0;
+ continue;
+ }
+ ls->macfile = 0;
+ if (c == '\r') {
+ /*
+ * We found a '\r'; we handle it as a newline
+ * and ignore the next newline. This should work
+ * with all combinations of Msdos, MacIntosh and
+ * Unix files on these three platforms. On other
+ * platforms, native file formats are always
+ * supported.
+ */
+ ls->macfile = 1;
+ c = '\n';
+ }
+ break;
+ }
+ /*vb*/
+#ifdef HAVE_MISRA
+ if(misracheck){
+ if(!isspace((unsigned char)c)&&
+ (c<'A'||c>'Z')&&
+ (c<'a'||c>'z')&&
+ (c<'0'||c>'9')&&
+ c!='!'&&c!='\"'&&c!='#'&&c!='%'&&c!='&'&&c!='\''&&c!='('&&c!=')'&&
+ c!='*'&&c!='+'&&c!=','&&c!='-'&&c!='.'&&c!='/'&&c!=':'&&
+ c!=';'&&c!='<'&&c!='='&&c!='>'&&c!='?'&&c!='['&&c!=']'&&
+ c!='^'&&c!='_'&&c!='{'&&c!='|'&&c!='}'&&c!='~'&&c!='\\'
+ )
+ misra_neu(5,4,1,ls->line,c,' ');
+ }
+#endif
+ return c;
+}
+
+/*
+ * next_fifo_char(), char_lka1() and char_lka2() give a two character
+ * look-ahead on the input stream; this is needed for trigraphs
+ */
+static inline int next_fifo_char(struct lexer_state *ls)
+{
+ int c;
+
+ if (ls->nlka != 0) {
+ c = ls->lka[0];
+ ls->lka[0] = ls->lka[1];
+ ls->nlka --;
+ } else c = read_char(ls);
+ return c;
+}
+
+static inline int char_lka1(struct lexer_state *ls)
+{
+ if (ls->nlka == 0) {
+ ls->lka[0] = read_char(ls);
+ ls->nlka ++;
+ }
+ return ls->lka[0];
+}
+
+static inline int char_lka2(struct lexer_state *ls)
+{
+#ifdef AUDIT
+ if (ls->nlka == 0) ouch("always in motion future is");
+#endif
+ if (ls->nlka == 1) {
+ ls->lka[1] = read_char(ls);
+ ls->nlka ++;
+ }
+ return ls->lka[1];
+}
+
+static struct trigraph {
+ int old, new;
+} trig[9] = {
+ { '=', '#' },
+ { '/', '\\' },
+ { '\'', '^' },
+ { '(', '[' },
+ { ')', ']' },
+ { '!', '|' },
+ { '<', '{' },
+ { '>', '}' },
+ { '-', '~' }
+};
+
+/*
+ * Returns the next character, after treatment of trigraphs and terminating
+ * backslashes. Return value is -1 if there is no more input.
+ */
+static inline int next_char(struct lexer_state *ls)
+{
+ int c;
+
+ if (!ls->discard) return ls->last;
+ ls->discard = 0;
+ do {
+ c = next_fifo_char(ls);
+#ifdef HAVE_ECPP
+ if(c==':'){
+ if(char_lka1(ls)==':'){
+ next_fifo_char(ls);
+ }else{
+ c='@';
+ }
+ }
+#endif
+ /* check trigraphs */
+ if (c == '?' && char_lka1(ls) == '?'
+ && (ls->flags & HANDLE_TRIGRAPHS)) {
+ int i, d;
+
+ d = char_lka2(ls);
+ for (i = 0; i < 9; i ++) if (d == trig[i].old) {
+ if (ls->flags & WARN_TRIGRAPHS) {
+ ls->count_trigraphs ++;
+ }
+ if (ls->flags & WARN_TRIGRAPHS_MORE) {
+ warning(ls->line, "trigraph ?""?%c "
+ "encountered", d);
+ /*vb*/
+#ifdef HAVE_MISRA
+ misra_neu(7,4,2,-1,d);
+#endif
+ }
+ next_fifo_char(ls);
+ next_fifo_char(ls);
+ c = trig[i].new;
+ break;
+ }
+ }
+ if (c == '\\' && char_lka1(ls) == '\n') {
+ ls->line ++;
+ next_fifo_char(ls);
+ } else {
+ ls->last = c;
+ return c;
+ }
+ } while (1);
+}
+
+/*
+ * wrapper for next_char(), to be called from outside
+ * (used by #error, #include directives)
+ */
+int grap_char(struct lexer_state *ls)
+{
+ return next_char(ls);
+}
+
+/*
+ * Discard the current character, so that the next call to next_char()
+ * will step into the input stream.
+ */
+void discard_char(struct lexer_state *ls)
+{
+#ifdef AUDIT
+ if (ls->discard) ouch("overcollecting garbage");
+#endif
+ ls->discard = 1;
+ ls->utf8 = 0;
+ if (ls->last == '\n') ls->line ++;
+}
+
+/*
+ * Convert an UTF-8 encoded character to a Universal Character Name
+ * using \u (or \U when appropriate).
+ */
+static int utf8_to_string(unsigned char buf[], unsigned long utf8)
+{
+ unsigned long val = 0;
+ static char hex[16] = "0123456789abcdef";
+
+ if (utf8 & 0x80UL) {
+ unsigned long x1, x2, x3, x4;
+
+ x1 = (utf8 >> 24) & 0x7fUL;
+ x2 = (utf8 >> 16) & 0x7fUL;
+ x3 = (utf8 >> 8) & 0x7fUL;
+ x4 = (utf8) & 0x3fUL;
+ x1 &= 0x07UL;
+ if (x2 & 0x40UL) x2 &= 0x0fUL;
+ if (x3 & 0x40UL) x3 &= 0x1fUL;
+ val = x4 | (x3 << 6) | (x2 << 12) | (x1 << 16);
+ } else val = utf8;
+ if (val < 128) {
+ buf[0] = val;
+ buf[1] = 0;
+ return 1;
+ } else if (val < 0xffffUL) {
+ buf[0] = '\\';
+ buf[1] = 'u';
+ buf[2] = hex[(size_t)(val >> 12)];
+ buf[3] = hex[(size_t)((val >> 8) & 0xfU)];
+ buf[4] = hex[(size_t)((val >> 4) & 0xfU)];
+ buf[5] = hex[(size_t)(val & 0xfU)];
+ buf[6] = 0;
+ return 6;
+ }
+ buf[0] = '\\';
+ buf[1] = 'U';
+ buf[2] = '0';
+ buf[3] = '0';
+ buf[4] = hex[(size_t)(val >> 20)];
+ buf[5] = hex[(size_t)((val >> 16) & 0xfU)];
+ buf[6] = hex[(size_t)((val >> 12) & 0xfU)];
+ buf[7] = hex[(size_t)((val >> 8) & 0xfU)];
+ buf[8] = hex[(size_t)((val >> 4) & 0xfU)];
+ buf[9] = hex[(size_t)(val & 0xfU)];
+ buf[10] = 0;
+ return 10;
+}
+
+/*
+ * Scan the identifier and put it in canonical form:
+ * -- tranform \U0000xxxx into \uxxxx
+ * -- inside \u and \U, make letters low case
+ * -- report (some) incorrect use of UCN
+ */
+static void canonize_id(struct lexer_state *ls, char *id)
+{
+ char *c, *d;
+
+ for (c = d = id; *c;) {
+ if (*c == '\\') {
+ int i;
+
+ if (!*(c + 1)) goto canon_error;
+ if (*(c + 1) == 'U') {
+ for (i = 0; i < 8 && *(c + i + 2); i ++);
+ if (i != 8) goto canon_error;
+ *(d ++) = '\\';
+ c += 2;
+ for (i = 0; i < 4 && *(c + i) == '0'; i ++);
+ if (i == 4) {
+ *(d ++) = 'u';
+ c += 4;
+ } else {
+ *(d ++) = 'U';
+ i = 8;
+ }
+ for (; i > 0; i --) {
+ switch (*c) {
+ case 'A': *(d ++) = 'a'; break;
+ case 'B': *(d ++) = 'b'; break;
+ case 'C': *(d ++) = 'c'; break;
+ case 'D': *(d ++) = 'd'; break;
+ case 'E': *(d ++) = 'e'; break;
+ case 'F': *(d ++) = 'f'; break;
+ default: *(d ++) = *c; break;
+ }
+ c ++;
+ }
+ } else if (*(c + 1) == 'u') {
+ for (i = 0; i < 4 && *(c + i + 2); i ++);
+ if (i != 4) goto canon_error;
+ *(d ++) = '\\';
+ *(d ++) = 'u';
+ c += 2;
+ for (; i > 0; i --) {
+ switch (*c) {
+ case 'A': *(d ++) = 'a'; break;
+ case 'B': *(d ++) = 'b'; break;
+ case 'C': *(d ++) = 'c'; break;
+ case 'D': *(d ++) = 'd'; break;
+ case 'E': *(d ++) = 'e'; break;
+ case 'F': *(d ++) = 'f'; break;
+ default: *(d ++) = *c; break;
+ }
+ c ++;
+ }
+ } else goto canon_error;
+ continue;
+ }
+ *(d ++) = *(c ++);
+ }
+ *d = 0;
+ return;
+
+canon_error:
+ for (; *c; *(d ++) = *(c ++));
+ if (ls->flags & WARN_STANDARD) {
+ warning(ls->line, "malformed identifier with UCN: '%s'", id);
+ }
+ *d = 0;
+}
+
+/*
+ * Run the automaton, in order to get the next token.
+ * This function should not be called, except by next_token()
+ *
+ * return value: 1 on error, 2 on end-of-file, 0 otherwise.
+ */
+static inline int read_token(struct lexer_state *ls)
+{
+ int cstat = S_START, nstat;
+ size_t ltok = 0;
+ int c, outc = 0, ucn_in_id = 0;
+ int shift_state;
+ unsigned long utf8;
+ long l = ls->line;
+
+ ls->ctok->line = l;
+ if (ls->pending_token) {
+ if ((ls->ctok->type = ls->pending_token) == BUNCH) {
+ ls->ctok->name[0] = '\\';
+ ls->ctok->name[1] = 0;
+ }
+ ls->pending_token = 0;
+ return 0;
+ }
+ if (ls->flags & UTF8_SOURCE) {
+ utf8 = ls->utf8;
+ shift_state = 0;
+ }
+ if (!(ls->flags & LEXER) && (ls->flags & KEEP_OUTPUT))
+ for (; ls->line > ls->oline;) put_char(ls, '\n');
+ do {
+ c = next_char(ls);
+ if (c < 0) {
+ if ((ls->flags & UTF8_SOURCE) && shift_state) {
+ if (ls->flags & WARN_STANDARD)
+ warning(ls->line, "truncated UTF-8 "
+ "character");
+ shift_state = 0;
+ utf8 = 0;
+ }
+ if (cstat == S_START) return 2;
+ nstat = cppm_vch[cstat];
+ } else {
+ if (ls->flags & UTF8_SOURCE) {
+ if (shift_state) {
+ if ((c & 0xc0) != 0x80) {
+ if (ls->flags & WARN_STANDARD)
+ warning(ls->line,
+ "truncated "
+ "UTF-8 "
+ "character");
+ shift_state = 0;
+ utf8 = 0;
+ c = '_';
+ } else {
+ utf8 = (utf8 << 8) | c;
+ if (-- shift_state) {
+ ls->discard = 1;
+ continue;
+ }
+ c = '_';
+ }
+ } else if ((c & 0xc0) == 0xc0) {
+ if ((c & 0x30) == 0x30) {
+ shift_state = 3;
+ } else if (c & 0x20) {
+ shift_state = 2;
+ } else {
+ shift_state = 1;
+ }
+ utf8 = c;
+ ls->discard = 1;
+ continue;
+ } else utf8 = 0;
+ }
+ nstat = cppm[cstat][c < MAX_CHAR_VAL ? c : 0];
+ }
+#ifdef AUDIT
+ if (nstat == S_OUCH) {
+ ouch("bad move...");
+ }
+#endif
+ /*
+ * disable C++-like comments
+ */
+ if (nstat == S_COMMENT5 && !(ls->flags & CPLUSPLUS_COMMENTS))
+ nstat = FRZ(STO(SLASH));
+
+ if (noMOD(nstat) >= MSTATE && !ttSTO(nstat))
+ switch (noMOD(nstat)) {
+ case S_ILL:
+ if (ls->flags & CCHARSET) {
+ error(ls->line, "illegal character '%c'", c);
+ return 1;
+ }
+ nstat = PUT(STO(BUNCH));
+ break;
+ case S_BS:
+ ls->ctok->name[0] = '\\';
+ ltok ++;
+ nstat = FRZ(STO(BUNCH));
+ if (!(ls->flags & LEXER)) put_char(ls, '\\');
+ break;
+ case S_ROGUE_BS:
+ ls->pending_token = BUNCH;
+ nstat = FRZ(STO(NAME));
+ break;
+ case S_DDOT:
+ ls->pending_token = DOT;
+ nstat = FRZ(STO(DOT));
+ break;
+ case S_DDSHARP:
+ ls->pending_token = PCT;
+ nstat = FRZ(STO(DIG_SHARP));
+ break;
+ case S_BEHEAD:
+ error(l, "unfinished string at end of line");
+ return 1;
+ case S_DECAY:
+ warning(l, "unterminated // comment");
+ nstat = FRZ(STO(COMMENT));
+ break;
+ case S_TRUNC:
+ error(l, "truncated token");
+ return 1;
+ case S_TRUNCC:
+ error(l, "truncated comment");
+ return 1;
+#ifdef AUDIT
+ case S_OUCH:
+ ouch("machine went out of control");
+ break;
+#endif
+ }
+ if (!ttFRZ(nstat)) {
+ discard_char(ls);
+ if (!(ls->flags & LEXER) && ls->condcomp) {
+ int z = ttSTO(nstat) ? S_ILL : noMOD(nstat);
+
+ if (cstat == S_NAME || z == S_NAME
+ || ((CMT(cstat) || CMT(z))
+ && (ls->flags & DISCARD_COMMENTS))) {
+ outc = 0;
+ } else if (z == S_LCHAR || z == S_SLASH
+ || (z == S_SHARP && ls->ltwnl)
+ || (z == S_PCT && ls->ltwnl)
+ || (z == S_BACKSLASH)) {
+ outc = c;
+ } else if (z == S_PCT2 && ls->ltwnl) {
+ outc = -1;
+ } else if (z == S_PCT3 && ls->ltwnl) {
+ /* we have %:% but this still might
+ not be a %:%: */
+ outc = -2;
+ } else {
+ if (outc < 0) {
+ put_char(ls, '%');
+ put_char(ls, ':');
+ if (outc == -2)
+ put_char(ls, '%');
+ outc = 0;
+ } else if (outc) {
+ put_char(ls, outc);
+ outc = 0;
+ }
+ put_char(ls, c);
+ }
+ }
+ } else if (outc == '/' && !(ls->flags & LEXER)
+ && ls->condcomp) {
+ /* this is a hack: we need to dump a pending slash */
+ put_char(ls, outc);
+ outc = 0;
+ }
+ if (ttPUT(nstat)) {
+ if (cstat == S_NAME_BS) {
+ ucn_in_id = 1;
+ wan(ls->ctok->name, ltok, '\\', ls->tknl);
+ }
+ if ((ls->flags & UTF8_SOURCE) && utf8) {
+ unsigned char buf[11];
+ int i, j;
+
+ for (i = 0, j = utf8_to_string(buf, utf8);
+ i < j; i ++)
+ wan(ls->ctok->name, ltok, buf[i],
+ ls->tknl);
+ /* if (j > 1) ucn_in_id = 1; */
+ } else wan(ls->ctok->name, ltok,
+ (unsigned char)c, ls->tknl);
+ }
+ if (ttSTO(nstat)) {
+ if (S_TOKEN(noMOD(nstat))) {
+ wan(ls->ctok->name, ltok,
+ (unsigned char)0, ls->tknl);
+ }
+ ls->ctok->type = noMOD(nstat);
+ break;
+ }
+ cstat = noMOD(nstat);
+ } while (1);
+ if (!(ls->flags & LEXER) && (ls->flags & DISCARD_COMMENTS)
+ && ls->ctok->type == COMMENT) put_char(ls, ' ');
+ if (ucn_in_id && ls->ctok->type == NAME)
+ canonize_id(ls, ls->ctok->name);
+ return 0;
+}
+
+/*
+ * fills ls->ctok with the next token
+ */
+int next_token(struct lexer_state *ls)
+{
+ if (ls->flags & READ_AGAIN) {
+ ls->flags &= ~READ_AGAIN;
+ if (!(ls->flags & LEXER)) {
+ char *c = S_TOKEN(ls->ctok->type) ?
+ ls->ctok->name : token_name(ls->ctok);
+ if (ls->ctok->type == OPT_NONE) {
+ ls->ctok->type = NONE;
+#ifdef SEMPER_FIDELIS
+ ls->ctok->name[0] = ' ';
+ ls->ctok->name[1] = 0;
+#endif
+ put_char(ls, ' ');
+ } else if (ls->ctok->type != NAME &&
+ !(ls->ltwnl && (ls->ctok->type == SHARP
+ || ls->ctok->type == DIG_SHARP)))
+ for (; *c; c ++) put_char(ls, *c);
+ }
+ return 0;
+ }
+ return read_token(ls);
+}
diff --git a/ucpp/macro.c b/ucpp/macro.c
new file mode 100755
index 0000000..d42e006
--- /dev/null
+++ b/ucpp/macro.c
@@ -0,0 +1,1870 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/*vb*/
+#ifdef HAVE_MISRA
+void misra(int,...);
+void misra_neu(int, int, int, int, ...);
+int misra_is_reserved(const char*);
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <limits.h>
+#include <ctype.h>
+#include "ucppi.h"
+#include "mem.h"
+#include "hash.h"
+#include "tune.h"
+
+/*vb*/
+extern int nesting;
+#ifdef HAVE_MISRA
+extern int misracheck;
+#endif
+
+/*
+ * we store macros in a hash table, and retrieve them using their name
+ * as identifier.
+ */
+static struct HT *macros = 0;
+
+static void del_macro(void *m)
+{
+ struct macro *n = m;
+ int i;
+
+ if (n->name) freemem(n->name);
+ for (i = 0; i < n->narg; i ++) freemem(n->arg[i]);
+ if (n->narg > 0) freemem(n->arg);
+#ifdef LOW_MEM
+ if (n->cval.length) freemem(n->cval.t);
+#else
+ if (n->val.nt) {
+ for (i = 0; i < n->val.nt; i ++)
+ if (S_TOKEN(n->val.t[i].type))
+ freemem(n->val.t[i].name);
+ freemem(n->val.t);
+ }
+#endif
+ freemem(n);
+}
+
+static inline struct macro *new_macro(void)
+{
+ struct macro *m = getmem(sizeof(struct macro));
+
+ m->name = 0;
+ m->narg = -1;
+ m->nest = 0;
+#ifdef LOW_MEM
+ m->cval.length = 0;
+#else
+ m->val.nt = m->val.art = 0;
+#endif
+ m->vaarg = 0;
+ return m;
+}
+
+/*
+ * for special macros, and the "defined" operator
+ */
+enum {
+ MAC_NONE, MAC_DEFINED,
+ MAC_LINE, MAC_FILE, MAC_DATE, MAC_ADATE, MAC_TIME, MAC_STDC, MAC_PRAGMA
+};
+#define MAC_SPECIAL MAC_LINE
+
+/*
+ * returns 1 for "defined"
+ * returns x > 1 for a special macro such as __FILE__
+ * returns 0 otherwise
+ */
+static inline int check_special_macro(char *name)
+{
+ if (!strcmp(name, "defined")) return MAC_DEFINED;
+ if (*name != '_') return MAC_NONE;
+ if (*(name + 1) == 'P') {
+ if (!strcmp(name, "_Pragma")) return MAC_PRAGMA;
+ return MAC_NONE;
+ } else if (*(name + 1) != '_') return MAC_NONE;
+ if (no_special_macros) return MAC_NONE;
+ if (!strcmp(name, "__LINE__")) return MAC_LINE;
+ else if (!strcmp(name, "__FILE__")) return MAC_FILE;
+ else if (!strcmp(name, "__DATE__")) return MAC_DATE;
+ else if (!strcmp(name, "__AMIGADATE__")) return MAC_ADATE;
+ else if (!strcmp(name, "__TIME__")) return MAC_TIME;
+ else if (!strcmp(name, "__STDC__")) return MAC_STDC;
+ return MAC_NONE;
+}
+
+int c99_compliant = 1;
+int c99_hosted = 1;
+
+/*
+ * add the special macros to the macro table
+ */
+static void add_special_macros(void)
+{
+ struct macro *m;
+
+ m = new_macro(); m->name = sdup("__LINE__"); putHT(macros, m);
+ m = new_macro(); m->name = sdup("__FILE__"); putHT(macros, m);
+ m = new_macro(); m->name = sdup("__DATE__"); putHT(macros, m);
+ m = new_macro(); m->name = sdup("__AMIGADATE__"); putHT(macros, m);
+ m = new_macro(); m->name = sdup("__TIME__"); putHT(macros, m);
+ m = new_macro(); m->name = sdup("__STDC__"); putHT(macros, m);
+ m = new_macro(); m->name = sdup("_Pragma"); m->narg = 1;
+ m->arg = getmem(sizeof(char *)); m->arg[0] = sdup("foo");
+ putHT(macros, m);
+ if (c99_compliant) {
+#ifndef LOW_MEM
+ struct token t;
+#endif
+
+ m = new_macro();
+ m->name = sdup("__STDC_VERSION__");
+#ifdef LOW_MEM
+ m->cval.t = getmem(9);
+ m->cval.t[0] = NUMBER;
+ mmv(m->cval.t + 1, "199901L", 8);
+ m->cval.length = 9;
+#else
+ t.type = NUMBER;
+ t.line = 0;
+ t.name = sdup("199901L");
+ aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG);
+#endif
+ putHT(macros, m);
+ }
+ if (c99_hosted) {
+#ifndef LOW_MEM
+ struct token t;
+#endif
+
+ m = new_macro();
+ m->name = sdup("__STDC_HOSTED__");
+#ifdef LOW_MEM
+ m->cval.t = getmem(3);
+ m->cval.t[0] = NUMBER;
+ mmv(m->cval.t + 1, "1", 2);
+ m->cval.length = 3;
+#else
+ t.type = NUMBER;
+ t.line = 0;
+ t.name = sdup("1");
+ aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG);
+#endif
+ putHT(macros, m);
+ }
+}
+
+/*
+ * print the content of a macro, in #define form
+ */
+static void print_macro(void *vm)
+{
+ struct macro *m = vm;
+ int x = check_special_macro(m->name);
+ int i;
+
+ if (x != MAC_NONE) {
+ fprintf(emit_output, "/* #define %s */ /* special */\n",
+ m->name);
+ return;
+ }
+ fprintf(emit_output, "#define %s", m->name);
+ if (m->narg >= 0) {
+ fprintf(emit_output, "(");
+ for (i = 0; i < m->narg; i ++) {
+ fprintf(emit_output, i ? ", %s" : "%s", m->arg[i]);
+ }
+ if (m->vaarg) {
+ fputs(m->narg ? ", ..." : "...", emit_output);
+ }
+ fprintf(emit_output, ")");
+ }
+#ifdef LOW_MEM
+ if (m->cval.length == 0) {
+ fputc('\n', emit_output);
+ return;
+ }
+ fputc(' ', emit_output);
+ for (i = 0; i < m->cval.length;) {
+ int tt = m->cval.t[i ++];
+
+ if (tt == MACROARG) {
+ if (m->cval.t[i] == m->narg)
+ fputs("__VA_ARGS__", emit_output);
+ else
+ fputs(m->arg[(size_t)(m->cval.t[i])],
+ emit_output);
+ i ++;
+ }
+ else if (S_TOKEN(tt)) {
+ fputs((char *)(m->cval.t + i), emit_output);
+ i += 1 + strlen((char *)(m->cval.t + i));
+ } else fputs(operators_name[tt], emit_output);
+ }
+#else
+ if (m->val.nt == 0) {
+ fputc('\n', emit_output);
+ return;
+ }
+ fputc(' ', emit_output);
+ for (i = 0; i < m->val.nt; i ++) {
+ if (m->val.t[i].type == MACROARG) {
+ if (m->val.t[i].line == m->narg)
+ fputs("__VA_ARGS__", emit_output);
+ else
+ fputs(m->arg[(size_t)(m->val.t[i].line)],
+ emit_output);
+ } else fputs(token_name(m->val.t + i), emit_output);
+ }
+#endif
+ fputc('\n', emit_output);
+}
+
+/*
+ * Send a token to the output (a token_fifo in lexer mode, the output
+ * buffer in stand alone mode).
+ */
+void print_token(struct lexer_state *ls, struct token *t, long uz_line)
+{
+ char *x = t->name;
+
+ if (uz_line && t->line < 0) t->line = uz_line;
+ if (ls->flags & LEXER) {
+ struct token at;
+
+ at = *t;
+ if (S_TOKEN(t->type)) {
+ at.name = sdup(at.name);
+ throw_away(ls->gf, at.name);
+ }
+ aol(ls->output_fifo->t, ls->output_fifo->nt, at,
+ TOKEN_LIST_MEMG);
+ return;
+ }
+ if (ls->flags & KEEP_OUTPUT) {
+ for (; ls->oline < ls->line;) put_char(ls, '\n');
+ }
+ if (!S_TOKEN(t->type)) x = operators_name[t->type];
+ for (; *x; x ++) put_char(ls, *x);
+}
+
+/*
+ * send a reduced whitespace token to the output
+ */
+#define print_space(ls) do { \
+ struct token lt; \
+ lt.type = OPT_NONE; \
+ lt.line = (ls)->line; \
+ print_token((ls), <, 0); \
+ } while (0)
+
+/*
+ * We found a #define directive; parse the end of the line, perform
+ * sanity checks, store the new macro into the "macros" hash table.
+ *
+ * In case of a redefinition of a macro: we enforce the rule that a
+ * macro should be redefined identically, including the spelling of
+ * parameters. We emit an error on offending code; dura lex, sed lex.
+ * After all, it is easy to avoid such problems, with a #undef directive.
+ */
+int handle_define(struct lexer_state *ls)
+{
+ struct macro *m, *n;
+#ifdef LOW_MEM
+ struct token_fifo mv;
+#endif
+ int ltwws = 1, redef = 0;
+ char *mname = 0;
+ int narg;
+ size_t nt;
+ long l = ls->line;
+
+ /*vb*/
+#ifdef HAVE_MISRA
+ if(nesting!=0) misra_neu(91,19,5,0);
+#endif
+
+ /* find the next non-white token on the line, this should be
+ the macro name */
+ while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+ if (ttMWS(ls->ctok->type)) continue;
+ if (ls->ctok->type == NAME) mname = sdup(ls->ctok->name);
+ break;
+ }
+ if (mname == 0) {
+ error(l, "missing macro name");
+ return 1;
+ }
+ if (check_special_macro(mname)) {
+ error(l, "trying to redefine the special macro %s", mname);
+ goto warp_error;
+ }
+ /*
+ * If a macro with this name was already defined: the K&R
+ * states that the new macro should be identical to the old one
+ * (with some arcane rule of equivalence of whitespace); otherwise,
+ * redefining the macro is an error. Most preprocessors would
+ * only emit a warning (or nothing at all) on an unidentical
+ * redefinition.
+ *
+ * Since it is easy to avoid this error (with a #undef directive),
+ * we choose to enforce the rule and emit an error.
+ */
+
+#ifdef HAVE_MISRA
+ if (misra_is_reserved(mname)) misra_neu(114,20,1,-1);
+#endif
+
+ if ((n = getHT(macros, &mname)) != 0) {
+ /* redefinition of a macro: we must check that we define
+ it identical */
+ redef = 1;
+#ifdef LOW_MEM
+ n->cval.rp = 0;
+#endif
+ freemem(mname);
+ }
+ if (!redef) {
+ m = new_macro();
+ m->name = mname;
+ m->narg = -1;
+#ifdef LOW_MEM
+ mv.art = mv.nt = 0;
+#define mval mv
+#else
+#define mval (m->val)
+#endif
+ }
+ if (next_token(ls)) goto define_end;
+ /*
+ * Check if the token immediately following the macro name is
+ * a left parenthesis; if so, then this is a macro with arguments.
+ * Collect their names and try to match the next parenthesis.
+ */
+ if (ls->ctok->type == LPAR) {
+ int i, j;
+ int need_comma = 0, saw_mdots = 0;
+
+ narg = 0;
+ while (!next_token(ls)) {
+ if (ls->ctok->type == NEWLINE) {
+ error(l, "truncated macro definition");
+ return 1;
+ }
+ if (ls->ctok->type == COMMA) {
+ if (saw_mdots) {
+ error(l, "'...' must end the macro "
+ "argument list");
+ goto warp_error;
+ }
+ if (!need_comma) {
+ error(l, "void macro argument");
+ goto warp_error;
+ }
+ need_comma = 0;
+ continue;
+ } else if (ls->ctok->type == NAME) {
+ if (saw_mdots) {
+ error(l, "'...' must end the macro "
+ "argument list");
+ goto warp_error;
+ }
+ if (need_comma) {
+ error(l, "missing comma in "
+ "macro argument list");
+ goto warp_error;
+ }
+ if (!redef) {
+ aol(m->arg, narg,
+ sdup(ls->ctok->name), 8);
+ if (narg == 128
+ && (ls->flags & WARN_STANDARD))
+ warning(l, "more arguments to "
+ "macro than the ISO "
+ "limit (127)");
+#ifdef LOW_MEM
+ if (narg == 254) {
+ error(l, "too many arguments "
+ "in macro definition "
+ "(max 253)");
+ goto warp_error;
+ }
+#endif
+ } else {
+ /* this is a redefinition of the
+ macro; check equality between
+ old and new definitions */
+ if (narg >= n->narg) goto redef_error;
+ if (strcmp(ls->ctok->name,
+ n->arg[narg ++]))
+ goto redef_error;
+ }
+ need_comma = 1;
+ continue;
+ } else if ((ls->flags & MACRO_VAARG)
+ && ls->ctok->type == MDOTS) {
+ if (need_comma) {
+ error(l, "missing comma before '...'");
+ goto warp_error;
+ }
+ if (redef && !n->vaarg) goto redef_error;
+ if (!redef) m->vaarg = 1;
+ saw_mdots = 1;
+ need_comma = 1;
+ continue;
+ } else if (ls->ctok->type == RPAR) {
+ if (narg > 0 && !need_comma) {
+ error(l, "void macro argument");
+ goto warp_error;
+ }
+ if (redef && n->vaarg && !saw_mdots)
+ goto redef_error;
+ break;
+ } else if (ttMWS(ls->ctok->type)) {
+ continue;
+ }
+ error(l, "invalid macro argument");
+ goto warp_error;
+ }
+ if (!redef) {
+ for (i = 1; i < narg; i ++) for (j = 0; j < i; j ++)
+ if (!strcmp(m->arg[i], m->arg[j])) {
+ error(l, "duplicate macro "
+ "argument");
+ goto warp_error;
+ }
+ }
+ if (!redef) m->narg = narg;
+ } else {
+ if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD))
+ warning(ls->line, "identifier not followed by "
+ "whitespace in #define");
+ ls->flags |= READ_AGAIN;
+ narg = 0;
+ }
+ if (redef) nt = 0;
+
+ /* now, we have the arguments. Let's get the macro contents. */
+ while (!next_token(ls) && ls->ctok->type != NEWLINE) {
+ struct token t;
+
+ t.type = ls->ctok->type;
+ if (ltwws && ttMWS(t.type)) continue;
+ t.line = 0;
+ if (t.type == NAME) {
+ int i;
+
+ if ((ls->flags & MACRO_VAARG)
+ && !strcmp(ls->ctok->name, "__VA_ARGS__")) {
+ if (redef) {
+ if (!n->vaarg) goto redef_error;
+ } else if (!m->vaarg) {
+ error(l, "'__VA_ARGS__' is forbidden "
+ "in macros with a fixed "
+ "number of arguments");
+ goto warp_error;
+ }
+ t.type = MACROARG;
+ t.line = redef ? n->narg : m->narg;
+ }
+ for (i = 0; i < narg; i ++)
+ if (!strcmp(redef ? n->arg[i] : m->arg[i],
+ ls->ctok->name)) {
+ t.type = MACROARG;
+ /* this is a hack: we store the
+ argument number in the line field */
+ t.line = i;
+ break;
+ }
+ }
+ if (!redef && S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
+ if (ttMWS(t.type)) {
+ if (ltwws) continue;
+#ifdef SEMPER_FIDELIS
+ t.type = OPT_NONE;
+#else
+ t.type = NONE;
+#endif
+ ltwws = 1;
+ } else ltwws = 0;
+ if (!redef) {
+ /* we ensure that each macro token has a correct
+ line number */
+ if (t.type != MACROARG) t.line = l;
+ aol(mval.t, mval.nt, t, TOKEN_LIST_MEMG);
+ } else {
+#ifdef LOW_MEM
+ int tt;
+
+ if (n->cval.rp >= n->cval.length) {
+#ifdef SEMPER_FIDELIS
+ if (t.type != OPT_NONE) goto redef_error;
+#else
+ if (t.type != NONE) goto redef_error;
+#endif
+ } else if (t.type != n->cval.t[n->cval.rp]
+ || (t.type == MACROARG
+ && t.line != n->cval.t[n->cval.rp + 1])
+ || (S_TOKEN(t.type) && strcmp(ls->ctok->name,
+ (char *)(n->cval.t + n->cval.rp + 1)))) {
+ goto redef_error;
+ }
+ tt = n->cval.t[n->cval.rp ++];
+ if (S_TOKEN(tt)) n->cval.rp += 1
+ + strlen((char *)(n->cval.t + n->cval.rp));
+ else if (tt == MACROARG) n->cval.rp ++;
+#else
+ if (nt >= n->val.nt) {
+#ifdef SEMPER_FIDELIS
+ if (t.type != OPT_NONE) goto redef_error;
+#else
+ if (t.type != NONE) goto redef_error;
+#endif
+ } else if (t.type != n->val.t[nt].type
+ || (t.type == MACROARG
+ && t.line != n->val.t[nt].line)
+ || (S_TOKEN(t.type) && strcmp(ls->ctok->name,
+ n->val.t[nt].name))) {
+ goto redef_error;
+ }
+#endif
+ nt ++;
+ }
+ }
+
+ if (redef) {
+#ifdef LOW_MEM
+ if (n->cval.rp < n->cval.length) goto redef_error_2;
+#else
+ if (nt < n->val.nt) goto redef_error_2;
+#endif
+ return 0;
+ }
+
+ /* now we have the complete macro; perform some checks about
+ the operators # and ##, and, if everything is ok,
+ store the macro into the hash table */
+define_end:
+#ifdef SEMPER_FIDELIS
+ if (mval.nt && mval.t[mval.nt - 1].type == OPT_NONE) {
+#else
+ if (mval.nt && mval.t[mval.nt - 1].type == NONE) {
+#endif
+ mval.nt --;
+ if (mval.nt == 0) freemem(mval.t);
+ }
+ if (mval.nt != 0) {
+ size_t i;
+
+ /* some checks about the macro */
+ if (mval.t[0].type == DSHARP
+ || mval.t[0].type == DIG_DSHARP
+ || mval.t[mval.nt - 1].type == DSHARP
+ || mval.t[mval.nt - 1].type == DIG_DSHARP) {
+ error(l, "operator '##' may neither begin "
+ "nor end a macro");
+ return 1;
+ }
+ if (m->narg >= 0) for (i = 0; i < mval.nt; i ++)
+ if ((mval.t[i].type == SHARP
+ || mval.t[i].type == DIG_SHARP) &&
+ (i == (mval.nt - 1)
+ || (ttMWS(mval.t[i + 1].type) &&
+ (i == mval.nt - 2
+ || mval.t[i + 2].type != MACROARG))
+ || (!ttMWS(mval.t[i + 1].type)
+ && mval.t[i + 1].type != MACROARG))) {
+ error(l, "operator '#' not followed "
+ "by a macro argument");
+ return 1;
+ }
+ }
+#ifdef LOW_MEM
+ {
+ size_t i, l;
+
+ for (i = 0, l = 0; i < mval.nt; i ++) {
+ l ++;
+ if (S_TOKEN(mval.t[i].type))
+ l += 1 + strlen(mval.t[i].name);
+ else if (mval.t[i].type == MACROARG) l ++;
+ }
+ m->cval.length = l;
+ if (l) m->cval.t = getmem(l);
+ for (i = 0, l = 0; i < mval.nt; i ++) {
+ m->cval.t[l ++] = mval.t[i].type;
+ if (S_TOKEN(mval.t[i].type)) {
+ size_t x = 1 + strlen(mval.t[i].name);
+
+ mmv(m->cval.t + l, mval.t[i].name, x);
+ l += x;
+ freemem(mval.t[i].name);
+ }
+ else if (mval.t[i].type == MACROARG)
+ m->cval.t[l ++] = mval.t[i].line;
+ }
+ if (mval.nt) freemem(mval.t);
+ }
+#endif
+
+
+#ifdef LOW_MEM
+ /*vb*/
+#ifdef HAVE_MISRA
+ if(misracheck)
+ {
+ int i,lp=0;
+ for(i=0;i<m->cval.length;){
+ int tt=m->cval.t[i++];
+ if(tt==MACROARG){
+ i++;
+ if(!lp||m->cval.t[i]!=RPAR) misra_neu(96,19,10,0);
+ }else if(S_TOKEN(tt)){
+ i += 1 + strlen((char *)(m->cval.t + i));
+ }else{
+ if(tt==LPAR) lp=1; else lp=0;
+ }
+ }
+ }
+#endif
+#else
+#error not supported
+#endif
+
+ putHT(macros, m);
+ if (emit_defines) print_macro(m);
+ return 0;
+
+redef_error:
+ while (ls->ctok->type != NEWLINE && !next_token(ls));
+redef_error_2:
+ error(l, "macro '%s' redefined unidentically", n->name);
+ return 1;
+warp_error:
+ while (ls->ctok->type != NEWLINE && !next_token(ls));
+ return 1;
+#undef mval
+}
+
+/*
+ * Get the arguments for a macro. This code is tricky because there can
+ * be multiple sources for these arguments, if we are in the middle of
+ * a macro replacement; arguments are macro-replaced before inclusion
+ * into the macro replacement.
+ *
+ * return value:
+ * 1 no argument (last token read from next_token())
+ * 2 no argument (last token read from tfi)
+ * 3 no argument (nothing read)
+ * 4 error
+ *
+ * Void arguments are allowed in C99.
+ */
+static int collect_arguments(struct lexer_state *ls, struct token_fifo *tfi,
+ int penury, struct token_fifo *atl, int narg, int vaarg, int *wr)
+{
+ int ltwws = 1, npar = 0, i;
+ struct token *ct = 0;
+ int read_from_fifo = 0;
+ long begin_line = ls->line;
+
+#define unravel(ls) (read_from_fifo = 0, !((tfi && tfi->art < tfi->nt \
+ && (read_from_fifo = 1) && (ct = tfi->t + (tfi->art ++))) \
+ || ((!tfi || penury) && !next_token(ls) && (ct = (ls)->ctok))))
+
+ /*
+ * collect_arguments() is assumed to setup correctly atl
+ * (this is not elegant, but it works)
+ */
+ for (i = 0; i < narg; i ++) atl[i].art = atl[i].nt = 0;
+ if (vaarg) atl[narg].art = atl[narg].nt = 0;
+ *wr = 0;
+ while (!unravel(ls)) {
+ if (!read_from_fifo && ct->type == NEWLINE) ls->ltwnl = 1;
+ if (ttWHI(ct->type)) {
+ *wr = 1;
+ continue;
+ }
+ if (ct->type == LPAR) {
+ npar = 1;
+ }
+ break;
+ }
+ if (!npar) {
+ if (ct == ls->ctok) return 1;
+ if (read_from_fifo) return 2;
+ return 3;
+ }
+ if (!read_from_fifo && ct == ls->ctok) ls->ltwnl = 0;
+ i = 0;
+ if ((narg + vaarg) == 0) {
+ while(!unravel(ls)) {
+ if (ttWHI(ct->type)) continue;
+ if (ct->type == RPAR) goto harvested;
+ npar = 1;
+ goto too_many_args;
+ }
+ }
+ while (!unravel(ls)) {
+ struct token t;
+
+ if (ct->type == LPAR) npar ++;
+ else if (ct->type == RPAR && (-- npar) == 0) {
+ if (atl[i].nt != 0
+ && ttMWS(atl[i].t[atl[i].nt - 1].type))
+ atl[i].nt --;
+ i ++;
+ /*
+ * C99 standard states that at least one argument
+ * should be present for the ... part; to relax
+ * this behaviour, change 'narg + vaarg' to 'narg'.
+ */
+ if (i < (narg + vaarg)) {
+ error(begin_line, "not enough arguments "
+ "to macro");
+#ifdef HAVE_MISRA
+ misra_neu(94,19,8,0);
+#endif
+ return 4;
+ }
+ if (i > narg) {
+ if (!(ls->flags & MACRO_VAARG) || !vaarg)
+ goto too_many_args;
+ }
+ goto harvested;
+ } else if (ct->type == COMMA && npar <= 1 && i < narg) {
+ if (atl[i].nt != 0
+ && ttMWS(atl[i].t[atl[i].nt - 1].type))
+ atl[i].nt --;
+ if (++ i == narg) {
+ if (!(ls->flags & MACRO_VAARG) || !vaarg)
+ goto too_many_args;
+ }
+ if (i > 30000) goto too_many_args;
+ ltwws = 1;
+ continue;
+ } else if (ltwws && ttWHI(ct->type)) continue;
+
+ t.type = ct->type;
+ if (!read_from_fifo) t.line = ls->line; else t.line = ct->line;
+ /*
+ * Stringification applies only on macro arguments;
+ * so we handle here OPT_NONE.
+ * OPT_NONE is kept, but does not count as whitespace,
+ * and merges with other whitespace to give a fully
+ * qualified NONE token. Two OPT_NONE tokens merge.
+ * Initial and final OPT_NONE are discarded (initial
+ * is already done, as OPT_NONE is matched by ttWHI).
+ */
+
+ if (ttWHI(t.type)) {
+ if (t.type != OPT_NONE) {
+ t.type = NONE;
+ ltwws = 1;
+ }
+ if (atl[i].nt > 0
+ && atl[i].t[atl[i].nt - 1].type == OPT_NONE)
+ atl[i].nt --;
+ } else ltwws = 0;
+ if (S_TOKEN(t.type)) {
+ t.name = ct->name;
+ if (ct == (ls)->ctok) {
+ t.name = sdup(t.name);
+ throw_away(ls->gf, t.name);
+ }
+ }
+ aol(atl[i].t, atl[i].nt, t, TOKEN_LIST_MEMG);
+ }
+ error(begin_line, "unfinished macro call");
+ return 4;
+too_many_args:
+ error(begin_line, "too many arguments to macro");
+ while (npar && !unravel(ls)) {
+ if (ct->type == LPAR) npar ++;
+ else if (ct->type == RPAR) npar --;
+ }
+ return 4;
+harvested:
+ if (i > 127 && (ls->flags & WARN_STANDARD))
+ warning(begin_line, "macro call with %d arguments (ISO "
+ "specifies 127 max)", i);
+ return 0;
+#undef unravel
+}
+
+/*
+ * concat_token() is called when the ## operator is used. It uses
+ * the struct lexer_state dsharp_lexer to parse the result of the
+ * concatenation.
+ *
+ * Law enforcement: if the whole string does not produce a valid
+ * token, report an error. This also applies if only the beginning
+ * of the string gives a statement. For instance, '( ## )' will
+ * produce an error, since '()' is not a valid C token. Other
+ * preprocessors would ignore the ## operator in such instance.
+ */
+struct lexer_state dsharp_lexer;
+
+static inline int concat_token(struct token *t1, struct token *t2)
+{
+ char *n1 = token_name(t1), *n2 = token_name(t2);
+ size_t l1 = strlen(n1), l2 = strlen(n2);
+ unsigned char *x = getmem(l1 + l2 + 1);
+ int r;
+
+ mmv(x, n1, l1);
+ mmv(x + l1, n2, l2);
+ x[l1 + l2] = 0;
+ dsharp_lexer.input = 0;
+ dsharp_lexer.input_string = x;
+ dsharp_lexer.pbuf = 0;
+ dsharp_lexer.ebuf = l1 + l2;
+ dsharp_lexer.discard = 1;
+ dsharp_lexer.flags = DEFAULT_LEXER_FLAGS;
+ dsharp_lexer.pending_token = 0;
+ r = next_token(&dsharp_lexer);
+ freemem(x);
+ return (r == 1 || dsharp_lexer.pbuf < (l1 + l2)
+ || dsharp_lexer.pending_token
+ || (dsharp_lexer.pbuf == (l1 + l2) && !dsharp_lexer.discard));
+}
+
+#ifdef PRAGMA_TOKENIZE
+/*
+ * tokenize_string() takes a string as input, and split it into tokens,
+ * reassembling the tokens into a single compressed string generated by
+ * compress_token_list(); this function is used for _Pragma processing.
+ */
+struct lexer_state tokenize_lexer;
+
+static char *tokenize_string(struct lexer_state *ls, char *buf)
+{
+ struct token_fifo tf;
+ size_t bl = strlen(buf);
+ int r;
+
+ tokenize_lexer.input = 0;
+ tokenize_lexer.input_string = (unsigned char *)buf;
+ tokenize_lexer.pbuf = 0;
+ tokenize_lexer.ebuf = bl;
+ tokenize_lexer.discard = 1;
+ tokenize_lexer.flags = ls->flags | LEXER;
+ tokenize_lexer.pending_token = 0;
+ tf.art = tf.nt = 0;
+ while (!(r = next_token(&tokenize_lexer))) {
+ struct token t, *ct = tokenize_lexer.ctok;
+
+ if (ttWHI(ct->type)) continue;
+ t = *ct;
+ if (S_TOKEN(t.type)) t.name = sdup(t.name);
+ aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG);
+ }
+ if (tokenize_lexer.pbuf < bl) goto tokenize_error;
+ return (char *)((compress_token_list(&tf)).t);
+
+tokenize_error:
+ if (tf.nt) {
+ for (tf.art = 0; tf.art < tf.nt; tf.art ++)
+ if (S_TOKEN(tf.t[tf.art].type))
+ freemem(tf.t[tf.art].name);
+ freemem(tf.t);
+ }
+ return 0;
+}
+#endif
+
+/*
+ * stringify_string() has a self-explanatory name. It is called when
+ * the # operator is used in a macro and a string constant must be
+ * stringified.
+ */
+static inline char *stringify_string(char *x)
+{
+ size_t l;
+ int i, inside_str = 0, inside_cc = 0, must_quote, has_quoted = 0;
+ char *y, *d;
+
+ for (i = 0; i < 2; i ++) {
+ if (i) d[0] = '"';
+ for (l = 1, y = x; *y; y ++, l ++) {
+ must_quote = 0;
+ if (inside_cc) {
+ if (*y == '\\') {
+ must_quote = 1;
+ has_quoted = 1;
+ } else if (!has_quoted && *y == '\'')
+ inside_cc = 0;
+ } else if (inside_str) {
+ if (*y == '"' || *y == '\\') must_quote = 1;
+ if (*y == '\\') has_quoted = 1;
+ else if (!has_quoted && *y == '"')
+ inside_str = 0;
+ } else if (*y == '"') {
+ inside_str = 1;
+ must_quote = 1;
+ } else if (*y == '\'') {
+ inside_cc = 1;
+ }
+ if (must_quote) {
+ if (i) d[l] = '\\';
+ l ++;
+ }
+ if (i) d[l] = *y;
+ }
+ if (!i) d = getmem(l + 2);
+ if (i) {
+ d[l] = '"';
+ d[l + 1] = 0;
+ }
+ }
+ return d;
+}
+
+/*
+ * stringify() produces a constant string, result of the # operator
+ * on a list of tokens.
+ */
+static char *stringify(struct token_fifo *tf)
+{
+ size_t tlen;
+ size_t i;
+ char *x, *y;
+
+ for (tlen = 0, i = 0; i < tf->nt; i ++)
+ if (tf->t[i].type < CPPERR && tf->t[i].type != OPT_NONE)
+ tlen += strlen(token_name(tf->t + i));
+ if (tlen == 0) return sdup("\"\"");
+ x = getmem(tlen + 1);
+ for (tlen = 0, i = 0; i < tf->nt; i ++) {
+ if (tf->t[i].type >= CPPERR || tf->t[i].type == OPT_NONE)
+ continue;
+ strcpy(x + tlen, token_name(tf->t + i));
+ tlen += strlen(token_name(tf->t + i));
+ }
+ /* no need to add a trailing 0: strcpy() did that (and the string
+ is not empty) */
+ y = stringify_string(x);
+ freemem(x);
+ return y;
+}
+
+/*
+ * Two strings evaluated at initialization time, to handle the __TIME__
+ * and __DATE__ special macros.
+ *
+ * C99 specifies that these macros should remain constant throughout
+ * the whole preprocessing.
+ */
+char compile_time[12], compile_date[24], compile_adate[16];
+
+/*
+ * substitute_macro() performs the macro substitution. It is called when
+ * an identifier recognized as a macro name has been found; this function
+ * tries to collect the arguments (if needed), applies # and ## operators
+ * and perform recursive and nested macro expansions.
+ *
+ * In the substitution of a macro, we remove all newlines that were in the
+ * arguments. This might confuse error reporting (which could report
+ * erroneous line numbers) or have worse effect is the preprocessor is
+ * used for another language pickier than C. Since the interface between
+ * the preprocessor and the compiler is not fully specified, I believe
+ * that this is no violation of the standard. Comments welcome.
+ *
+ * We take tokens from tfi. If tfi has no more tokens to give: we may
+ * take some tokens from ls to complete a call (fetch arguments) if
+ * and only if penury is non zero.
+ */
+int substitute_macro(struct lexer_state *ls, struct macro *m,
+ struct token_fifo *tfi, int penury, int reject_nested, long l)
+{
+ struct token_fifo *atl, etl;
+ struct token t, *ct;
+ int i, save_nest = m->nest;
+ size_t save_art, save_tfi, etl_limit;
+ int ltwds, ntwds, ltwws;
+ int pragma_op = 0;
+
+ /*
+ * Reject the replacement, if we are already inside the macro.
+ */
+ if (m->nest > reject_nested) {
+ t.type = NAME;
+ t.line = ls->line;
+ t.name = m->name;
+ print_token(ls, &t, 0);
+ return 0;
+ }
+#ifdef HAVE_MISRA
+ if (!strcmp(m->name,"offsetof")) misra_neu(120,20,6,-1);
+ if (!strcmp(m->name,"setjmp")) misra_neu(122,20,7,-1);
+#endif
+ /*
+ * put a separation from preceeding tokens
+ */
+ print_space(ls);
+
+ /*
+ * Check if the macro is a special one.
+ */
+ if ((i = check_special_macro(m->name)) >= MAC_SPECIAL) {
+ /* we have a special macro */
+ switch (i) {
+ char buf[30], *bbuf, *cfn;
+
+ case MAC_LINE:
+ t.type = NUMBER;
+ t.line = l;
+ sprintf(buf, "%ld", l);
+ t.name = buf;
+ print_space(ls);
+ print_token(ls, &t, 0);
+ break;
+ case MAC_FILE:
+ t.type = STRING;
+ t.line = l;
+ cfn = current_long_filename ?
+ current_long_filename : current_filename;
+ bbuf = getmem(2 * strlen(cfn) + 3);
+ {
+ char *c, *d;
+ int lcwb = 0;
+
+ bbuf[0] = '"';
+ for (c = cfn, d = bbuf + 1; *c; c ++) {
+ if (*c == '\\') {
+ if (lcwb) continue;
+ *(d ++) = '\\';
+ lcwb = 1;
+ } else lcwb = 0;
+ *(d ++) = *c;
+ }
+ *(d ++) = '"';
+ *(d ++) = 0;
+ }
+ t.name = bbuf;
+ print_space(ls);
+ print_token(ls, &t, 0);
+ freemem(bbuf);
+ break;
+ case MAC_DATE:
+ t.type = STRING;
+ t.line = l;
+ t.name = compile_date;
+ print_space(ls);
+ print_token(ls, &t, 0);
+ break;
+ case MAC_ADATE:
+ t.type = STRING;
+ t.line = l;
+ t.name = compile_adate;
+ print_space(ls);
+ print_token(ls, &t, 0);
+ break;
+ case MAC_TIME:
+ t.type = STRING;
+ t.line = l;
+ t.name = compile_time;
+ print_space(ls);
+ print_token(ls, &t, 0);
+ break;
+ case MAC_STDC:
+ t.type = NUMBER;
+ t.line = l;
+ t.name = "1";
+ print_space(ls);
+ print_token(ls, &t, 0);
+ break;
+ case MAC_PRAGMA:
+ if (reject_nested > 0) {
+ /* do not replace _Pragma() unless toplevel */
+ t.type = NAME;
+ t.line = ls->line;
+ t.name = m->name;
+ print_token(ls, &t, 0);
+ return 0;
+ }
+ pragma_op = 1;
+ goto collect_args;
+#ifdef AUDIT
+ default:
+ ouch("unbekanntes fliegendes macro");
+#endif
+ }
+ return 0;
+ }
+
+ /*
+ * If the macro has arguments, collect them.
+ */
+collect_args:
+ if (m->narg >= 0) {
+ unsigned long save_flags = ls->flags;
+ int wr = 0;
+
+ ls->flags |= LEXER;
+ if (m->narg > 0 || m->vaarg)
+ atl = getmem((m->narg + m->vaarg)
+ * sizeof(struct token_fifo));
+ switch (collect_arguments(ls, tfi, penury, atl,
+ m->narg, m->vaarg, &wr)) {
+ case 1:
+ /* the macro expected arguments, but we did not
+ find any; the last read token should be read
+ again. */
+ ls->flags = save_flags | READ_AGAIN;
+ goto no_argument_next;
+ case 2:
+ tfi->art --;
+ /* fall through */
+ case 3:
+ ls->flags = save_flags;
+ no_argument_next:
+ t.type = NAME;
+ t.line = l;
+ t.name = m->name;
+ print_token(ls, &t, 0);
+ if (wr) {
+ t.type = NONE;
+ t.line = l;
+#ifdef SEMPER_FIDELIS
+ t.name = " ";
+#endif
+ print_token(ls, &t, 0);
+ goto exit_macro_2;
+ }
+ goto exit_macro_1;
+ case 4:
+ ls->flags = save_flags;
+ return 1;
+ }
+ ls->flags = save_flags;
+ }
+
+ /*
+ * If the macro is _Pragma, and we got here, then we have
+ * exactly one argument. We check it, unstringize it, and
+ * emit a PRAGMA token.
+ */
+ if (pragma_op) {
+ char *pn;
+
+ if (atl[0].nt != 1 || atl[0].t[0].type != STRING) {
+ error(ls->line, "invalid argument to _Pragma");
+ if (atl[0].nt) freemem(atl[0].t);
+ freemem(atl);
+ return 1;
+ }
+ pn = atl[0].t[0].name;
+ if ((pn[0] == '"' && pn[1] == '"') || (pn[0] == 'L'
+ && pn[1] == '"' && pn[2] == '"')) {
+ /* void pragma -- just ignore it */
+ freemem(atl[0].t);
+ freemem(atl);
+ return 0;
+ }
+ if (ls->flags & TEXT_OUTPUT) {
+#ifdef PRAGMA_DUMP
+ /*
+ * This code works because we actually evaluate arguments in a
+ * lazy way: we scan a macro argument only if it appears in the
+ * output, and exactly as many times as it appears. Therefore,
+ * _Pragma() will get evaluated just like they should.
+ */
+ char *c = atl[0].t[0].name, *d;
+
+ for (d = "\n#pragma "; *d; d ++) put_char(ls, *d);
+ d = (*c == 'L') ? c + 2 : c + 1;
+ for (; *d != '"'; d ++) {
+ if (*d == '\\' && (*(d + 1) == '\\'
+ || *(d + 1) == '"')) {
+ d ++;
+ }
+ put_char(ls, *d);
+ }
+ put_char(ls, '\n');
+ ls->oline = ls->line;
+ enter_file(ls, ls->flags);
+#else
+ if (ls->flags & WARN_PRAGMA)
+ warning(ls->line,
+ "_Pragma() ignored and not dumped");
+#endif
+ } else if (ls->flags & HANDLE_PRAGMA) {
+ char *c = atl[0].t[0].name, *d, *buf;
+ struct token t;
+
+ /* a wide string is a string */
+ if (*c == 'L') c ++;
+ c ++;
+ for (buf = d = getmem(strlen(c)); *c != '"'; c ++) {
+ if (*c == '\\' && (*(c + 1) == '\\'
+ || *(c + 1) == '"')) {
+ *(d ++) = *(++ c);
+ } else *(d ++) = *c;
+ }
+ *d = 0;
+ t.type = PRAGMA;
+ t.line = ls->line;
+#ifdef PRAGMA_TOKENIZE
+ t.name = tokenize_string(ls, buf);
+ freemem(buf);
+ buf = t.name;
+ if (!buf) {
+ freemem(atl[0].t);
+ freemem(atl);
+ return 1;
+ }
+#else
+ t.name = buf;
+#endif
+ aol(ls->toplevel_of->t, ls->toplevel_of->nt,
+ t, TOKEN_LIST_MEMG);
+ throw_away(ls->gf, buf);
+ }
+ freemem(atl[0].t);
+ freemem(atl);
+ return 0;
+ }
+
+ /*
+ * Now we expand and replace the arguments in the macro; we
+ * also handle '#' and '##'. If we find an argument, that has
+ * to be replaced, we expand it in its own token list, then paste
+ * it. Tricky point: when we paste an argument, we must scan
+ * again the resulting list for further replacements. This
+ * implies problems with regards to nesting self-referencing
+ * macros.
+ *
+ * We do then YAUH (yet another ugly hack): if a macro is replaced,
+ * and nested replacement exhibit the same macro, we mark it with
+ * a negative line number. All produced negative line numbers
+ * must be cleaned in the end.
+ */
+
+#define ZAP_LINE(t) do { \
+ if ((t).type == NAME) { \
+ struct macro *zlm = getHT(macros, &((t).name)); \
+ if (zlm && zlm->nest > reject_nested) \
+ (t).line = -1 - (t).line; \
+ } \
+ } while (0)
+
+#ifdef LOW_MEM
+ save_art = m->cval.rp;
+ m->cval.rp = 0;
+#else
+ save_art = m->val.art;
+ m->val.art = 0;
+#endif
+ etl.art = etl.nt = 0;
+ m->nest = reject_nested + 1;
+ ltwds = ntwds = 0;
+#ifdef LOW_MEM
+ while (m->cval.rp < m->cval.length) {
+#else
+ while (m->val.art < m->val.nt) {
+#endif
+ size_t next, z;
+#ifdef LOW_MEM
+ struct token uu;
+
+ ct = &uu;
+ ct->line = 1;
+ t.type = ct->type = m->cval.t[m->cval.rp ++];
+ if (ct->type == MACROARG) {
+ ct->line = m->cval.t[m->cval.rp ++];
+ } else if (S_TOKEN(ct->type)) {
+ t.name = ct->name = (char *)(m->cval.t + m->cval.rp);
+ m->cval.rp += 1 + strlen(ct->name);
+ }
+#ifdef SEMPER_FIDELIS
+ else if (ct->type == OPT_NONE) {
+ t.type = ct->type = NONE;
+ t.name = ct->name = " ";
+ }
+#endif
+ t.line = ls->line;
+ next = m->cval.rp;
+ if ((next < m->cval.length && (m->cval.t[z = next] == DSHARP
+ || m->cval.t[z = next] == DIG_DSHARP))
+ || ((next + 1) < m->cval.length
+ && ttWHI(m->cval.t[next])
+ && (m->cval.t[z = next + 1] == DSHARP
+ || m->cval.t[z = next + 1] == DIG_DSHARP))) {
+ ntwds = 1;
+ m->cval.rp = z;
+ } else ntwds = 0;
+#else
+ ct = m->val.t + (m->val.art ++);
+ next = m->val.art;
+ t.type = ct->type;
+ t.line = ls->line;
+#ifdef SEMPER_FIDELIS
+ if (t.type == OPT_NONE) {
+ t.type = NONE;
+ t.name = " ";
+ } else
+#else
+ t.name = ct->name;
+#endif
+ if ((next < m->val.nt && (m->val.t[z = next].type == DSHARP
+ || m->val.t[z = next].type == DIG_DSHARP))
+ || ((next + 1) < m->val.nt
+ && ttWHI(m->val.t[next].type)
+ && (m->val.t[z = next + 1].type == DSHARP
+ || m->val.t[z = next + 1].type == DIG_DSHARP))) {
+ ntwds = 1;
+ m->val.art = z;
+ } else ntwds = 0;
+#endif
+ if (ct->type == MACROARG) {
+ z = ct->line; /* the argument number is there */
+ if (ltwds && atl[z].nt != 0 && etl.nt) {
+ if (concat_token(etl.t + (-- etl.nt),
+ atl[z].t)) {
+ error(ls->line, "operator '##' "
+ "produced the invalid token "
+ "'%s%s'",
+ token_name(etl.t + etl.nt),
+ token_name(atl[z].t));
+ m->nest = save_nest;
+#ifdef LOW_MEM
+ m->cval.rp = save_art;
+#else
+ m->val.art = save_art;
+#endif
+ return 1;
+ }
+ if (etl.nt == 0) freemem(etl.t);
+ else if (!ttWHI(etl.t[etl.nt - 1].type)) {
+ t.type = OPT_NONE;
+ t.line = ls->line;
+ aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+ }
+ t.type = dsharp_lexer.ctok->type;
+ t.line = ls->line;
+ if (S_TOKEN(t.type)) {
+ t.name = sdup(dsharp_lexer.ctok->name);
+ throw_away(ls->gf, t.name);
+ }
+ ZAP_LINE(t);
+ aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+ atl[z].art = 1;
+ } else atl[z].art = 0;
+ if (atl[z].art < atl[z].nt && (!etl.nt
+ || !ttWHI(etl.t[etl.nt - 1].type))) {
+ t.type = OPT_NONE;
+ t.line = ls->line;
+ aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+ }
+ if (ltwds || ntwds) {
+ while (atl[z].art < atl[z].nt) {
+ t = atl[z].t[atl[z].art ++];
+ t.line = ls->line;
+ ZAP_LINE(t);
+ aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+ }
+ } else {
+ struct token_fifo *save_tf;
+ unsigned long save_flags;
+ int ret = 0;
+
+ atl[z].art = 0;
+ save_tf = ls->output_fifo;
+ ls->output_fifo = &etl;
+ save_flags = ls->flags;
+ ls->flags |= LEXER;
+ while (atl[z].art < atl[z].nt) {
+ struct macro *nm;
+ struct token *cct;
+
+ cct = atl[z].t + (atl[z].art ++);
+ if (cct->type == NAME
+ && cct->line >= 0
+ && (nm = getHT(macros,
+ &(cct->name)))
+ && nm->nest <=
+ (reject_nested + 1)) {
+ ret |= substitute_macro(ls,
+ nm, atl + z, 0,
+ reject_nested + 1, l);
+ continue;
+ }
+ ZAP_LINE(t);
+ aol(etl.t, etl.nt, *cct,
+ TOKEN_LIST_MEMG);
+ }
+ ls->output_fifo = save_tf;
+ ls->flags = save_flags;
+ if (ret) {
+ m->nest = save_nest;
+#ifdef LOW_MEM
+ m->cval.rp = save_art;
+#else
+ m->val.art = save_art;
+#endif
+ return ret;
+ }
+ }
+ if (!ntwds && (!etl.nt
+ || !ttWHI(etl.t[etl.nt - 1].type))) {
+ t.type = OPT_NONE;
+ t.line = ls->line;
+ aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+ }
+ ltwds = 0;
+ continue;
+ }
+ /*
+ * This code is definitely cursed.
+ *
+ * For the extremely brave reader who tries to understand
+ * what is happening: ltwds is a flag meaning "last token
+ * was double-sharp" and ntwds means "next token will be
+ * double-shar". The tokens are from the macro definition,
+ * and scanned from left to right. Arguments that are
+ * not implied into a #/## construction are macro-expanded
+ * seperately, then included into the token stream.
+ */
+ if (ct->type == DSHARP || ct->type == DIG_DSHARP) {
+ if (ltwds) {
+ error(ls->line, "quad sharp");
+ m->nest = save_nest;
+#ifdef LOW_MEM
+ m->cval.rp = save_art;
+#else
+ m->val.art = save_art;
+#endif
+ return 1;
+ }
+#ifdef LOW_MEM
+ if (m->cval.rp < m->cval.length
+ && ttMWS(m->cval.t[m->cval.rp]))
+ m->cval.rp ++;
+#else
+ if (m->val.art < m->val.nt
+ && ttMWS(m->val.t[m->val.art].type))
+ m->val.art ++;
+#endif
+ ltwds = 1;
+ continue;
+ } else if (ltwds && etl.nt != 0) {
+ if (concat_token(etl.t + (-- etl.nt), ct)) {
+ error(ls->line, "operator '##' produced "
+ "the invalid token '%s%s'",
+ token_name(etl.t + etl.nt),
+ token_name(ct));
+ m->nest = save_nest;
+#ifdef LOW_MEM
+ m->cval.rp = save_art;
+#else
+ m->val.art = save_art;
+#endif
+ return 1;
+ }
+ if (etl.nt == 0) freemem(etl.t);
+ t.type = dsharp_lexer.ctok->type;
+ t.line = ls->line;
+ if (S_TOKEN(t.type)) {
+ t.name = sdup(dsharp_lexer.ctok->name);
+ throw_away(ls->gf, t.name);
+ }
+ ct = &t;
+ }
+ ltwds = 0;
+#ifdef LOW_MEM
+ if ((ct->type == SHARP || ct->type == DIG_SHARP)
+ && next < m->cval.length
+ && (m->cval.t[next] == MACROARG
+ || (ttMWS(m->cval.t[next])
+ && (next + 1) < m->cval.length
+ && m->cval.t[next + 1] == MACROARG))) {
+#else
+ if ((ct->type == SHARP || ct->type == DIG_SHARP)
+ && next < m->val.nt
+ && (m->val.t[next].type == MACROARG
+ || (ttMWS(m->val.t[next].type)
+ && (next + 1) < m->val.nt
+ && m->val.t[next + 1].type == MACROARG))) {
+#endif
+ /*
+ * We have a # operator followed by (an optional
+ * whitespace and) a macro argument; this means
+ * stringification. So be it.
+ */
+#ifdef LOW_MEM
+ if (ttMWS(m->cval.t[next])) m->cval.rp ++;
+#else
+ if (ttMWS(m->val.t[next].type)) m->val.art ++;
+#endif
+ t.type = STRING;
+#ifdef LOW_MEM
+ m->cval.rp ++;
+ t.name = stringify(atl +
+ (size_t)(m->cval.t[m->cval.rp ++]));
+#else
+ t.name = stringify(atl +
+ (size_t)(m->val.t[m->val.art ++].line));
+#endif
+ throw_away(ls->gf, t.name);
+ ct = &t;
+ /*
+ * There is no need for extra spaces here.
+ */
+ }
+ t = *ct;
+ ZAP_LINE(t);
+ aol(etl.t, etl.nt, t, TOKEN_LIST_MEMG);
+ }
+#ifdef LOW_MEM
+ m->cval.rp = save_art;
+#else
+ m->val.art = save_art;
+#endif
+
+
+ /*
+ * Now etl contains the expanded macro, to be parsed again for
+ * further expansions -- much easier, since '#' and '##' have
+ * already been handled.
+ * However, we might need some input from tfi. So, we paste
+ * the contents of tfi after etl, and we put back what was
+ * not used.
+ *
+ * Some adjacent spaces are merged; only unique NONE, or sequences
+ * OPT_NONE NONE are emitted.
+ */
+ etl_limit = etl.nt;
+ if (tfi) {
+ save_tfi = tfi->art;
+ while (tfi->art < tfi->nt) aol(etl.t, etl.nt,
+ tfi->t[tfi->art ++], TOKEN_LIST_MEMG);
+ }
+ ltwws = 0;
+ while (etl.art < etl_limit) {
+ struct macro *nm;
+
+ ct = etl.t + (etl.art ++);
+ if (ct->type == NAME && ct->line >= 0
+ && (nm = getHT(macros, &(ct->name)))) {
+ if (substitute_macro(ls, nm, &etl,
+ penury, reject_nested, l)) {
+ m->nest = save_nest;
+ return 1;
+ }
+ ltwws = 0;
+ continue;
+ }
+ if (ttMWS(ct->type)) {
+ if (ltwws == 1) {
+ if (ct->type == OPT_NONE) continue;
+ ltwws = 2;
+ } else if (ltwws == 2) continue;
+ else if (ct->type == OPT_NONE) ltwws = 1;
+ else ltwws = 2;
+ } else ltwws = 0;
+ if (ct->line >= 0) ct->line = l;
+ print_token(ls, ct, reject_nested ? 0 : l);
+ }
+ if (etl.nt) freemem(etl.t);
+ if (tfi) {
+ tfi->art = save_tfi + (etl.art - etl_limit);
+ }
+
+exit_macro_1:
+ print_space(ls);
+exit_macro_2:
+ for (i = 0; i < m->narg; i ++) if (atl[i].nt) freemem(atl[i].t);
+ if (m->narg > 0) freemem(atl);
+ m->nest = save_nest;
+ return 0;
+}
+
+/*
+ * print already defined macros
+ */
+void print_defines(void)
+{
+ scanHT(macros, print_macro);
+}
+
+/*
+ * define_macro() defines a new macro, whom definition is given in
+ * the command-line syntax: macro=def
+ * The '=def' part is optional.
+ *
+ * It returns non-zero on error.
+ */
+int define_macro(struct lexer_state *ls, char *def)
+{
+ char *c = sdup(def), *d;
+ int with_def = 0;
+ int ret = 0;
+
+ for (d = c; *d && *d != '='; d ++);
+ if (*d) {
+ *d = ' ';
+ with_def = 1;
+ }
+ if (with_def) {
+ struct lexer_state lls;
+ size_t n = strlen(c) + 1;
+
+ if (c == d) {
+ error(-1, "void macro name");
+ ret = 1;
+ } else {
+ *(c + n - 1) = '\n';
+ init_buf_lexer_state(&lls, 0);
+ lls.flags = ls->flags | LEXER;
+ lls.input = 0;
+ lls.input_string = (unsigned char *)c;
+ lls.pbuf = 0;
+ lls.ebuf = n;
+ lls.line = -1;
+ ret = handle_define(&lls);
+ free_lexer_state(&lls);
+ }
+ } else {
+ struct macro *m;
+
+ if (!*c) {
+ error(-1, "void macro name");
+ ret = 1;
+ } else if ((m = getHT(macros, &c))
+#ifdef LOW_MEM
+ && (m->cval.length != 3
+ || m->cval.t[0] != NUMBER
+ || strcmp((char *)(m->cval.t + 1), "1"))) {
+#else
+ && (m->val.nt != 1
+ || m->val.t[0].type != NUMBER
+ || strcmp(m->val.t[0].name, "1"))) {
+#endif
+ error(-1, "macro %s already defined", c);
+ ret = 1;
+ } else {
+#ifndef LOW_MEM
+ struct token t;
+#endif
+
+ m = new_macro();
+ m->name = sdup(c);
+#ifdef LOW_MEM
+ m->cval.length = 3;
+ m->cval.t = getmem(3);
+ m->cval.t[0] = NUMBER;
+ m->cval.t[1] = '1';
+ m->cval.t[2] = 0;
+#else
+ t.type = NUMBER;
+ t.name = sdup("1");
+ aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG);
+#endif
+ putHT(macros, m);
+ }
+ }
+ freemem(c);
+ return ret;
+}
+
+/*
+ * undef_macro() undefines the macro whom name is given as "def";
+ * it is not an error to try to undef a macro that does not exist.
+ *
+ * It returns non-zero on error (undefinition of a special macro,
+ * void macro name).
+ */
+int undef_macro(struct lexer_state *ls, char *def)
+{
+ char *c = def;
+
+ if (!*c) {
+ error(-1, "void macro name");
+ return 1;
+ }
+ if (getHT(macros, &c)) {
+ if (check_special_macro(c)) {
+ error(-1, "trying to undef special macro %s", c);
+ return 1;
+ } else delHT(macros, &c);
+ }
+ return 0;
+}
+
+/*
+ * We saw a #ifdef directive. Parse the line.
+ * return value: 1 if the macro is defined, 0 if it is not, -1 on error
+ */
+int handle_ifdef(struct lexer_state *ls)
+{
+ while (!next_token(ls)) {
+ int tgd = 1;
+
+ if (ls->ctok->type == NEWLINE) break;
+ if (ttMWS(ls->ctok->type)) continue;
+ if (ls->ctok->type == NAME) {
+ int x = (getHT(macros, &(ls->ctok->name)) != 0);
+ while (!next_token(ls) && ls->ctok->type != NEWLINE)
+ if (tgd && !ttWHI(ls->ctok->type)
+ && (ls->flags & WARN_STANDARD)) {
+ warning(ls->line, "trailing garbage "
+ "in #ifdef");
+ tgd = 0;
+ }
+ return x;
+ }
+ error(ls->line, "illegal macro name for #ifdef");
+ while (!next_token(ls) && ls->ctok->type != NEWLINE)
+ if (tgd && !ttWHI(ls->ctok->type)
+ && (ls->flags & WARN_STANDARD)) {
+ warning(ls->line, "trailing garbage in "
+ "#ifdef");
+ tgd = 0;
+ }
+ return -1;
+ }
+ error(ls->line, "unfinished #ifdef");
+ return -1;
+}
+
+/*
+ * for #undef
+ * return value: 1 on error, 0 on success. Undefining a macro that was
+ * already not defined is not an error.
+ */
+int handle_undef(struct lexer_state *ls)
+{
+ /*vb*/
+#ifdef HAVE_MISRA
+ if(nesting!=0) misra_neu(91,19,5,0);
+ misra_neu(92,19,6,0);
+#endif
+
+ while (!next_token(ls)) {
+ if (ls->ctok->type == NEWLINE) break;
+ if (ttMWS(ls->ctok->type)) continue;
+ if (ls->ctok->type == NAME) {
+ struct macro *m = getHT(macros, &(ls->ctok->name));
+ int tgd = 1;
+
+ if (m != 0) {
+ if (check_special_macro(ls->ctok->name)) {
+ error(ls->line, "trying to undef "
+ "special macro %s",
+ ls->ctok->name);
+ goto undef_error;
+ }
+ if (emit_defines)
+ fprintf(emit_output, "#undef %s\n",
+ m->name);
+ delHT(macros, &(ls->ctok->name));
+ }
+ while (!next_token(ls) && ls->ctok->type != NEWLINE)
+ if (tgd && !ttWHI(ls->ctok->type)
+ && (ls->flags & WARN_STANDARD)) {
+ warning(ls->line, "trailing garbage "
+ "in #undef");
+ tgd = 0;
+ }
+ return 0;
+ }
+ error(ls->line, "illegal macro name for #undef");
+ undef_error:
+ while (!next_token(ls) && ls->ctok->type != NEWLINE);
+ return 1;
+ }
+ error(ls->line, "unfinished #undef");
+ return 1;
+}
+
+/*
+ * for #ifndef
+ * return value: 0 if the macro is defined, 1 if it is not, -1 on error.
+ */
+int handle_ifndef(struct lexer_state *ls)
+{
+ while (!next_token(ls)) {
+ int tgd = 1;
+
+ if (ls->ctok->type == NEWLINE) break;
+ if (ttMWS(ls->ctok->type)) continue;
+ if (ls->ctok->type == NAME) {
+ int x = (getHT(macros, &(ls->ctok->name)) == 0);
+
+ while (!next_token(ls) && ls->ctok->type != NEWLINE)
+ if (tgd && !ttWHI(ls->ctok->type)
+ && (ls->flags & WARN_STANDARD)) {
+ warning(ls->line, "trailing garbage "
+ "in #ifndef");
+ tgd = 0;
+ }
+ if (protect_detect.state == 1) {
+ protect_detect.state = 2;
+ protect_detect.macro = sdup(ls->ctok->name);
+ }
+ return x;
+ }
+ error(ls->line, "illegal macro name for #ifndef");
+ while (!next_token(ls) && ls->ctok->type != NEWLINE)
+ if (tgd && !ttWHI(ls->ctok->type)
+ && (ls->flags & WARN_STANDARD)) {
+ warning(ls->line, "trailing garbage in "
+ "#ifndef");
+ tgd = 0;
+ }
+ return -1;
+ }
+ error(ls->line, "unfinished #ifndef");
+ return -1;
+}
+
+/*
+ * initialize the macro table
+ */
+void init_macros(void)
+{
+ if (macros) killHT(macros);
+ macros = newHT(128, cmp_struct, hash_struct, del_macro);
+ if (!no_special_macros) add_special_macros();
+}
+
+/*
+ * find a macro from its name
+ */
+struct macro *get_macro(char *name)
+{
+ return getHT(macros, &name);
+}
diff --git a/ucpp/mem.c b/ucpp/mem.c
new file mode 100755
index 0000000..db621d5
--- /dev/null
+++ b/ucpp/mem.c
@@ -0,0 +1,157 @@
+/*
+ * Memory manipulation routines
+ * (c) Thomas Pornin 1998, 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "mem.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef AUDIT
+void die(void)
+{
+ abort();
+}
+
+static void suicide(unsigned long e)
+{
+ fprintf(stderr, "ouch: Schrodinger's beef is not dead ! %lx\n", e);
+ die();
+}
+#else
+void die(void)
+{
+ exit(1);
+}
+#endif
+
+#if defined AUDIT || defined MEM_CHECK
+/*
+ * This function is equivalent to a malloc(), but will display an error
+ * message and exit if the wanted memory is not available
+ */
+void *getmem(size_t x)
+{
+ void *m;
+
+#ifdef AUDIT
+ m = malloc(x + 8);
+#else
+ m = malloc(x);
+#endif
+ if (m == 0) {
+ fprintf(stderr, "ouch: malloc() failed\n");
+ die();
+ }
+#ifdef AUDIT
+ *((unsigned long *)m) = 0xdeadbeefUL;
+ return (void *)(((char *)m) + 8);
+#else
+ return m;
+#endif
+}
+#endif
+
+/*
+ * This function is equivalent to a realloc(); if the realloc() call
+ * fails, it will try a malloc() and a memcpy(). If not enough memory is
+ * available, the program exits with an error message
+ */
+void *incmem(void *m, size_t x, size_t nx)
+{
+ void *nm;
+
+#ifdef AUDIT
+ m = (void *)(((char *)m) - 8);
+ if (*((unsigned long *)m) != 0xdeadbeefUL)
+ suicide(*((unsigned long *)m));
+ x += 8; nx += 8;
+#endif
+ if (!(nm = realloc(m, nx))) {
+ if (x > nx) x = nx;
+ nm = getmem(nx);
+ memcpy(nm, m, x);
+ /* free() and not freemem(), because of the Schrodinger beef */
+ free(m);
+ }
+#ifdef AUDIT
+ return (void *)(((char *)nm) + 8);
+#else
+ return nm;
+#endif
+}
+
+#ifdef AUDIT
+/*
+ * This function frees the given block
+ */
+void freemem(void *x)
+{
+#ifdef AUDIT
+ void *y = (void *)(((char *)x) - 8);
+
+ if ((*((unsigned long *)y)) != 0xdeadbeefUL)
+ suicide(*((unsigned long *)y));
+ *((unsigned long *)y) = 0xfeedbabeUL;
+ free(y);
+#else
+ free(x);
+#endif
+}
+#endif
+
+#ifdef AUDIT
+/*
+ * This function copies n bytes from src to dest
+ */
+void *mmv(void *dest, void *src, size_t n)
+{
+ return memcpy(dest, src, n);
+}
+
+/*
+ * This function copies n bytes from src to dest
+ */
+void *mmvwo(void *dest, void *src, size_t n)
+{
+ return memmove(dest, src, n);
+}
+#endif
+
+/*
+ * This function creates a new char * and fills it with a copy of src
+ */
+char *sdup(char *src)
+{
+ size_t n = 1 + strlen(src);
+ char *x = getmem(n);
+
+ mmv(x, src, n);
+ return x;
+}
diff --git a/ucpp/mem.h b/ucpp/mem.h
new file mode 100755
index 0000000..6d646b7
--- /dev/null
+++ b/ucpp/mem.h
@@ -0,0 +1,133 @@
+/*
+ * (c) Thomas Pornin 1998, 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef UCPP__MEM__
+#define UCPP__MEM__
+
+#include <stdlib.h>
+
+void die(void);
+void *incmem(void *, size_t, size_t);
+char *sdup(char *);
+
+#if defined AUDIT || defined MEM_CHECK
+void *getmem(size_t);
+#else
+#define getmem malloc
+#endif
+
+#ifdef AUDIT
+void freemem(void *);
+#else
+#define freemem free
+#endif
+
+#ifdef AUDIT
+void *mmv(void *, void *, size_t);
+void *mmvwo(void *, void *, size_t);
+#else
+#define mmv memcpy
+#define mmvwo memmove
+#endif
+
+/*
+ * this macro adds the object obj at the end of the array list, handling
+ * memory allocation when needed; ptr contains the number of elements in
+ * the array, and memg is the granularity of memory allocations (a power
+ * of 2 is recommanded, for optimization reasons)
+ *
+ * list and ptr may be updated, and thus need to be lvalues
+ */
+#define aol(list,ptr,obj,memg) do { \
+ if (((ptr) % (memg)) == 0) { \
+ if ((ptr) != 0) { \
+ (list) = incmem((list), (ptr) * sizeof(obj), \
+ ((ptr) + (memg)) * sizeof(obj)); \
+ } else { \
+ (list) = getmem((memg) * sizeof(obj)); \
+ } \
+ } \
+ (list)[(ptr) ++] = (obj); \
+ } while (0)
+
+/*
+ * bol() does the same as aol(), but adds the new item at the beginning
+ * of the list; beware, the computational cost is greater.
+ */
+#define bol(list,ptr,obj,memg) do { \
+ if (((ptr) % (memg)) == 0) { \
+ if ((ptr) != 0) { \
+ (list) = incmem((list), (ptr) * sizeof(obj), \
+ ((ptr) + (memg)) * sizeof(obj)); \
+ } else { \
+ (list) = getmem((memg) * sizeof(obj)); \
+ } \
+ } \
+ if ((ptr) != 0) \
+ mmvwo((list) + 1, (list), (ptr) * sizeof(obj)); \
+ (ptr) ++; \
+ (list)[0] = (obj); \
+ } while (0)
+
+/*
+ * mbol() does the same as bol(), but adds the new item at the given
+ * emplacement; bol() is equivalent to mbol with 0 as last argument.
+ */
+#define mbol(list,ptr,obj,memg,n) do { \
+ if (((ptr) % (memg)) == 0) { \
+ if ((ptr) != 0) { \
+ (list) = incmem((list), (ptr) * sizeof(obj), \
+ ((ptr) + (memg)) * sizeof(obj)); \
+ } else { \
+ (list) = getmem((memg) * sizeof(obj)); \
+ } \
+ } \
+ if ((ptr) > n) \
+ mmvwo((list) + n + 1, (list) + n, \
+ ((ptr) - n) * sizeof(obj)); \
+ (ptr) ++; \
+ (list)[n] = (obj); \
+ } while (0)
+
+/*
+ * this macro adds the object obj at the end of the array list, doubling
+ * the size of list when needed; as for aol(), ptr and list must be
+ * lvalues, and so must be llng
+ */
+
+#define wan(list,ptr,obj,llng) do { \
+ if ((ptr) == (llng)) { \
+ (llng) += (llng); \
+ (list) = incmem((list), (ptr) * sizeof(obj), \
+ (llng) * sizeof(obj)); \
+ } \
+ (list)[(ptr) ++] = (obj); \
+ } while (0)
+
+#endif
diff --git a/ucpp/sample.c b/ucpp/sample.c
new file mode 100755
index 0000000..7903184
--- /dev/null
+++ b/ucpp/sample.c
@@ -0,0 +1,107 @@
+/*
+ * Sample code showing how to use ucpp as an integrated lexer.
+ * This file is public domain.
+ */
+
+/*
+ * This is an example of how to use ucpp as a preprocessor and lexer
+ * into another project. The steps are those described in ucpp README
+ * file. To use this code, compile the ucpp source files with
+ * STAND_ALONE not defined, and link them with this code. The resulting
+ * binary will take a C source file as standard input, preprocess it,
+ * and output each non-whitespace token on stdout, with its numerical
+ * value (defined as an enum in cpp.h) and its contents. This code
+ * defines no system include path.
+ *
+ * This code supposes that the ucpp files are compiled with PRAGMA_TOKENIZE
+ * enabled (see the tune.h file).
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mem.h"
+#include "cpp.h"
+
+int main(int argc, char *argv[])
+{
+ int i, r;
+ struct lexer_state ls;
+
+ /* step 1 */
+ init_cpp();
+
+ /* step 2 */
+ no_special_macros = 0;
+ emit_defines = emit_assertions = 0;
+
+ /* step 3 -- with assertions */
+ init_tables(1);
+
+ /* step 4 -- no default include path */
+ init_include_path(0);
+
+ /* step 5 -- no need to reset the two emit_* variables set in 2 */
+ emit_dependencies = 0;
+
+ /* step 6 -- we work with stdin, this is not a real filename */
+ set_init_filename("[stdin]", 0);
+
+ /* step 7 -- we make sure that assertions are on, and pragma are
+ handled */
+ init_lexer_state(&ls);
+ init_lexer_mode(&ls);
+ ls.flags |= HANDLE_ASSERTIONS | HANDLE_PRAGMA | LINE_NUM;
+
+ /* step 8 -- input is from stdin */
+ ls.input = stdin;
+
+ /* step 9 -- we do not have any macro to define, but we add any
+ argument as an include path */
+ for (i = 1; i < argc; i ++) add_incpath(argv[i]);
+
+ /* step 10 -- we are a lexer and we want CONTEXT tokens */
+ enter_file(&ls, ls.flags);
+
+ /* read tokens until end-of-input is reached -- errors (non-zero
+ return values different from CPPERR_EOF) are ignored */
+ while ((r = lex(&ls)) < CPPERR_EOF) {
+ if (r) {
+ /* error condition -- no token was retrieved */
+ continue;
+ }
+ /* we print each token: its numerical value, and its
+ string content; if this is a PRAGMA token, the
+ string content is in fact a compressed token list,
+ that we uncompress and print. */
+ if (ls.ctok->type == PRAGMA) {
+ unsigned char *c = (unsigned char *)(ls.ctok->name);
+
+ printf("line %ld: <#pragma>\n", ls.line);
+ for (; *c; c ++) {
+ int t = *c;
+
+ if (STRING_TOKEN(t)) {
+ printf(" <%2d> ", t);
+ for (c ++; *c != PRAGMA_TOKEN_END;
+ c ++) putchar(*c);
+ putchar('\n');
+ } else {
+ printf(" <%2d> `%s'\n", t,
+ operators_name[t]);
+ }
+ }
+ } else if (ls.ctok->type == CONTEXT) {
+ printf("new context: file '%s', line %ld\n",
+ ls.ctok->name, ls.ctok->line);
+ } else if (ls.ctok->type == NEWLINE) {
+ printf("[newline]\n");
+ } else {
+ printf("line %ld: <%2d> `%s'\n", ls.ctok->line,
+ ls.ctok->type,
+ STRING_TOKEN(ls.ctok->type) ? ls.ctok->name
+ : operators_name[ls.ctok->type]);
+ }
+ }
+ return 0;
+}
diff --git a/ucpp/tune.h b/ucpp/tune.h
new file mode 100755
index 0000000..feb6275
--- /dev/null
+++ b/ucpp/tune.h
@@ -0,0 +1,308 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef UCPP__TUNE__
+#define UCPP__TUNE__
+
+/* ====================================================================== */
+/*
+ * Define LOW_MEM for low memory machines. It seems to improve performance
+ * on larger systems, so this is on by default.
+ */
+#define LOW_MEM
+
+/* ====================================================================== */
+/*
+ * Define AMIGA for systems using "drive letters" at the beginning of
+ * some paths; define MSDOS on systems with drive letters and using
+ * backslashes to seperate directory components. ATARI is same as MSDOS
+ * but does not use %VAR% notation and Turbo C specific code.
+ */
+/* #define AMIGA */
+/* #define MSDOS */
+/* #define ATARI */
+
+/* ====================================================================== */
+/*
+ * Buffering: there are two levels of buffering on input and output streams:
+ * the standard libc buffering (manageable with setbuf() and setvbuf())
+ * and some buffering provided by ucpp itself. The ucpp buffering uses
+ * two buffers, of size respectively INPUT_BUF_MEMG and OUTPUT_BUF_MEMG
+ * (as defined below).
+ * You can disable one or both of these bufferings by defining the macros
+ * NO_LIBC_BUF and NO_UCPP_BUF.
+ *
+ * Performance may vary, depending on the target architecture. On a
+ * Linux/Alpha workstation, use both bufferings (that means, disable none
+ * of them) for maximum performance. On a Minix-86 machine, disabling
+ * ucpp buffering saves some memory and does not seem to impact performance.
+ */
+/* #define NO_LIBC_BUF */
+/* #define NO_UCPP_BUF */
+
+/*
+ * On Unix stations, the system call mmap() might be used on input files.
+ * This option is a subclause of ucpp internal buffering. On one station,
+ * a 10% speed improvement was observe. Do not define this unless the
+ * host architecture has the following characteristics:
+ * -- Posix compliance
+ * -- Text files correspond one to one with memory representation
+ * If a file is not seekable or not mmapable, ucpp will revert to the
+ * standard fread() solution.
+ *
+ * This feature is still considered beta quality. On some systems where
+ * files can be bigger than memory address space (mainly, 32-bit systems
+ * with files bigger than 4 GB), this option makes ucpp fail to operate
+ * on those extremely large files.
+ */
+/* #define UCPP_MMAP */
+
+/* To protect the innocent. */
+#if defined(NO_UCPP_BUF) && defined(UCPP_MMAP)
+#undef UCPP_MMAP
+#endif
+
+/* ====================================================================== */
+/*
+ * Define this if you want ucpp to generate tokenized PRAGMA tokens;
+ * otherwise, it will generate raw string contents. This setting is
+ * irrelevant to the stand-alone version of ucpp.
+ */
+/*#define PRAGMA_TOKENIZE*/
+
+/*
+ * Define this to the special character that marks the end of tokens with
+ * a string value inside a tokenized PRAGMA token. The #pragma and _Pragma()
+ * directives which use this character will be a bit more difficult to
+ * decode (but ucpp will not mind). 0 cannot be used. '\n' is fine because
+ * it cannot appear inside a #pragma or _Pragma(), since newlines cannot be
+ * embedded inside tokens, neither directly nor by macro substitution and
+ * stringization. Besides, '\n' is portable.
+ */
+#define PRAGMA_TOKEN_END ((unsigned char)'\n')
+
+/*
+ * Define this if you want ucpp to include encountered #pragma directives
+ * in its output in non-lexer mode; _Pragma() are translated to equivalent
+ * #pragma directives.
+ */
+#define PRAGMA_DUMP
+
+/*
+ * According to may interpretation of the C99 standard, _Pragma() are
+ * evaluated wherever macro expansion could take place. However, Neil Booth,
+ * whose mother language is English (contrary to me) and who is well aware
+ * of the C99 standard (and especially the C preprocessor) told me that
+ * it was unclear whether _Pragma() are evaluated inside directives such
+ * as #if, #include and #line. If you want to disable the evaluation of
+ * _Pragma() inside such directives, define the following macro.
+ */
+/* #define NO_PRAGMA_IN_DIRECTIVE */
+
+/* ====================================================================== */
+/*
+ * Define INMACRO_FLAG to include two flags to the structure lexer_state,
+ * that tell whether tokens come from a macro-replacement, and count those
+ * macro-replacements.
+ */
+/* #define INMACRO_FLAG */
+
+/* ====================================================================== */
+/*
+ * Paths where files are looked for by default, when #include is used.
+ * Typical path is /usr/local/include and /usr/include, in that order.
+ * If you want to set up no path, define the macro to 0.
+ *
+ * For Linux, get gcc includes too, or you will miss things like stddef.h.
+ * The exact path varies much, depending on the distribution.
+ */
+#define STD_INCLUDE_PATH "/usr/local/include", "/usr/include", \
+ "/usr/lib/gcc-lib/alphaev56-unknown-linux-gnu/2.95.2/include"
+
+/* ====================================================================== */
+/*
+ * For the evaluation of #if expression. If NATIVE_UINTMAX is defined,
+ * the evaluation is done with NATIVE_UINTMAX as unsigned type, and
+ * NATIVE_INTMAX as signed type. If NATIVE_UINTMAX is not defined but
+ * SIMUL_UINTMAX is defined, evaluation is performed with a big integer
+ * type, whom size is twice the size of unsigned long. If neither is
+ * defined, ucpp will use uintmax_t and intmax_t if available, unsigned
+ * long and long otherwise.
+ * See the README file for details.
+ */
+/*
+ * uncomment these two lines if you want evaluation with a "long long" type
+#define NATIVE_UINTMAX unsigned long long
+#define NATIVE_INTMAX long long
+ */
+/*
+ * uncomment the following if you want evaluation with an emulated type
+ * built with two "unsigned long".
+#define SIMUL_UINTMAX
+ */
+/*
+ * to force signedness of wide character constants, define WCHAR_SIGNEDNESS
+ * to 0 for unsigned, 1 for signed.
+#define WCHAR_SIGNEDNESS 0
+ */
+
+/* ====================================================================== */
+/*
+ * Standard assertions. They should include one cpu() assertion, one machine()
+ * assertion (identical to cpu()), and one or more system() assertions.
+ *
+ * for Linux/PC: cpu(i386), machine(i386), system(unix), system(linux)
+ * for Linux/Alpha: cpu(alpha), machine(alpha), system(unix), system(linux)
+ * for Sparc/Solaris: cpu(sparc), machine(sparc), system(unix), system(solaris)
+ *
+ * These are only suggestions. On Solaris, machine() should be defined
+ * for i386 or sparc. For cross-compilation, define assertions related
+ * to the target architecture.
+ *
+ * If you want no standard assertion, define STD_ASSERT to 0.
+ */
+#define STD_ASSERT "cpu(alpha)", "machine(alpha)", "system(unix)", \
+ "system(linux)"
+
+/* ====================================================================== */
+/*
+ * System predefined macros. Nothing really mandatory, but some programs
+ * might rely on those.
+ * Each string must be either "name" or "name=token-list". If you want
+ * no predefined macro, define STD_MACROS to 0.
+ */
+#define STD_MACROS "__linux", "__unix", "__alpha", \
+ "__linux__", "__unix__", "__alpha__"
+
+/* ====================================================================== */
+/*
+ * Default flags; HANDLE_ASSERTIONS is required for Solaris system headers.
+ * See cpp.h for the definition of these flags.
+ */
+#define DEFAULT_CPP_FLAGS (DISCARD_COMMENTS | WARN_STANDARD \
+ | WARN_PRAGMA | FAIL_SHARP | MACRO_VAARG \
+ | CPLUSPLUS_COMMENTS | LINE_NUM | TEXT_OUTPUT \
+ | KEEP_OUTPUT | HANDLE_TRIGRAPHS \
+ | HANDLE_ASSERTIONS)
+#define DEFAULT_LEXER_FLAGS (DISCARD_COMMENTS | WARN_STANDARD | FAIL_SHARP \
+ | MACRO_VAARG | CPLUSPLUS_COMMENTS | LEXER \
+ | HANDLE_TRIGRAPHS | HANDLE_ASSERTIONS)
+
+/* ====================================================================== */
+/*
+ * Define this to use sigsetjmp()/siglongjmp() instead of setjmp()/longjmp().
+ * This is non-ANSI, but recommended on AIX systems.
+ */
+/* #define POSIX_JMP */
+
+/* ====================================================================== */
+/*
+ * Maximum value (plus one) of a character handled by the lexer; 128 is
+ * alright for ASCII native source code, but 256 is needed for EBCDIC.
+ * 256 is safe in both cases; you will have big problems if you set
+ * this value to INT_MAX or above. On Minix-86 or Msdos (small memory
+ * model), define MAX_CHAR_VAL to 128.
+ *
+ * Set MAX_CHAR_VAL to a power of two to increase lexing speed. Beware
+ * that lexer.c defines a static array of size MSTATE * MAX_CHAR_VAL
+ * values of type int (MSTATE is defined in lexer.c and is about 40).
+ */
+#define MAX_CHAR_VAL 256
+
+/*
+ * If you want some extra character to be considered as whitespace,
+ * define this macro to that space. On ISO-8859-1 machines, 160 is
+ * the code for the unbreakable space.
+ */
+/* #define UNBREAKABLE_SPACE 160 */
+
+/*
+ * If you want whitespace tokens contents to be recorded (making them
+ * tokens with a string content), define this. The macro STRING_TOKEN
+ * will be adjusted accordingly.
+ * Without this option, whitespace tokens are not even returned by the
+ * lex() function. This is irrelevant for the non-lexer mode (almost --
+ * it might slow down a bit ucpp, and with this option, comments will be
+ * kept inside #pragma directives).
+ */
+/* #define SEMPER_FIDELIS */
+
+/* ====================================================================== */
+/*
+ * Some constants used for memory increment granularity. Increasing these
+ * values reduces the number of calls to malloc() but increases memory
+ * consumption.
+ *
+ * Values should be powers of 2.
+ */
+
+/* for cpp.c */
+#define COPY_LINE_LENGTH 80
+#define INPUT_BUF_MEMG 8192
+#define OUTPUT_BUF_MEMG 8192
+#define TOKEN_NAME_MEMG 64 /* must be at least 4 */
+#define TOKEN_LIST_MEMG 32
+#define INCPATH_MEMG 16
+#define GARBAGE_LIST_MEMG 32
+#define LS_STACK_MEMG 4
+#define FNAME_MEMG 32
+
+/* ====================================================================== */
+/*
+ * C90 does not know about the "inline" keyword, but C99 does know,
+ * and some C90 compilers know it as an extension. This part detects
+ * these occurrences.
+ */
+
+#ifndef INLINE
+
+#if __STDC__ && __STDC_VERSION >= 199901L
+/* this is a C99 compiler, keep inline unchanged */
+#elif defined(__GNUC__)
+/* this is GNU gcc; modify inline. The semantics is not identical to C99
+ but the differences are irrelevant as long as inline functions are static */
+#undef inline
+#define inline __inline__
+#elif defined(__DECC) && defined(__linux__)
+/* this is Compaq C under Linux, use __inline__ */
+#undef inline
+#define inline __inline__
+#else
+/* unknown compiler -> deactivate inline */
+#undef inline
+#define inline
+#endif
+
+#else
+/* INLINE has been set, use its value */
+#undef inline
+#define inline INLINE
+#endif
+
+#endif
diff --git a/ucpp/ucppi.h b/ucpp/ucppi.h
new file mode 100755
index 0000000..6ae982d
--- /dev/null
+++ b/ucpp/ucppi.h
@@ -0,0 +1,192 @@
+/*
+ * (c) Thomas Pornin 1999, 2000
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. The name of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef UCPP__UCPPI__
+#define UCPP__UCPPI__
+
+#include "cpp.h"
+#include "tune.h"
+
+/*
+ * A macro represented in a compact form; simple tokens are represented
+ * by one byte, containing their number. Tokens with a string value are
+ * followed by the value (string finished by a 0). Macro arguments are
+ * followed by the argument number (in one byte -- thus implying a hard
+ * limit of 254 arguments (number 255 is for __VA_ARGS__).
+ */
+struct comp_token_fifo {
+ size_t length;
+ size_t rp;
+ unsigned char *t;
+};
+
+/* These declarations are used only internally by ucpp */
+
+/*
+ * S_TOKEN(x) checks whether x is a token type with an embedded string
+ * ttMWS(x) checks whether x is macro whitespace (space, comment...)
+ * ttWHI(x) checks whether x is whitespace (MWS or newline)
+ */
+#define S_TOKEN(x) STRING_TOKEN(x)
+#define ttMWS(x) ((x) == NONE || (x) == COMMENT || (x) == OPT_NONE)
+#define ttWHI(x) (ttMWS(x) || (x) == NEWLINE)
+
+/*
+ * Function prototypes
+ */
+/*
+ * from lexer.c
+ */
+#define init_cppm ucpp_init_cppm
+#define put_char ucpp_put_char
+#define discard_char ucpp_discard_char
+#define next_token ucpp_next_token
+#define grap_char ucpp_grap_char
+#define space_char ucpp_space_char
+
+void init_cppm(void);
+void put_char(struct lexer_state *, unsigned char);
+void discard_char(struct lexer_state *);
+int next_token(struct lexer_state *);
+int grap_char(struct lexer_state *);
+int space_char(int);
+
+/*
+ * from assert.c
+ */
+struct assert {
+ char *name; /* this must be the first field */
+ size_t nbval;
+ struct token_fifo *val;
+};
+
+#define cmp_token_list ucpp_cmp_token_list
+#define handle_assert ucpp_handle_assert
+#define handle_unassert ucpp_handle_unassert
+#define get_assertion ucpp_get_assertion
+
+int cmp_token_list(struct token_fifo *, struct token_fifo *);
+int handle_assert(struct lexer_state *);
+int handle_unassert(struct lexer_state *);
+struct assert *get_assertion(char *);
+
+/*
+ * from macro.c
+ */
+struct macro {
+ char *name; /* this must be the first field */
+ int narg;
+ char **arg;
+ int nest;
+ int vaarg;
+#ifdef LOW_MEM
+ struct comp_token_fifo cval;
+#else
+ struct token_fifo val;
+#endif
+};
+
+#define print_token ucpp_print_token
+#define handle_define ucpp_handle_define
+#define handle_undef ucpp_handle_undef
+#define handle_ifdef ucpp_handle_ifdef
+#define handle_ifndef ucpp_handle_ifndef
+#define substitute_macro ucpp_substitute_macro
+#define get_macro ucpp_get_macro
+#define dsharp_lexer ucpp_dsharp_lexer
+#define compile_time ucpp_compile_time
+#define compile_date ucpp_compile_date
+#define compile_adate ucpp_compile_adate
+#ifdef PRAGMA_TOKENIZE
+#define tokenize_lexer ucpp_tokenize_lexer
+#endif
+
+void print_token(struct lexer_state *, struct token *, long);
+int handle_define(struct lexer_state *);
+int handle_undef(struct lexer_state *);
+int handle_ifdef(struct lexer_state *);
+int handle_ifndef(struct lexer_state *);
+int substitute_macro(struct lexer_state *, struct macro *,
+ struct token_fifo *, int, int, long);
+struct macro *get_macro(char *);
+
+extern struct lexer_state dsharp_lexer;
+extern char compile_time[], compile_date[], compile_adate[];
+#ifdef PRAGMA_TOKENIZE
+extern struct lexer_state tokenize_lexer;
+#endif
+
+/*
+ * from eval.c
+ */
+#define strtoconst ucpp_strtoconst
+#define eval_expr ucpp_eval_expr
+#define eval_line ucpp_eval_line
+
+unsigned long strtoconst(char *);
+unsigned long eval_expr(struct token_fifo *, int *, int);
+extern long eval_line;
+
+#define eval_exception ucpp_eval_exception
+
+#ifdef POSIX_JMP
+#define JMP_BUF sigjmp_buf
+#define catch(x) sigsetjmp((x), 0)
+#define throw(x) siglongjmp((x), 1)
+#else
+#define JMP_BUF jmp_buf
+#define catch(x) setjmp((x))
+#define throw(x) longjmp((x), 1)
+#endif
+extern JMP_BUF eval_exception;
+
+/*
+ * from cpp.c
+ */
+#define token_name ucpp_token_name
+#define throw_away ucpp_throw_away
+#define garbage_collect ucpp_garbage_collect
+#define init_buf_lexer_state ucpp_init_buf_lexer_state
+#ifdef PRAGMA_TOKENIZE
+#define compress_token_list ucpp_compress_token_list
+#endif
+
+char *token_name(struct token *);
+void throw_away(struct garbage_fifo *, char *);
+void garbage_collect(struct garbage_fifo *);
+void init_buf_lexer_state(struct lexer_state *, int);
+#ifdef PRAGMA_TOKENIZE
+struct comp_token_fifo compress_token_list(struct token_fifo *);
+#endif
+
+#define ouch ucpp_ouch
+#define error ucpp_error
+#define warning ucpp_warning
+
+#endif
diff --git a/vars.c b/vars.c
new file mode 100644
index 0000000..21a12fe
--- /dev/null
+++ b/vars.c
@@ -0,0 +1,105 @@
+/* $VER: vbcc (vars.c) $Revision: 1.41 $ */
+#include "vbc.h"
+#ifdef AMIGA
+static const char *__ver="$VER: vbcc 0.9i_pre (xx.yy.2022)\r\n";
+long __stack=65536;
+#endif
+char *s,*ident;
+char number[MAXI],buff[MAXI];
+tunit *first_tunit,*last_tunit;
+struct_declaration *first_sd[MAXN],*last_sd[MAXN],*merk_sdf,*merk_sdl;
+struct_identifier *first_si[MAXN],*last_si[MAXN],*merk_sif,*merk_sil;
+identifier_list *first_ilist[MAXN],*last_ilist[MAXN],*merk_ilistf,*merk_ilistl;
+llist *first_llist,*last_llist;
+int nesting;
+hashtable *hash_ext;
+Var *first_var[MAXN],*last_var[MAXN],*merk_varf,*merk_varl,*first_ext,*last_ext;
+Var *block_vla[MAXN];
+llist *vladeflabels[MAXN],*vlajmplabels[MAXN];
+vlaadjust_list *vlaadjusts[MAXN];
+rpair rp;
+FILE *out,*ic1,*ic2,*ppout,*cmdfile;
+int c99=1;
+int force_statics,prefer_statics;
+int range_opt;
+int merge_strings;
+int sec_per_obj;
+int mask_opt;
+int opencl;
+int disallow_statics;
+int header_cnt;
+int wpo,wpo_key;
+FILE *input_wpo;
+int nocode,dontdelete;
+int const_expr,for_decl;
+int registerpri=200,currentpri,looppri=10;
+int return_value,break_label,switch_typ,switch_count,switch_act;
+int pointer_call;
+int softfloat;
+int ecpp;
+type *return_typ;
+Var *return_var;
+zmax local_offset[MAXN];
+int c_flags[MAXCF]={
+ VALFLAG,STRINGFLAG,0,0,
+ VALFLAG,0,0,0,
+ VALFLAG,FUNCFLAG,FUNCFLAG,VALFLAG,
+ VALFLAG,0,0,0,
+ 0,0,0,0,
+ 0,0,0,0,0,
+ VALFLAG,0,0,0,0,
+ 0,VALFLAG,0,0,0,STRINGFLAG,0,
+ VALFLAG,VALFLAG,0,VALFLAG,0,
+ FUNCFLAG,FUNCFLAG,FUNCFLAG,0,
+ 0,0,0,0,
+ 0,0,0,VALFLAG,
+ 0,
+ VALFLAG,VALFLAG,VALFLAG,VALFLAG,
+ STRINGFLAG,0,0,0,0,0,
+ 0,0,0,0
+};
+char *c_flags_name[MAXCF]={
+ "O","o","ic1","ic2",
+ "debug","noasm","quiet","ansi",
+ "maxerrors","dontwarn","warn","maxoptpasses",
+ "inline-size","+","cpp-comments","no-trigraphs",
+ "no-inline-peephole","final","E","dontkeep-initialized-data",
+ "strip-path","fp-associative","iso","no-alias-opt","no-multiple-ccs",
+ "unroll-size","double-push","speed","size","unroll-all",
+ "stack-check","inline-depth","g","c99","wpo","cmd","noitra",
+ "misra","coloring","dmalloc","disable","soft-float",
+ "misrawarn","misradontwarn","reserve-reg","ecpp",
+ "short-push","unsigned-char","opencl","no-include-stack",
+ "deps","deps-for-libs","no-cpp-warn","hash-size",
+ "warnings-as-errors",
+ "clist-copy-stack","clist-copy-static","clist-copy-pointer","inline-memcpy",
+ "depobj","c89","force-statics","prefer-statics","range-opt","merge-strings",
+ "sec-per-obj","no-eff-ics","early-eff-ics","mask-opt"
+};
+union ppi c_flags_val[MAXCF];
+char *inname;
+char **target_macros;
+Var *regsbuf[MAXR+1];
+int regbnesting[MAXR+1];
+const_list *first_clist,*last_clist;
+int afterlabel;
+terr_out err_out[]={
+#include "errors.h"
+"",0
+};
+int err_num=sizeof(err_out)/sizeof(err_out[0])-1;
+
+tmisra_err_out misra_err_out[]={
+#include "misra_errors.h"
+0,0,"",0
+};
+
+#ifdef HAVE_ECPP
+struct_declaration *current_class=0;
+type *current_func=0;
+ecpp_dtor_list *ecpp_dlist[MAXN];
+#endif
+
+char *cur_func="shouldn't happen!";
+Var *cur_funcv;
+char *copyright="vbcc V0.9i pre (c) in 1995-2022 by Volker Barthelmann";
diff --git a/vbc.h b/vbc.h
new file mode 100644
index 0000000..6d170ac
--- /dev/null
+++ b/vbc.h
@@ -0,0 +1,273 @@
+/* $VER: vbcc (vbc.h) $Revision: 1.23 $ */
+
+#include "supp.h"
+
+#define eval_constn(a) eval_const(&a->val,a->ntyp->flags)
+
+typedef struct identifier_list{
+ char *identifier;
+ int length;
+ struct identifier_list *next;
+} identifier_list;
+typedef struct struct_identifier{
+/* int flags;*/
+ char *identifier;
+ struct struct_declaration *sd;
+ struct struct_identifier *next;
+} struct_identifier;
+
+#ifndef NODES
+#error wrong node
+typedef struct node{
+ int flags,lvalue,sidefx;
+ type *ntyp;
+ struct node *left;
+ struct node *right;
+ struct argument_list *alist;
+ char *identifier;
+ union atyps val;
+ struct obj o;
+} node;
+
+typedef node *np;
+
+#define NODES sizeof(node)
+#endif
+
+typedef struct argument_list{
+ np arg;
+ struct argument_list *next;
+ struct IC *pushic;
+} argument_list;
+
+
+#define MAXI 512 /* maximale Laenge von Identifiers in Bytes */
+#define MAXN 128 /* maximale Verschachtelung von Bloecken */
+
+extern struct tunit *first_tunit,*last_tunit;
+extern type *arith_typ(type*,type *);
+extern void insert_constn(np);
+extern int int_erw(int);
+extern type *andcomp(np,np);
+extern void simple_alg_opt(np);
+extern int type_expression(np,type *),
+ compatible_types(type *,type *,int),
+ compare_sd(struct struct_declaration *,struct struct_declaration *);
+#if HAVE_AOS4
+extern int aos4_attr(type *,char *);
+#endif
+extern np identifier_expression(void),constant_expression(void),string_expression(void),
+ postfix_expression(void),unary_expression(void),cast_expression(void),
+ multiplicative_expression(void),additive_expression(void),
+ shift_expression(void),relational_expression(void),equality_expression(void),
+ and_expression(void),exclusive_or_expression(void),
+ inclusive_or_expression(void),logical_and_expression(void),
+ logical_or_expression(void),conditional_expression(void),
+ assignment_expression(void),expression(void),primary_expression(void);
+extern struct argument_list *argument_list_expression(void);
+extern struct const_list *cl_from_string(char *start, char *end);
+
+extern np new_node(void);
+
+/* puh */
+extern int is_keyword(char *);
+extern void pre(FILE *,np),pra(FILE *,struct argument_list *);
+extern void free_expression(np),free_alist(struct argument_list *);
+extern void cpbez(char *m,int ckw),cpnum(char *m),killsp(void);
+extern void copy_token(/*no prototype because cpp.h not always included*/);
+extern void push_token(/*no prototype because cpp.h not always included*/);
+extern void next_token(void);
+extern struct struct_declaration *add_sd(struct struct_declaration *,int);
+extern void add_sl(struct struct_declaration *,struct struct_list (*)[]);
+extern void free_sd(struct struct_declaration *);
+extern void prl(FILE *,struct struct_declaration *);
+extern char *add_identifier(char *,int);
+extern type *declarator(type *),*direct_declarator(type *),
+ *pointer(type *),*declaration_specifiers(void);
+extern int declaration(int),type_uncomplete(type *);
+extern struct const_list *initialization(type *,int,int,int,struct struct_declaration *,struct const_list *);
+extern void init_local_compound(struct Var *);
+extern zmax init_dyn_sz,init_const_sz;
+extern int init_dyn_cnt,init_const_cnt;
+extern struct struct_declaration *find_struct(char *,int);
+extern void add_struct_identifier(char *,struct struct_declaration *);
+extern void free_si(struct struct_identifier *);
+extern char *ident;
+extern char number[MAXI],buff[MAXI];
+extern struct struct_declaration *first_sd[MAXN],*last_sd[MAXN],*merk_sdf,*merk_sdl;
+extern struct struct_identifier *first_si[MAXN],*last_si[MAXN],*merk_sif,*merk_sil;
+extern struct identifier_list *first_ilist[MAXN],*last_ilist[MAXN],*merk_ilistf,*merk_ilistl;
+extern void free_ilist(struct identifier_list *);
+extern int nesting;
+extern hashtable *hash_ext;
+extern struct Var *first_var[MAXN],*last_var[MAXN],*merk_varf,*merk_varl,*first_ext,*last_ext;
+extern struct Var *block_vla[MAXN];
+extern struct llist *vladeflabels[MAXN],*vlajmplabels[MAXN];
+extern struct vlaadjust_list *vlaadjusts[MAXN];
+extern void freevl(void);
+extern void clearvl(void);
+extern void free_var(struct Var *);
+extern void var_declaration(void);
+extern int storage_class_specifiers(void);
+extern void enter_block(void),leave_block(void);
+extern struct Var *find_var(char *,int);
+extern struct Var *find_ext_var(char *);
+extern struct Var *add_var(char *,type *,int,struct const_list *);
+extern void fi_from_attr(struct Var *);
+extern void needs(char *s);
+
+
+extern int usz;
+
+extern int c99;
+extern int opencl;
+extern int merge_strings;
+extern int mask_opt;
+extern int disallow_statics;
+extern int header_cnt;
+extern int softfloat;
+#define MAGIC_WPO 123
+extern int wpo,wpo_key;
+extern FILE *input_wpo;
+
+extern void gen_IC(np,int,int),convert(np,int),gen_label(int);
+extern void gen_test(struct obj *,int,int,int);
+extern void savescratch(int,struct IC *,int,struct obj *);
+typedef struct regargs_list{
+ struct regargs_list *next;
+ struct argument_list *al;
+ int reg;
+ struct Var *v;
+ int rsaved;
+} regargs_list;
+#ifdef HAVE_REGPARMS
+extern zmax push_args(struct argument_list *,struct struct_declaration *,int,struct regargs_list **,struct reg_handle *,struct obj *,type *,int,type *);
+#else
+extern zmax push_args(struct argument_list *,struct struct_declaration *,int,struct regargs_list **);
+#endif
+extern int allocreg(int,int);
+extern void free_reg(int),alloc_hardreg(int);
+
+extern FILE *out,*ic1,*ic2,*ppout,*cmdfile;
+
+extern void statement(void),labeled_statement(void),if_statement(void);
+extern void switch_statement(void),while_statement(void),for_statement(void);
+extern void do_statement(void),goto_statement(void),continue_statement(void);
+extern void break_statement(void),return_statement(void);
+extern void expression_statement(void),compound_statement(void);
+extern void translation_unit(void);
+extern int main(int, char *[]);
+extern int nocode,dontdelete,registerpri,looppri,currentpri;
+extern int no_cast_free;
+
+extern np makepointer(np);
+
+typedef struct vlaadjust_list {
+ struct IC *branch,*first;
+ struct vlaadjust_list *next;
+} vlaadjust_list;
+
+extern int switch_typ,switch_count,switch_act;
+typedef struct llist{
+ char *identifier;
+ int label,flags,switch_count;
+ struct llist *next;
+ union atyps val;
+} llist;
+#define LABELDEFINED 1
+#define LABELUSED 2
+#define LABELDEFAULT 4
+#define LSIZE sizeof(struct llist)
+extern struct llist *first_llist,*last_llist;
+extern struct llist *find_label(char *),*add_label(char *);
+extern void free_llist(struct llist *);
+
+extern int endok,return_label,return_value,break_label;
+extern int const_expr,for_decl;
+extern struct Var *return_var;
+extern type *return_typ;
+extern zmax local_offset[MAXN];
+
+extern void scratch_var(struct obj *,int,type *);
+extern void get_scratch(struct obj *,int,int,type *);
+extern void gen_cond(struct obj *,int,int,int);
+
+#define MAXCF 70
+extern int c_flags[MAXCF];
+extern char *c_flags_name[MAXCF];
+extern union ppi c_flags_val[MAXCF];
+
+extern FILE *open_out(char *,char *);
+
+extern char *inname;
+
+extern void gen_vars(struct Var *);
+
+/* Format der Tabelle fuer Fehlermeldungen */
+typedef struct err_out{
+ char *text;
+ int flags;
+} terr_out;
+
+
+/* Flags fuer err_out.flags */
+#define ERROR 1
+#define WARNING 2
+#define ANSIV 4
+#define INTERNAL 8
+#define FATAL 16
+#define MESSAGE 32
+#define DONTWARN 64
+#define PREPROC 128
+#define NOLINE 256
+#define INFUNC 512
+#define INIC 1024
+#define NORAUS 2048
+
+extern struct err_out err_out[];
+extern int err_num;
+
+typedef struct misra_err_out{
+ int chapter;
+ int rule;
+ char *text;
+ int flags;
+} tmisra_err_out;
+
+extern struct misra_err_out misra_err_out[];
+
+#define MISRA 1
+#define MISRA_PREPROC 2
+#define MISRA_2004 4
+#define MISRA_1998 8
+
+#ifdef HAVE_ECPP
+typedef struct ecpp_dtor_list {
+ struct Var *var;
+ struct ecpp_dtor_list *next;
+} ecpp_dtor_list;
+extern struct struct_declaration *current_class;
+extern type *current_func;
+extern struct ecpp_dtor_list *ecpp_dlist[MAXN];
+struct Var *ecpp_find_ext_var(char *identifier);
+struct Var *ecpp_find_var(char *identifier);
+struct struct_declaration *ecpp_find_scope(char* nested_name,char** identifier);
+struct struct_list *ecpp_find_member(char* identifier,struct struct_declaration *scope,struct struct_declaration** ret_scope,int search_flag);
+void ecpp_auto_call_dtors();
+int ecpp_is_friend(struct struct_declaration *class);
+#endif
+
+extern int afterlabel;
+
+extern int errors;
+
+extern int float_used;
+extern char *cur_func;
+extern Var *cur_funcv;
+extern int line;
+extern void free_clist(struct const_list *);
+extern struct const_list *first_clist,*last_clist;
+extern struct Var *regsbuf[MAXR+1];
+extern int regbnesting[MAXR+1];
+
+
diff --git a/vbcc_cpp.h b/vbcc_cpp.h
new file mode 100755
index 0000000..1e14b0f
--- /dev/null
+++ b/vbcc_cpp.h
@@ -0,0 +1,47 @@
+/* $VER: vbcc (vbcc_cpp.h) $Revision: 1.2 $ */
+
+
+/* fix some name clashes between vbcc and ucpp and include cpp.h */
+/* has to be include prior to other vbcc includes */
+
+
+#define STRING T_STRING
+#define CHAR T_CHAR
+#define CAST T_CAST
+#define AND T_AND
+#define OR T_OR
+#define COLON T_COLON
+#define LOR T_LOR
+#define LAND T_LAND
+#define MINUS T_MINUS
+
+#define NO_UCPP_ERROR_FUNCTIONS 1
+#include "ucpp/cpp.h"
+
+typedef struct token token;
+typedef struct lexer_state lexer_state;
+typedef struct stack_context stack_context;
+
+extern token *ctok;
+extern lexer_state ls;
+
+#undef STRING
+#undef CHAR
+#undef CAST
+#undef AND
+#undef OR
+#undef COLON
+#undef LOR
+#undef LAND
+#undef MINUS
+
+#define next_token vbcc_next_token
+#undef error
+
+#undef S_TOKEN
+#define S_TOKEN(x) ((x) >= NUMBER && (x) <= T_CHAR)
+
+#define ttMWS(x) ((x) == NONE || (x) == COMMENT || (x) == OPT_NONE)
+#define ttWHI(x) (ttMWS(x) || (x) == NEWLINE)
+
+char *ucpp_token_name();
diff --git a/vbpp.h b/vbpp.h
new file mode 100755
index 0000000..aa70f07
--- /dev/null
+++ b/vbpp.h
@@ -0,0 +1,89 @@
+#ifndef _VBPP_H
+#define _VBPP_H 1
+
+/* vbpp.h
+ * last change: 17.08.1995 Thorsten Schaaps
+ */
+
+/* strnode-types */
+#define NORMAL 0 /* anything: brackets,+,-,/,*, etc.. */
+#define PP_IDENT 1 /* possible identifier */
+#define ARGUMENT 2 /* argument: see number */
+#define PP_STR 3 /* strings */
+#define NUMBER 4 /* numbers (123,0x00,0L,..) */
+#define SPACE 5 /* spaces, tabs, etc. */
+#define SPECIAL 6 /* flags=1->#,flags=2->## */
+
+/* flags for type==SPECIAL */
+#define NONE 0
+#define TOSTRING 1 /* #define t(c) #c */
+#define KILLSPACES 2 /* #define t(a,b) a##b */
+
+struct strnode{
+ char *str; /* the string =8) ah, you guessed that. */
+ int len; /* the length of the string */
+ int flags; /* flags: see above */
+ int type; /* type: see above */
+ int number; /* only valid if type==ARGUMENT */
+ struct strnode *prev,*next; /* pointers to previous and next node or NULL */
+};
+
+/* Macro-Node-Flags */
+#define FUNCTION 1 /* for macros changing from line to line, e.g. */
+ /* __LINE__, __FILE__, __TIME__ etc.. */
+#define PARAMETER 2 /* Macro has arguments */
+#define NODELETE 4 /* Macro cannot be UNDEFined, e.g. __TIME__, */
+ /* __DATE__, __STDC__ */
+#define NOREDEF 8 /* Macro cannot be reDEFINED, (s. above, but */
+ /* not __STDC__) */
+
+/* Function-Numbers for FUNCTION-Macros */
+#define FUNCLINE 1 /* __LINE__ */
+#define FUNCFILE 2 /* __FILE__ */
+#define FUNCDATE 3 /* __DATE__ */
+#define FUNCTIME 4 /* __TIME__ */
+ /* __STDC__ is a normal macro, but cannot be deleted */
+
+struct mnode{
+ char *name; /* name, e.g. SQR */
+ char *args; /* arguments, e.g. (x) */
+ char *token; /* definition as string, e.g. ((x)*(x)) */
+ /* BE CAREFULL: may be NULL in the future */
+ struct strnode *tokenlist; /* definition as list */
+ int flags; /* flags, see above */
+ int numargs; /* number of arguments */
+ int funcnum; /* number of function (see above) */
+ struct mnode *prev,*next; /* pointers to previos and next node or NULL */
+};
+
+/* Return-Codes for ExpandList/ExpandArgMakro/CloneArg-Functions */
+#define OK 0
+#define OUT_OF_MEM -1
+#define NUM_OF_ARGS -2
+#define ARG_EXPECTED -3
+
+void AddMakroNode(struct mnode **, struct mnode *);
+void InsertMakroNode(struct mnode **, struct mnode *, struct mnode *);
+void RemMakroNode(struct mnode **, struct mnode *);
+struct mnode *FindMakroNode(struct mnode *, char *, int);
+void DelMakroNode(struct mnode **, struct mnode *);
+void DelMakroList(struct mnode **);
+
+void AddStrNode(struct strnode **, struct strnode *, char *);
+void RemStrNode(struct strnode **, struct strnode *);
+/* struct strnode *FindStrNode(struct strnode *, char *, int); */
+void DelStrNode(struct strnode **, struct strnode *);
+void DelStrList(struct strnode **);
+struct strnode *CloneStrList(struct strnode *, struct strnode *);
+struct strnode *DoMakroFunction(struct mnode *);
+
+struct strnode *Str2List(char *);
+int List2Str(struct strnode *, char *, int);
+
+int ExpandList(struct strnode **);
+
+struct mnode *ParseIdentifier(char *);
+int PreParse(void);
+
+#endif
+
diff --git a/vcpr/vcpr.c b/vcpr/vcpr.c
new file mode 100644
index 0000000..8fa0bff
--- /dev/null
+++ b/vcpr/vcpr.c
@@ -0,0 +1,441 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "vcpr.h"
+
+line *first_line,*last_line;
+
+int debug=0;
+
+
+
+int labcnt,maxlab;
+labinfo *labinfos;
+
+const char vs_copyright[]="vcpr code compressor V0.1 (c) 2020 by Volker Barthelmann";
+
+
+
+void *mymalloc(size_t sz)
+{
+ void *p=malloc(sz);
+ if(!p){
+ fprintf(stderr,"Out of memory!\n");
+ exit(EXIT_FAILURE);
+ }
+ return p;
+}
+
+match *new_match(void)
+{
+ match *new;
+ new=mymalloc(sizeof(*new));
+ new->next=0;
+ new->start=0;
+ new->max=0;
+ return new;
+}
+
+void extend_labinfos(int n)
+{
+ if(n>maxlab)
+ maxlab=n;
+ /* TODO */
+}
+
+int new_label(void)
+{
+ maxlab++;
+ extend_labinfos(maxlab);
+ return maxlab;
+}
+
+line *new_line(void)
+{
+ line *new;
+ new=mymalloc(sizeof(*new));
+ new->next=new->prev=0;
+ new->code=0;
+ new->flags=0;
+ new->size=0;
+ new->l1=new->l2=0;
+ return new;
+}
+
+void add_line(line *new)
+{
+ if(last_line){
+ last_line->next=new;
+ new->prev=last_line;
+ last_line=new;
+ }else{
+ first_line=last_line=new;
+ }
+}
+
+void insert_line(line *after, line *new)
+{
+ if(!after){
+ new->next=first_line;
+ first_line=new;
+ }else{
+ new->next=after->next;
+ after->next=new;
+ }
+ new->prev=after;
+ if(new->next)
+ new->next->prev=new;
+ else
+ last_line=new;
+}
+
+void free_line(line *p)
+{
+ if(p->code) free(p->code);
+ free(p);
+}
+
+void remove_line(line *p)
+{
+ if(p->prev) p->prev->next=p->next; else first_line=p->next;
+ if(p->next) p->next->prev=p->prev; else last_line=p->prev;
+}
+
+
+
+
+
+
+void read_lines(FILE *f)
+{
+ char buf[MAXLEN],*p;
+ line *new;
+ int idx=0;
+
+ while(1){
+ p=fgets(buf,MAXLEN,f);
+ if(feof(f))
+ return;
+ new=new_line();
+ parse_line(buf,new);
+ new->code=mymalloc(strlen(buf)+1);
+ strcpy(new->code,buf);
+ new->idx=++idx;
+ add_line(new);
+ if(new->flags&LABUSE){
+ extend_labinfos(new->l1);
+ extend_labinfos(new->l2);
+ labinfos[new->l1].usecnt++;
+ labinfos[new->l2].usecnt++;
+ }
+ if(new->flags&LABDEF)
+ extend_labinfos(new->l1);
+ /* skip rest of long line, TODO */
+ while(p==&buf[MAXLEN-1])
+ p=fgets(buf,MAXLEN,f);
+ }
+}
+
+void print_line(line *p)
+{
+ printf("[idx=%d flags=%d sz=%d l1=%d l2=%d]: %s",p->idx,p->flags,p->size,p->l1,p->l2,p->code);
+}
+
+int slab,dlab;
+
+int match_line(line *a, line *b)
+{
+ if((a->flags&(BARRIER|LBARRIER))||(b->flags&(BARRIER|LBARRIER)))
+ return 0;
+
+ /* we currently handle only one label */
+ if(a->l2!=b->l2)
+ return 0;
+
+ if(a->l1&&!b->l1)
+ return 0;
+ if(b->l1&&!a->l1)
+ return 0;
+
+ if(a->l1&&a->l1==slab)
+ if(b->l1!=dlab)
+ return 0;
+
+ if(!strcmp(a->code, b->code)&&!(a->flags&BRANCH))
+ return 1;
+
+ if(slab&&a->l1!=slab&&a->l1!=b->l1)
+ return 0;
+
+ if(a->l1&&b->l1){
+ char *pa=a->code;
+ char *pb=b->code;
+ char al[32],bl[32];
+ int la,lb;
+ sprintf(al,"l%d",a->l1);
+ sprintf(bl,"l%d",b->l1);
+ la=strlen(al);
+ lb=strlen(bl);
+ while(*pa&&*pb){
+ if(!strncmp(pa,al,la)){
+ if(!strncmp(pb,bl,lb)){
+ pa+=la;
+ pb+=lb;
+ }else
+ return 0;
+ }else{
+ if(*pa!=*pb)
+ return 0;
+ pa++;
+ pb++;
+ }
+ }
+ if(*pa||*pb)
+ return 0;
+ if(!slab){
+ slab=a->l1;
+ dlab=b->l1;
+ }else{
+ if(a->l1!=slab||b->l1!=dlab)
+ return 0;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+match *check_matches(line *s,line *p, int min)
+{
+ int sz=0,n=0;
+ match *new;
+ line *first;
+
+ slab=dlab=0;
+
+ if(!match_line(s, p))
+ return 0;
+
+ first=p;
+
+ new=new_match();
+ new->start=p;
+
+ do{
+ sz+=p->size;
+ new->size[n]=sz;
+ n++;
+ new->max=n;
+ p=p->next;
+ s=s->next;
+ }while(n<MAXMLEN&&p&&s&&match_line(s ,p)&&s!=first);
+
+ if(sz<min){
+ free(new);
+ return 0;
+ }
+
+ if(slab){
+ int lstart=0,luse=0,ldef=0;
+ if(debug) printf("checking labvalid\n");
+ for(n=0,p=new->start;n<new->max;n++,p=p->next){
+ if(p->l1==dlab){
+ lstart=1;
+ if(p->flags&LABDEF)
+ ldef=1;
+ if(p->flags&LABUSE)
+ luse++;
+ }
+ if(lstart&&(!ldef||luse<labinfos[dlab].usecnt))
+ new->size[n]=0;
+ }
+ }
+
+ return new;
+}
+
+void free_matches(match *p)
+{
+ match *n;
+ while(p){
+ n=p->next;
+ free(p);
+ p=n;
+ }
+}
+
+void print_matches(match *p)
+{
+ int i;
+ line *l;
+ if(p->next)
+ print_matches(p->next);
+ printf("match:\n");
+ for(i=0,l=p->start;i<p->max;i++){
+ printf("sv=%d ",p->size[i]);
+ print_line(l);
+ l=l->next;
+ }
+}
+
+
+int main(int argc,char *argv[])
+{
+ int i,quiet=0,changed,pass=0;
+ FILE *in,*out; char *inname=0,*outname=0;
+ line *p;
+
+ for(i=1;i<argc;i++){
+ if(*argv[i]!='-'){
+ if(!inname){
+ inname=argv[i];
+ }else{
+ if(outname){
+ printf("Only one input file allowed\n");
+ exit(EXIT_FAILURE);
+ }else{
+ outname=argv[i];
+ }
+ }
+ }else{
+ if(!strcmp("-quiet",argv[i])) {quiet=1;continue;}
+#ifndef DEBUG
+ if(!strncmp("-debug=",argv[i],7)){debug=atoi(argv[i]+7);continue;}
+#endif
+ printf("Unknown option \"%s\"\n",argv[i]);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if(!quiet){
+#ifdef SPECIAL_COPYRIGHT
+ printf("%s\n",SPECIAL_COPYRIGHT);
+#else
+ printf("%s\n%s\n",vs_copyright,tg_copyright);
+#endif
+ }
+ if(!inname){printf("No input file\n");exit(EXIT_FAILURE);}
+ if(!outname){printf("No output file\n");exit(EXIT_FAILURE);}
+ in=fopen(inname,"r");
+ if(!in){printf("Could not open input file \"%s\"\n",inname);exit(EXIT_FAILURE);}
+ out=fopen(outname,"w");
+ if(!out){printf("Could not open output file \"%s\"\n",outname);exit(EXIT_FAILURE);}
+
+ labinfos=mymalloc(sizeof(labinfo)*LABNUM);
+ labcnt=LABNUM;
+
+ for(i=0;i<labcnt;i++)
+ labinfos[i].usecnt=0;
+
+ read_lines(in);
+
+ if(debug)
+ for(p=first_line;p;p=p->next)
+ print_line(p);
+
+ if(debug)
+ for(i=1;i<labcnt;i++)
+ if(labinfos[i].usecnt)
+ printf("lab %d used %d times\n",i,labinfos[i].usecnt);
+
+ do{
+ pass++;
+ changed=0;
+ if(debug) printf("pass %d\n",pass);
+ for(p=first_line;p;p=p->next){
+ line *n;
+ match *m,*mlist=0;int max=0,tmp;
+
+ if(sscanf(p->code,";vcprmin=%d",&tmp)==1)
+ minsave=tmp;
+ if(sscanf(p->code,"#vcprmin=%d",&tmp)==1)
+ minsave=tmp;
+
+ for(n=p->next;n;n=n->next){
+ m=check_matches(p,n,minsave);
+ if(m){
+ m->next=mlist;
+ mlist=m;
+ if(m->max>max) max=m->max;
+ /* TODO: is this necessary? */
+ for(i=0;i<m->max;i++)
+ n=n->next;
+ }
+ }
+ if(mlist){
+ int maxsav=0,maxn=0,csav,cnt;
+
+ if(debug){
+ printf("mlist: \n");
+ print_line(p);
+ print_matches(mlist);
+ }
+ for(i=1;i<=max;i++){
+ csav=0;cnt=0;
+ for(m=mlist;m;m=m->next){
+ if(m->max>=i){
+ cnt++;
+ csav+=m->size[i-1]-minsave;
+ }
+ }
+ if(debug) printf("%d times %d: total %d\n",cnt,i,csav);
+ if(csav>maxsav){
+ maxsav=csav;
+ maxn=i;
+ }
+ }
+ if(debug) printf("best saving: %d: total %d\n",maxn,maxsav);
+
+ n=p->prev;
+ if(n&&maxsav>0){
+ add_header(last_line);
+ if(last_line->next==last_line) abort();
+ if(debug) printf("copying header:\n");
+ for(i=0;i<maxn;i++){
+ p=n->next;
+ if(debug) print_line(p);
+ p->flags|=LBARRIER;
+ remove_line(p);
+ insert_line(last_line,p);
+ }
+
+ changed=1;
+ add_jsr(n);
+
+ add_ret(last_line);
+
+ labinfos[n->next->l1].usecnt++;
+ if(debug) printf("update usecnt lab %d to %d\n",n->next->l1,labinfos[n->next->l1].usecnt);
+
+ for(m=mlist;m;m=m->next){
+ if(m->max>=maxn){
+ if(debug) printf("remove copy:\n");
+ p=m->start->prev;
+ for(i=0;i<maxn;i++){
+ line *t=p->next;
+ if(debug) print_line(t);
+ remove_line(t);
+ free_line(t);
+ }
+ add_jsr(p);
+ labinfos[p->next->l1].usecnt++;
+ if(debug) printf("update usecnt lab %d to %d\n",p->next->l1,labinfos[p->next->l1].usecnt);
+ }
+ }
+ p=n;
+ }
+ free_matches(mlist);
+ }
+ }
+ if(changed){
+ for(p=first_line;p;p=p->next)
+ p->flags&=~LBARRIER;
+ }
+ }while(changed);
+
+ for(p=first_line;p;p=p->next)
+ fprintf(out,"%s",p->code);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/vcpr/vcpr.h b/vcpr/vcpr.h
new file mode 100644
index 0000000..d2b64e7
--- /dev/null
+++ b/vcpr/vcpr.h
@@ -0,0 +1,50 @@
+#define LABDEF 1
+#define LABUSE 2
+#define BARRIER 4
+#define LBARRIER 8
+#define BRANCH 16 /* only move if target also moved */
+
+typedef struct line {
+ struct line *next,*prev;
+ char *code;
+ int flags;
+ int size;
+ int idx;
+ int l1,l2;
+} line;
+
+#define MAXMLEN 64
+
+typedef struct match {
+ struct match *next;
+ line *start;
+ int max;
+ int size[MAXMLEN];
+} match;
+
+typedef struct {
+ int usecnt;
+} labinfo;
+
+#define LABNUM 10000
+
+#define MAXLEN 1024
+
+
+/* functions available to backend */
+void *mymalloc(size_t sz);
+int new_label(void);
+void extend_labinfos(int n);
+line *new_line(void);
+void insert_line(line *after, line *new);
+void remove_line(line *p);
+void free_line(line *p);
+
+/* functions provided by the backend */
+extern int minsave;
+extern const char tg_copyright[];
+
+void parse_line(char *s,line *p);
+void add_header(line *after);
+void add_ret(line *after);
+void add_jsr(line *after);
diff --git a/vprof/vprof.c b/vprof/vprof.c
new file mode 100755
index 0000000..4601092
--- /dev/null
+++ b/vprof/vprof.c
@@ -0,0 +1,166 @@
+/*
+ * vprof
+ *
+ * vbcc profiler. Displays the contents of "mon.out" files.
+ * (C)1998,2010 by Frank Wille <frank@phoenix.owl.de>
+ *
+ * vprof is freeware and part of the portable and retargetable ANSI C
+ * compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
+ * vprof 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define VERSION 0
+#define REVISION 2
+#define PLEVEL 0
+#define DEFAULTNAME "mon.out"
+
+struct profdata {
+ char *funcname;
+ unsigned long ncalls;
+ unsigned long tottime;
+ unsigned long loctime;
+};
+
+
+static void show(struct profdata *pdata,int n)
+/* write profdata records to stdout */
+{
+ struct profdata *p;
+ unsigned long runtime;
+ int i;
+
+ for (i=0,p=pdata,runtime=0; i<n; i++,p++)
+ runtime += p->loctime;
+
+ printf(" %% total local local total\n"
+ " time seconds seconds calls ms/call ms/call name\n");
+ for (i=0,p=pdata; i<n; i++,p++) {
+ printf("%5.2f %7.2f %7.2f %9lu %10.3f %10.3f %s\n",
+ ((double)p->loctime/(double)runtime)*100.0,
+ (double)p->tottime/1000000.0,
+ (double)p->loctime/1000000.0,
+ p->ncalls,
+ ((double)p->loctime/(double)p->ncalls)/1000.0,
+ ((double)p->tottime/(double)p->ncalls)/1000.0,
+ p->funcname);
+ }
+}
+
+
+static int cmp_total(const void *pd1,const void *pd2)
+{
+ return ((int)(((struct profdata *)pd2)->loctime -
+ ((struct profdata *)pd1)->loctime));
+}
+
+
+static void show_local(struct profdata *pd,int n)
+/* show profiling data, sorted according to the local time */
+/* spent in each function */
+{
+ qsort(pd,n,sizeof(struct profdata),cmp_total);
+ show(pd,n);
+}
+
+
+static char *skipname(char *p)
+/* skip name and alignment bytes and return pointer to profile data */
+{
+ int n = strlen(p)+1;
+
+ p += n;
+ if (n &= 3)
+ p += 4-n;
+ return (p);
+}
+
+
+int main(int argc,char *argv[])
+{
+ char *mname;
+ FILE *fp;
+ long size,len;
+ char *buf,*p;
+ int i,nrecs = 0;
+ struct profdata *pdata,*pd;
+
+ if (argc >= 2) {
+ if (*argv[1]=='-' || *argv[1]=='?') {
+ printf("%s V%d.%d%c (c)1998,2010 by Frank Wille\n"
+ "Usage:\n %s [mon.out]\n",argv[0],
+ VERSION,REVISION,PLEVEL?('a'+PLEVEL-1):' ',argv[0]);
+ exit(1);
+ }
+ else
+ mname = argv[1];
+ }
+ else
+ mname = DEFAULTNAME;
+
+ if (fp = fopen(mname,"r")) {
+ /* determine file size */
+ fseek(fp,0,SEEK_END);
+ size = ftell(fp);
+ fseek(fp,0,SEEK_SET);
+ if (size < 0) {
+ fclose(fp);
+ fprintf(stderr,"%s: Seek error on %s!\n",argv[0],mname);
+ exit(EXIT_FAILURE);
+ }
+
+ /* allocate buffer and read file */
+ if (!(buf = malloc(size))) {
+ fclose(fp);
+ fprintf(stderr,"%s: Not enough memory!\n",argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (fread(buf,1,size,fp) != size) {
+ fclose(fp);
+ fprintf(stderr,"%s: %s had a read error!\n",argv[0],mname);
+ exit(EXIT_FAILURE);
+ }
+ fclose(fp);
+
+ /* count number of entries in mon.out and allocate profdata array */
+ p = buf;
+ while (p < buf+size) {
+ nrecs++;
+ p = skipname(p) + 3*sizeof(unsigned long);
+ }
+ if (p!=buf+size || nrecs==0) {
+ fprintf(stderr,"%s: %s: Corrupted file format.\n",argv[0],mname);
+ exit(EXIT_FAILURE);
+ }
+ if (!(pdata = malloc(nrecs * sizeof(struct profdata)))) {
+ fprintf(stderr,"%s: Not enough memory!\n",argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* fill profdata array */
+ for (i=0,p=buf,pd=pdata; i<nrecs; i++,pd++) {
+ pd->funcname = p;
+ p = skipname(p);
+ pd->ncalls = *(unsigned long *)p;
+ pd->tottime = *(unsigned long *)(p+sizeof(unsigned long));
+ pd->loctime = *(unsigned long *)(p+2*sizeof(unsigned long));
+ p += 3*sizeof(unsigned long);
+ }
+
+ /* display */
+ show_local(pdata,nrecs);
+ }
+ else {
+ fprintf(stderr,"%s: Can't open %s.\n",argv[0],mname);
+ exit(EXIT_FAILURE);
+ }
+
+ return 0;
+}
diff --git a/vsc/vsc.c b/vsc/vsc.c
new file mode 100755
index 0000000..9fc9a25
--- /dev/null
+++ b/vsc/vsc.c
@@ -0,0 +1,239 @@
+/* vsc - portable instruction scheduler for vbcc. */
+/* (c) 1997-99 by Volker Barthelmann. */
+
+#include "vsc.h"
+
+char vs_copyright[]="vsc scheduler V0.1 (c) 1997-99 by Volker Barthelmann";
+
+#define MAX_INS 128
+#define LINELENGTH 1024
+
+#ifndef DEBUG
+int DEBUG;
+#endif
+
+struct sinfo silist[MAX_INS];
+int si_count;
+int done;
+
+int bvcmp(unsigned char *dest,unsigned char *src,size_t len)
+/* vergleicht zwei Bitvektoren */
+{
+ for(;len>0;len--)
+ if(*dest++!=*src++) return(0);
+ return(1);
+}
+void bvunite(unsigned char *dest,unsigned char *src,size_t len)
+/* berechnet Vereinigung zweier Bitvektoren */
+{
+ for(;len>0;len--)
+ *dest++|=*src++;
+}
+void bvintersect(unsigned char *dest,unsigned char *src,size_t len)
+/* berechnet Durchschnitt zweier Bitvektoren */
+{
+ for(;len>0;len--)
+ *dest++&=*src++;
+}
+void bvdiff(unsigned char *dest,unsigned char *src,size_t len)
+/* berechnet 'Differenz' zweier Bitvektoren */
+{
+ for(;len>0;len--)
+ *dest++&=~(*src++);
+}
+
+void raus(void)
+{
+ sched_cleanup();
+ if(DEBUG&1) printf("raus\n");
+ if(done)
+ exit(EXIT_SUCCESS);
+ else
+ exit(EXIT_FAILURE);
+}
+void *mymalloc(size_t sz)
+{
+ void *p=malloc(sz);
+ if(!p){
+ puts("Out of memory!");
+ raus();
+ }
+ return p;
+}
+void print_sinfo(void)
+{
+ struct sinfo *p;int i,j;
+ if(DEBUG&2)
+ printf("print_sinfo\n");
+ else
+ return;
+ for(j=0;j<si_count;j++){
+ p=&silist[j];
+ printf("inst: %s",p->txt);
+ printf("flags=%u, label=%u latency=%u\n",p->flags,p->label,p->latency);
+ printf("available pipelines: ");
+ for(i=0;i<PIPES;i++)
+ if(BTST(p->pipes,i))
+ printf("%d ",i);
+ printf("\nuses registers (%d=mem): ",MEM);
+ for(i=0;i<=MEM;i++)
+ if(BTST(p->uses,i))
+ printf("%d ",i);
+ printf("\nmodifies registers (%d=MEM): ",MEM);
+ for(i=0;i<=MEM;i++)
+ if(BTST(p->modifies,i))
+ printf("%d ",i);
+ printf("\n\n");
+ }
+}
+void free_sinfo(void)
+{
+ int j;
+ for(j=0;j<si_count;j++)
+ free(silist[j].txt);
+}
+void output_scheduled(FILE *f)
+{
+ int pipes[PIPES],i,j,k,l,remaining;
+ int latency[MEM+1]={0},cycle=0;
+ unsigned char used[REGS_SIZE],modified[REGS_SIZE],tmp[REGS_SIZE],empty[REGS_SIZE]={0};
+ remaining=si_count;
+ if(DEBUG&2) print_sinfo();
+ while(remaining){
+ cycle++;
+ if(DEBUG&4){
+ printf("cycle %d\n",cycle);
+ for(i=0;i<=MEM;i++)
+ if(latency[i]>0) printf("latency[%d]=%d\n",i,latency[i]);
+ }
+ /* Mark all instructions which are ready. */
+ memset(modified,0,REGS_SIZE);
+ memset(used,0,REGS_SIZE);
+ for(i=0;i<si_count;i++){
+ if(silist[i].flags&OUT) continue;
+ memcpy(tmp,silist[i].uses,REGS_SIZE);
+ bvunite(tmp,silist[i].modifies,REGS_SIZE);
+ bvintersect(tmp,modified,REGS_SIZE);
+ if(bvcmp(tmp,empty,REGS_SIZE)){
+ /* uses and modifies nothing that has to be modified before */
+ memcpy(tmp,used,REGS_SIZE);
+ bvintersect(tmp,silist[i].modifies,REGS_SIZE);
+ if(bvcmp(tmp,empty,REGS_SIZE)){
+ /* modifies nothing that has to be used before */
+ for(k=0,j=0;j<=MEM;j++){
+ if(BTST(silist[i].uses,j)&&latency[j]>0) k=1;
+ }
+ if(!k) silist[i].flags|=READY;
+ }
+ }
+ bvunite(modified,silist[i].modifies,REGS_SIZE);
+ bvunite(used,silist[i].uses,REGS_SIZE);
+ }
+
+ /* Fill pipeline slots with ready instructions. */
+ for(i=0;i<PIPES;i++) pipes[i]=-1;
+ for(i=0;i<si_count;i++){
+ if(silist[i].flags&OUT) continue;
+ if(!(silist[i].flags&READY)) continue;
+ if(DEBUG&4) printf("inst ready: %s",silist[i].txt);
+ k=0;
+ /* Is there a free slot? */
+ for(j=0;!k&&j<PIPES;j++){
+ if(pipes[j]<0&&BTST(silist[i].pipes,j)){
+ pipes[j]=i;
+ k=1;
+ }
+ }
+ /* Replace a scheduled instruction with smaller latency. */
+ for(j=0;!k&&j<PIPES;j++){
+ if(BTST(silist[i].pipes,j)&&silist[i].latency>silist[pipes[j]].latency){
+ pipes[j]=i;
+ k=1;
+ }
+ }
+ }
+ if(DEBUG&4) printf("instructions for cycle %d:\n",cycle);
+ for(i=0;i<PIPES;i++){
+ if(pipes[i]>=0){
+ if(DEBUG&4) printf("%3d: %s",i,silist[pipes[i]].txt);
+ fprintf(f,"%s",silist[pipes[i]].txt);
+ silist[pipes[i]].flags|=OUT;
+ remaining--;
+ for(j=0;j<=MEM;j++){
+ if(BTST(silist[pipes[i]].modifies,j)) latency[j]=silist[pipes[i]].latency;
+ }
+ }
+ }
+ for(i=0;i<=MEM;i++)
+ if(latency[i]>0) latency[i]--;
+ }
+}
+int main(int argc,char *argv[])
+{
+ char s[LINELENGTH];int i,quiet=0;
+ FILE *in,*out; char *inname=0,*outname=0;
+ for(i=1;i<argc;i++){
+ if(*argv[i]!='-'){
+ if(!inname){
+ inname=argv[i];
+ }else{
+ if(outname){
+ printf("Only one input file allowed\n");
+ raus();
+ }else{
+ outname=argv[i];
+ }
+ }
+ }else{
+ if(!strcmp("-quiet",argv[i])) {quiet=1;continue;}
+#ifndef DEBUG
+ if(!strncmp("-debug=",argv[i],7)){DEBUG=atoi(argv[i]+7);continue;}
+#endif
+ printf("Unknown option \"%s\"\n",argv[i]);
+ raus();
+ }
+ }
+ if(!sched_init()){printf("sched_init failed\n");raus();}
+ if(!quiet){
+#ifdef SPECIAL_COPYRIGHT
+ printf("%s\n",SPECIAL_COPYRIGHT);
+#else
+ printf("%s\n%s\n",vs_copyright,tg_copyright);
+#endif
+ }
+ if(!inname){printf("No input file\n");raus();}
+ if(!outname){printf("No output file\n");raus();}
+ in=fopen(inname,"r");
+ if(!in){printf("Could not open input file \"%s\"\n",inname);raus();}
+ out=fopen(outname,"w");
+ if(!out){printf("Could not open output file \"%s\"\n",outname);raus();}
+ while(fgets(s,LINELENGTH-1,in)){
+ memset(&silist[si_count],0,sizeof(silist[0]));
+ silist[si_count].txt=mymalloc(strlen(s)+1);
+ strcpy(silist[si_count].txt,s);
+ if(!sched_info(&silist[si_count])){
+ printf("Do not understand instruction:\n%s\n",silist[si_count].txt);
+ raus();
+ }
+ if(silist[si_count].flags&(BARRIER|LABEL|COND_BRANCH|UNCOND_BRANCH)){
+ if(DEBUG&1) printf("Barrier: %s",silist[si_count].txt);
+ output_scheduled(out);
+ free_sinfo();
+ fprintf(out,silist[si_count].txt);
+ si_count=0;
+ }else{
+ if(++si_count>=MAX_INS){
+ if(DEBUG&1) printf("MAX_INS reached: %s",silist[si_count].txt);
+ output_scheduled(out);
+ free_sinfo();
+ si_count=0;
+ }
+ }
+ }
+ output_scheduled(out);
+ free_sinfo();
+ done=1;
+ raus();
+}
+
+
diff --git a/vsc/vsc.h b/vsc/vsc.h
new file mode 100755
index 0000000..468d592
--- /dev/null
+++ b/vsc/vsc.h
@@ -0,0 +1,121 @@
+/* vsc portable scheduler (c) 1997-99 by Volker Barthelmann */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#define BSET(array,bit) (array)[(bit)/CHAR_BIT]|=1<<((bit)%CHAR_BIT)
+#define BCLR(array,bit) (array)[(bit)/CHAR_BIT]&=~(1<<((bit)%CHAR_BIT))
+#define BTST(array,bit) ((array)[(bit)/CHAR_BIT]&(1<<((bit)%CHAR_BIT)))
+
+/* An instruction with LABEL set is preceded with a numbered label. */
+/* The number is in <label>. */
+#define LABEL 1
+
+/* An instrution with COND_BRANCH set may be followed by the next */
+/* instruction or by the instruction with the label in <label>. */
+#define COND_BRANCH 2
+
+/* An instruction with UNCOND_BRANCH set is followed by the */
+/* instruction with the label in <label>. */
+#define UNCOND_BRANCH 4
+
+/* The side-effects of an instruction with BARRIER set cannot entirely */
+/* be specified by a struct sinfo (e.g. function-calls, pseudo-ops or */
+/* other complicated things). vsc will not move any code across this */
+/* instruction. */
+#define BARRIER 8
+
+/* An instruction with neither COND_BRANCH, UNCOND_BRANCH nor BARRIER */
+/* set _must_ _not_ change control-flow. */
+
+/* Used by vsched.c. */
+#define OUT 16
+#define READY 32
+
+/* schedule.h has to #define REGS (the maximum number of registers */
+/* (numbered from 0 to REGS-1) and the maximum number of pipelines */
+/* PIPES (numbered from 0 to PIPES-1). If multiple CPUs with */
+/* different numbers of pipelines or registers are supported the */
+/* largest number must be specified. The CPU-differences must be */
+/* represented by the information provided by sched_info(). */
+#include "schedule.h"
+
+/* MEM is a pseudo-register used to indicate that memory is */
+/* accessed. */
+#define MEM REGS
+
+#define PIPES_SIZE ((PIPES+CHAR_BIT-1)/CHAR_BIT*CHAR_BIT)
+#define REGS_SIZE ((MEM+1+CHAR_BIT-1)/CHAR_BIT*CHAR_BIT)
+
+/* The struct to hold scheduling-information on an instruction. */
+struct sinfo {
+ /* The instruction in assembly-language. */
+ char *txt;
+
+ /* A combination of the flags mentioned above. */
+ unsigned int flags;
+
+ /* A numbered label used with LABEL, COND_BRANCH and UNCOND_BRANCH. */
+ unsigned int label;
+
+ /* Number of cycles until all side-effects of the operation are */
+ /* completed. */
+ unsigned int latency;
+
+ /* Bit-vector which contains 1s for every pipeline which can execute */
+ /* this instruction. */
+ unsigned char pipes[PIPES_SIZE];
+
+ /* Bit-vector which contains 1s for every register that is used by */
+ /* this instruction. Use pseudo-register MEM if it reads memory. */
+ unsigned char uses[REGS_SIZE];
+
+ /* Bit-vector which contains 1s for every register that is modified */
+ /* by this instruction. Use pseudo-register MEM if it writes memory. */
+ unsigned char modifies[REGS_SIZE];
+
+ /* An ID which identifies the memory-object which is read. 0 means */
+ /* no further information available. Two accesses with different IDs */
+ /* are guaranteed not to access the same memory. */
+ unsigned long memread_id;
+
+ /* An ID which identifies the memory-object which is written. 0 means */
+ /* no further information available. Two accesses with different IDs */
+ /* are guaranteed not to access the same memory. */
+ unsigned long memwrite_id;
+
+ /* If this flag is set to 1 then the write to the object with the */
+ /* ID specified by memwrite_id completely overwrites the object. */
+ unsigned int memwrite_completely;
+};
+
+
+/* Target-specific data which must be provided by schedule.c. */
+
+/* Copyright notice which is printed if -quiet is not specified. */
+extern char tg_copyright[];
+
+
+/* Target-specific functions which must be provided by schedule.c */
+
+/* This function allows some initializations to be done. If */
+/* zero is returned vsc assumes an error has happened and aborts. */
+extern int sched_init(void);
+
+/* This function allows some cleanup before vsc exits. */
+extern void sched_cleanup(void);
+
+/* This is the main target-specific function. It will be called with */
+/* a pointer to a struct sinfo that is set to binary zeroes except */
+/* for the member <txt> which points to the assembly representation */
+/* of the instruction. */
+/* sched_info() has to fill in all the other members with information */
+/* that correctly represents the instruction. */
+/* If the BARRIER-flag is set all other informations are basically */
+/* irrelevant. */
+extern int sched_info(struct sinfo *);
+
+
+