From: David Given Date: Tue, 15 Mar 2016 20:13:07 +0000 (+0100) Subject: Clean import of pcc. X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=ed9ce6a8bb11b17b9beaeff3f48fe54f0f2e2948;p=ack.git Clean import of pcc. --HG-- branch : default-branch --- diff --git a/lang/pcc/UPSTREAM_VERSION b/lang/pcc/UPSTREAM_VERSION new file mode 100644 index 000000000..df6ac44d1 --- /dev/null +++ b/lang/pcc/UPSTREAM_VERSION @@ -0,0 +1,2 @@ +ftp://pcc.ludd.ltu.se/pub/pcc/pcc-20160315.tgz + diff --git a/lang/pcc/pcc/DATESTAMP b/lang/pcc/pcc/DATESTAMP new file mode 100644 index 000000000..4ed5216e5 --- /dev/null +++ b/lang/pcc/pcc/DATESTAMP @@ -0,0 +1 @@ +20160315 diff --git a/lang/pcc/pcc/Makefile.in b/lang/pcc/pcc/Makefile.in new file mode 100644 index 000000000..1123e1a39 --- /dev/null +++ b/lang/pcc/pcc/Makefile.in @@ -0,0 +1,29 @@ +# $Id: Makefile.in,v 1.9 2011/06/07 13:56:05 plunky Exp $ +# +# Makefile.in for top-level of pcc. +# + +@SET_MAKE@ + +ALL_SUBDIRS= cc +DIST_SUBDIRS= $(ALL_SUBDIRS) f77 + +all install clean: + @for subdir in $(ALL_SUBDIRS); do \ + _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ + echo "===> $$_nextdir_"; \ + (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ + exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ + echo "<=== $$_nextdir_"; \ + done + +distclean: + @for subdir in $(DIST_SUBDIRS); do \ + _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ + echo "===> $$_nextdir_"; \ + (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ + exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ + echo "<=== $$_nextdir_"; \ + done + rm -rf Makefile config.log stamp-h1 config.status \ + configure.lineno config.h autom4te.cache diff --git a/lang/pcc/pcc/arch/amd64/code.c b/lang/pcc/pcc/arch/amd64/code.c new file mode 100644 index 000000000..673b750f1 --- /dev/null +++ b/lang/pcc/pcc/arch/amd64/code.c @@ -0,0 +1,1253 @@ +/* $Id: code.c,v 1.85 2015/12/13 09:00:04 ragge Exp $ */ +/* + * Copyright (c) 2008 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#ifndef LANG_CXX +#undef NIL +#define NIL NULL +#define NODE P1ND +#define nfree p1nfree +#define ccopy p1tcopy +#define tfree p1tfree +#endif + +static int nsse, ngpr, nrsp, rsaoff; +static int thissse, thisgpr, thisrsp; +enum { INTEGER = 1, INTMEM, SSE, SSEMEM, X87, + STRREG, STRMEM, STRSSE, STRIF, STRFI, STRX87 }; +static const int argregsi[] = { RDI, RSI, RDX, RCX, R08, R09 }; +/* + * The Register Save Area looks something like this. + * It is put first on stack with fixed offsets. + * struct { + * long regs[6]; + * double xmm[8][2]; // 16 byte in width + * }; + */ +#define RSASZ (6*SZLONG+8*2*SZDOUBLE) +#define RSALONGOFF(x) (RSASZ-(x)*SZLONG) +#define RSADBLOFF(x) ((8*2*SZDOUBLE)-(x)*SZDOUBLE*2) +/* va_list */ +#define VAARGSZ (SZINT*2+SZPOINT(CHAR)*2) +#define VAGPOFF(x) (x) +#define VAFPOFF(x) (x-SZINT) +#define VAOFA(x) (x-SZINT-SZINT) +#define VARSA(x) (x-SZINT-SZINT-SZPOINT(0)) + +static int stroffset; + +static int varneeds; +#define NEED_1FPREF 001 +#define NEED_2FPREF 002 +#define NEED_1REGREF 004 +#define NEED_2REGREF 010 +#define NEED_MEMREF 020 +#define NEED_STRFI 040 +#define NEED_STRIF 0100 + +static int argtyp(TWORD t, union dimfun *df, struct attr *ap); +static NODE *movtomem(NODE *p, int off, int reg); +static NODE *movtoreg(NODE *p, int rno); +void varattrib(char *name, struct attr *sap); + +/* + * Print out assembler segment name. + */ +#ifdef MACHOABI +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + case DATA: + case LDATA: name = ".data"; break; + case RDATA: name = ".const"; break; + case STRNG: name = ".cstring"; break; + case UDATA: break; + case CTORS: name = ".mod_init_func"; break; + case DTORS: name = ".mod_term_func"; break; + default: + cerror("unknown seg %d", seg); + } + printf("\t%s\n", name); +} + +#else +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + case DATA: + case LDATA: name = ".data"; break; + case STRNG: + case RDATA: name = ".section .rodata"; break; + case UDATA: break; + case PICLDATA: + case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; + case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; + case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; + case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; + case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; + case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; + case NMSEG: + printf("\t.section %s,\"a%c\",@progbits\n", name, + cftnsp ? 'x' : 'w'); + return; + } + printf("\t%s\n", name); +} +#endif + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + char *name; + + name = getexname(sp); + + if (sp->sclass == EXTDEF) { + printf("\t.globl %s\n", name); +#ifndef MACHOABI + if (ISFTN(sp->stype)) { + printf("\t.type %s,@function\n", name); + } else { + printf("\t.type %s,@object\n", name); + printf("\t.size %s,%d\n", name, + (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR); + } +#endif + } + if (sp->slevel == 0) + printf("%s:\n", name); + else + printf(LABFMT ":\n", sp->soffset); +} + +/* + * code for the end of a function + * deals with struct return here + * The return value is in (or pointed to by) RETREG. + */ +void +efcode(void) +{ + struct symtab *sp; + extern int gotnr; + TWORD t; + NODE *p, *r, *l; + int typ; + + gotnr = 0; /* new number for next fun */ + sp = cftnsp; + t = DECREF(sp->stype); + if (t != STRTY && t != UNIONTY) + return; + + /* XXX should have one routine for this */ + ngpr = nsse = 0; + typ = argtyp(t, sp->sdf, sp->sap); + if (typ == STRMEM) { + r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap); + regno(r) = RAX; + r = buildtree(UMUL, r, NIL); + l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap); + l = buildtree(UMUL, l, NIL); + ecomp(buildtree(ASSIGN, l, r)); + l = block(REG, NIL, NIL, LONG, 0, 0); + regno(l) = RAX; + r = tempnode(stroffset, LONG, 0, 0); + ecomp(buildtree(ASSIGN, l, r)); + } else if (typ == STRX87) { + p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0); + regno(p) = RAX; + p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL); + ecomp(movtoreg(p, 041)); + p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0); + regno(p) = RAX; + p = buildtree(UMUL, p, NIL); + ecomp(movtoreg(p, 040)); + } else { + TWORD t1, t2; + int r1, r2; + if (typ == STRSSE || typ == STRFI) + r1 = XMM0, t1 = DOUBLE; + else + r1 = RAX, t1 = LONG; + if (typ == STRSSE) + r2 = XMM1, t2 = DOUBLE; + else if (typ == STRFI) + r2 = RAX, t2 = LONG; + else if (typ == STRIF) + r2 = XMM0, t2 = DOUBLE; + else /* if (typ == STRREG) */ + r2 = RDX, t2 = LONG; + + if (tsize(t, sp->sdf, sp->sap) > SZLONG) { + p = block(REG, NIL, NIL, INCREF(t2), 0, 0); + regno(p) = RAX; + p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL); + ecomp(movtoreg(p, r2)); + } + p = block(REG, NIL, NIL, INCREF(t1), 0, 0); + regno(p) = RAX; + p = buildtree(UMUL, p, NIL); + ecomp(movtoreg(p, r1)); + } +} + +/* + * code for the beginning of a function; a is an array of + * indices in symtab for the arguments; n is the number + */ +void +bfcode(struct symtab **s, int cnt) +{ + union arglist *al; + struct symtab *sp; + NODE *p, *r; + TWORD t; + int i, rno, typ, ssz; + + /* recalculate the arg offset and create TEMP moves */ + /* Always do this for reg, even if not optimizing, to free arg regs */ + nsse = ngpr = 0; + nrsp = ARGINIT; + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + sp = cftnsp; + if (argtyp(DECREF(sp->stype), sp->sdf, sp->sap) == STRMEM) { + r = block(REG, NIL, NIL, LONG, 0, 0); + regno(r) = argregsi[ngpr++]; + p = tempnode(0, r->n_type, r->n_df, r->n_ap); + stroffset = regno(p); + ecomp(buildtree(ASSIGN, p, r)); + } + } + + for (i = 0; i < cnt; i++) { + sp = s[i]; + + if (sp == NULL) + continue; /* XXX when happens this? */ + + ssz = tsize(sp->stype, sp->sdf, sp->sap); + switch (typ = argtyp(sp->stype, sp->sdf, sp->sap)) { + case INTEGER: + case SSE: + if (typ == SSE) + rno = XMM0 + nsse++; + else + rno = argregsi[ngpr++]; + r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->sap); + regno(r) = rno; + p = tempnode(0, sp->stype, sp->sdf, sp->sap); + sp->soffset = regno(p); + sp->sflags |= STNODE; + ecomp(buildtree(ASSIGN, p, r)); + break; + + case SSEMEM: + sp->soffset = nrsp; + nrsp += SZDOUBLE; + if (xtemps) { + p = tempnode(0, sp->stype, sp->sdf, sp->sap); + p = buildtree(ASSIGN, p, nametree(sp)); + sp->soffset = regno(p->n_left); + sp->sflags |= STNODE; + ecomp(p); + } + break; + + case INTMEM: + sp->soffset = nrsp; + nrsp += SZLONG; + if (xtemps) { + p = tempnode(0, sp->stype, sp->sdf, sp->sap); + p = buildtree(ASSIGN, p, nametree(sp)); + sp->soffset = regno(p->n_left); + sp->sflags |= STNODE; + ecomp(p); + } + break; + + case STRX87: + case STRMEM: /* Struct in memory */ + sp->soffset = nrsp; + nrsp += ssz; + break; + + case X87: /* long double args */ + sp->soffset = nrsp; + nrsp += SZLDOUBLE; + break; + + case STRFI: + case STRIF: + case STRSSE: + case STRREG: /* Struct in register */ + autooff += (2*SZLONG); + + if (typ == STRSSE || typ == STRFI) { + rno = XMM0 + nsse++; + t = DOUBLE; + } else { + rno = argregsi[ngpr++]; + t = LONG; + } + r = block(REG, NIL, NIL, t, 0, 0); + regno(r) = rno; + ecomp(movtomem(r, -autooff, FPREG)); + + if (ssz > SZLONG) { + if (typ == STRSSE || typ == STRIF) { + rno = XMM0 + nsse++; + t = DOUBLE; + } else { + rno = argregsi[ngpr++]; + t = LONG; + } + r = block(REG, NIL, NIL, t, 0, 0); + regno(r) = rno; + ecomp(movtomem(r, -autooff+SZLONG, FPREG)); + } + sp->soffset = -autooff; + break; + + default: + cerror("bfcode: %d", typ); + } + } + + /* Check if there are varargs */ + if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL) + return; /* no prototype */ + al = cftnsp->sdf->dfun; + + for (; al->type != TELLIPSIS; al++) { + t = al->type; + if (t == TNULL) + return; + if (ISSOU(BTYPE(t))) + al++; + for (i = 0; t > BTMASK; t = DECREF(t)) + if (ISARY(t) || ISFTN(t)) + i++; + if (i) + al++; + } + + /* fix stack offset */ + SETOFF(autooff, ALMAX); + + /* Save reg arguments in the reg save area */ + p = NIL; + for (i = ngpr; i < 6; i++) { + r = block(REG, NIL, NIL, LONG, 0, 0); + regno(r) = argregsi[i]; + r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG); + p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0)); + } + for (i = nsse; i < 8; i++) { + r = block(REG, NIL, NIL, DOUBLE, 0, 0); + regno(r) = i + XMM0; + r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG); + p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0)); + } + autooff += RSASZ; + rsaoff = autooff; + thissse = nsse; + thisgpr = ngpr; + thisrsp = nrsp; + + ecomp(p); +} + + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ + if (flag) + return; + +#ifdef MACHOABI +#define PT(x) +#else +#define PT(x) printf(".type __pcc_" x ",@function\n") +#endif + +#define P(x) printf(x "\n") + /* printout varargs routines if used */ + if (varneeds & NEED_STRFI) { /* struct with one float and then int */ + P(".text\n.align 4"); + PT("strif"); + P("__pcc_strif:"); + P("cmpl $176,4(%%rdi)\njae .Ladd16"); + P("cmpl $48,(%%rdi)\njae .Ladd16\n"); + P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax"); + P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)"); + P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax"); + P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)"); + P("leaq 24(%%rdi),%%rax\nret"); + } + if (varneeds & NEED_STRIF) { /* struct with one int and one float */ + P(".text\n.align 4"); + PT("strif"); + P("__pcc_strif:"); + P("cmpl $176,4(%%rdi)\njae .Ladd16"); + P("cmpl $48,(%%rdi)\njae .Ladd16\n"); + P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax"); + P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)"); + P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax"); + P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)"); + P("leaq 24(%%rdi),%%rax\nret"); + } + if (varneeds & NEED_2FPREF) { /* struct with two float regs */ + P(".text\n.align 4"); + PT("2fpref"); + P("__pcc_2fpref:"); + P("cmpl $160,4(%%rdi)\njae .Ladd16"); + P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax"); + P("addl $32,4(%%rdi)"); + P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)"); + P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)"); + P("leaq 24(%%rdi),%%rax\nret"); + } + if (varneeds & NEED_1FPREF) { + printf(".text\n.align 4\n"); + PT("1fpref"); + printf("__pcc_1fpref:\n"); + printf("cmpl $176,4(%%rdi)\njae .Ladd8\n"); + printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n"); + printf("addl $16,4(%%rdi)\nret\n"); + } + if (varneeds & NEED_1REGREF) { + printf(".text\n.align 4\n"); + PT("1regref"); + printf("__pcc_1regref:\n"); + printf("cmpl $48,(%%rdi)\njae .Ladd8\n"); + printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n"); + printf("addl $8,(%%rdi)\nret\n"); + } + if (varneeds & NEED_2REGREF) { + printf(".text\n.align 4\n"); + PT("2regref"); + printf("__pcc_2regref:\n"); + printf("cmpl $40,(%%rdi)\njae .Ladd16\n"); + printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n"); + printf("addl $16,(%%rdi)\nret\n"); + } + if (varneeds & NEED_MEMREF) { + printf(".text\n.align 4\n"); + PT("memref"); + printf("__pcc_memref:\n"); + printf("movq 8(%%rdi),%%rax\n"); + printf("addq %%rsi,8(%%rdi)\nret\n"); + } + + if (varneeds & (NEED_1FPREF|NEED_1REGREF)) { + P(".Ladd8:"); + P("movq 8(%%rdi),%%rax"); + P("addq $8,8(%%rdi)"); + P("ret"); + } + if (varneeds & (NEED_2FPREF|NEED_2REGREF|NEED_STRFI|NEED_STRIF)) { + P(".Ladd16:"); + P("movq 8(%%rdi),%%rax"); + P("addq $16,8(%%rdi)"); + P("ret"); + } + +#ifdef MACHOABI + printf("\t.ident \"PCC: %s\"\n", VERSSTR); +#else + printf("\t.ident \"PCC: %s\"\n\t.end\n", VERSSTR); +#endif +} + +/* + * Varargs stuff: + * The ABI says that va_list should be declared as this typedef. + * We handcraft it here and then just reference it. + * + * typedef struct { + * unsigned int gp_offset; + * unsigned int fp_offset; + * void *overflow_arg_area; + * void *reg_save_area; + * } __builtin_va_list[1]; + * + * ...actually, we allocate two of them and use the second one as + * bounce buffers for floating point structs... + * + * There are a number of asm routines printed out if varargs are used: + * long __pcc_gpnext(va) - get a gpreg value + * long __pcc_fpnext(va) - get a fpreg value + * void *__pcc_1regref(va) - get reference to a onereg struct + * void *__pcc_2regref(va) - get reference to a tworeg struct + * void *__pcc_memref(va,sz) - get reference to a large struct + */ + +static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area; +static char *_1fpref, *_2fpref, *_1regref, *_2regref, *memref; +static char *strif, *strfi; + +void +bjobcode(void) +{ + struct symtab *sp; + struct rstack *rp; + NODE *p, *q; + char *c; + +#if defined(__GNUC__) || defined(__PCC__) + /* Be sure that the compiler uses full x87 */ + /* XXX cross-compiling will fail here */ + int fcw = 0; + __asm("fstcw (%0)" : : "r"(&fcw)); + fcw |= 0x33f; + __asm("fldcw (%0)" : : "r"(&fcw)); +#endif + + /* amd64 names for some asm constant printouts */ + astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; + astypnames[LONG] = astypnames[ULONG] = "\t.quad"; + + gp_offset = addname("gp_offset"); + fp_offset = addname("fp_offset"); + overflow_arg_area = addname("overflow_arg_area"); + reg_save_area = addname("reg_save_area"); + + rp = bstruct(NULL, STNAME, NULL); + p = block(NAME, NIL, NIL, UNSIGNED, 0, 0); + soumemb(p, gp_offset, 0); + soumemb(p, fp_offset, 0); + p->n_type = VOID+PTR; + p->n_ap = NULL; + soumemb(p, overflow_arg_area, 0); + soumemb(p, reg_save_area, 0); + nfree(p); + q = dclstruct(rp); + c = addname("__builtin_va_list"); + p = block(LB, bdty(NAME, c), bcon(2), INT, 0, 0); + p = tymerge(q, p); + p->n_sp = lookup(c, 0); + defid(p, TYPEDEF); + nfree(q); + nfree(p); + + /* for the static varargs functions */ +#define MKN(vn, rn) \ + { vn = addname(rn); sp = lookup(vn, SNORMAL); \ + sp->sclass = USTATIC; sp->stype = FTN|VOID|(PTR<n_left; + r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area), + mkstkref(-rsaoff, VOID)); + r = buildtree(COMOP, r, + buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area), + mkstkref(thisrsp, VOID))); + r = buildtree(COMOP, r, + buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset), + bcon(thisgpr*(SZLONG/SZCHAR)))); + r = buildtree(COMOP, r, + buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset), + bcon(thissse*(SZDOUBLE*2/SZCHAR)+48))); + + tfree(a); + return r; +} + +static NODE * +mkvacall(char *fun, NODE *a, int typ) +{ + NODE *r, *f = block(NAME, NIL, NIL, INT, 0, 0); + NODE *ap = a->n_left; + NODE *dp = a->n_right; + int sz = tsize(dp->n_type, dp->n_df, dp->n_ap); + + f->n_sp = lookup(fun, SNORMAL); + varneeds |= typ; + f->n_type = f->n_sp->stype; + f = clocal(f); + SETOFF(sz, ALLONG); + r = buildtree(CALL, f, + buildtree(CM, ccopy(ap), bcon(sz/SZCHAR))); + r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap); + r = buildtree(UMUL, r, NIL); + return r; +} + +NODE * +amd64_builtin_va_arg(const struct bitable *bt, NODE *a) +{ + NODE *r, *dp; + int typ, sz; + + dp = a->n_right; + + nsse = ngpr = 0; + sz = tsize(dp->n_type, dp->n_df, dp->n_ap); + switch (typ = argtyp(dp->n_type, dp->n_df, dp->n_ap)) { + case INTEGER: + r = mkvacall(_1regref, a, NEED_1REGREF); + break; + + case SSE: + r = mkvacall(_1fpref, a, NEED_1FPREF); + break; + + default: + cerror("va_arg: bad type %d", typ); + + case X87: + case STRX87: + case STRMEM: /* stored in memory */ + r = mkvacall(memref, a, NEED_MEMREF); + break; + + case STRREG: /* struct in general regs */ + if (sz <= SZLONG) + r = mkvacall(_1regref, a, NEED_1REGREF); + else + r = mkvacall(_2regref, a, NEED_2REGREF); + break; + + case STRSSE: + if (sz <= SZLONG) + r = mkvacall(_1fpref, a, NEED_1FPREF); + else + r = mkvacall(_2fpref, a, NEED_2FPREF); + break; + + case STRIF: + r = mkvacall(strif, a, NEED_STRIF); + break; + + case STRFI: + r = mkvacall(strfi, a, NEED_STRFI); + break; + } + + tfree(a); + return r; +} + +NODE * +amd64_builtin_va_end(const struct bitable *bt, NODE *a) +{ + tfree(a); + return bcon(0); /* nothing */ +} + +NODE * +amd64_builtin_va_copy(const struct bitable *bt, NODE *a) +{ + NODE *f; + + f = buildtree(ASSIGN, buildtree(UMUL, a->n_left, NIL), + buildtree(UMUL, a->n_right, NIL)); + nfree(a); + return f; +} + +static NODE * +movtoreg(NODE *p, int rno) +{ + NODE *r; + + r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); + regno(r) = rno; + return clocal(buildtree(ASSIGN, r, p)); +} + +static NODE * +movtomem(NODE *p, int off, int reg) +{ + struct symtab s; + NODE *r, *l; + + s.stype = p->n_type; + s.squal = 0; + s.sdf = p->n_df; + s.sap = p->n_ap; + s.soffset = off; + s.sclass = AUTO; + + l = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + slval(l, 0); + regno(l) = reg; + + r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap); + r->n_sp = &s; + r = stref(block(STREF, l, r, 0, 0, 0)); + + return clocal(buildtree(ASSIGN, r, p)); +} + +/* + * Check what to do with a struct. We traverse down in the struct to + * find which types it is and where the struct really should be. + * The return vals we may end up with are: + * STRREG - The whole struct is saved in general registers. + * STRMEM - the struct is saved in memory. + * STRSSE - the whole struct is saved in SSE registers. + * STRIF - First word of struct is saved in general reg, other SSE. + * STRFI - First word of struct is saved in SSE, next in general reg. + * + * - If size > 16 bytes or there are packed fields, use memory. + * - If any part of an eight-byte should be in a general register, + * the eight-byte is stored in a general register + * - If the eight-byte only contains float or double, use a SSE register + * - Otherwise use memory. + * + * Arrays must be broken up as separate elements, since the elements + * are classified separately. For example; + * struct s { short s; float f[3]; } S; + * will have the first 64 bits passed in general reg and the second in SSE. + * + * sp below is a pointer to a member list. + * off tells whether is is the first or second eight-byte to check. + */ +static int +classifystruct(struct symtab *sp, int off) +{ + struct symtab sps[16]; + union dimfun *df; + TWORD t; + int cl, cl2, sz, i; + + + for (cl = 0; sp; sp = sp->snext) { + t = sp->stype; + + /* fake a linked list of all array members */ + if (ISARY(t)) { + sz = 1; + df = sp->sdf; + do { + sz *= df->ddim; + t = DECREF(t); + df++; + } while (ISARY(t)); + for (i = 0; i < sz; i++) { + sps[i] = *sp; + sps[i].stype = t; + sps[i].sdf = df; + sps[i].snext = &sps[i+1]; + sps[i].soffset = i * tsize(t, df, sp->sap); + sps[i].soffset += sp->soffset; + } + sps[i-1].snext = sp->snext; + sp = &sps[0]; + } + + if (off == 0) { + if (sp->soffset >= SZLONG) + continue; + } else { + if (sp->soffset < SZLONG) + continue; + } + + if (t <= ULONGLONG || ISPTR(t)) { + if (cl == 0 || cl == STRSSE) + cl = STRREG; + } else if (t <= DOUBLE) { + if (cl == 0) + cl = STRSSE; + } else if (t == LDOUBLE) { + return STRMEM; + } else if (ISSOU(t)) { +#ifdef GCC_COMPAT + if (attr_find(sp->sap, GCC_ATYP_PACKED)) { + cl = STRMEM; + } else +#endif + { + cl2 = classifystruct(strmemb(sp->sap), off); + if (cl2 == STRMEM) { + cl = STRMEM; + } else if (cl2 == STRREG) { + if (cl == 0 || cl == STRSSE) + cl = STRREG; + } else if (cl2 == STRSSE) { + if (cl == 0) + cl = STRSSE; + } + } + } else + cerror("classifystruct: unknown type %x", t); + if (cl == STRMEM) + break; + } + if (cl == 0) + cerror("classifystruct: failed classify"); + return cl; +} + +/* + * Check for long double complex structs. + */ +static int +iscplx87(struct symtab *sp) +{ + if (sp->stype == LDOUBLE && sp->snext->stype == LDOUBLE && + sp->snext->snext == NULL) + return STRX87; + return 0; +} + +/* + * AMD64 parameter classification. + */ +static int +argtyp(TWORD t, union dimfun *df, struct attr *ap) +{ + int cl2, cl = 0; + + if (t <= ULONG || ISPTR(t) || t == BOOL) { + cl = ngpr < 6 ? INTEGER : INTMEM; + } else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) { + cl = nsse < 8 ? SSE : SSEMEM; + } else if (t == LDOUBLE || t == LIMAG) { + cl = X87; /* XXX */ + } else if (t == STRTY || t == UNIONTY) { + int sz = tsize(t, df, ap); + +#ifdef GCC_COMPAT + if (attr_find(ap, GCC_ATYP_PACKED)) { + cl = STRMEM; + } else +#endif + if (iscplx87(strmemb(ap)) == STRX87) { + cl = STRX87; + } else if (sz > 2*SZLONG) { + cl = STRMEM; + } else if (sz <= SZLONG) { + /* only one member to check */ + cl = classifystruct(strmemb(ap), 0); + if (cl == STRREG && ngpr > 5) + cl = STRMEM; + else if (cl == STRSSE && nsse > 7) + cl = STRMEM; + } else { + cl = classifystruct(strmemb(ap), 0); + cl2 = classifystruct(strmemb(ap), 1); + if (cl == STRMEM || cl2 == STRMEM) + cl = STRMEM; + else if (cl == STRREG && cl2 == STRSSE) + cl = STRIF; + else if (cl2 == STRREG && cl == STRSSE) + cl = STRFI; + + if (cl == STRREG && ngpr > 4) + cl = STRMEM; + else if (cl == STRSSE && nsse > 6) + cl = STRMEM; + else if ((cl == STRIF || cl == STRFI) && + (ngpr > 5 || nsse > 7)) + cl = STRMEM; + } + } else + cerror("FIXME: classify"); + return cl; +} + +/* + * Do the "hard work" in assigning correct destination for arguments. + * Also convert arguments < INT to inte (default argument promotions). + * XXX - should be dome elsewhere. + */ +static NODE * +argput(NODE *p) +{ + NODE *q, *ql; + TWORD ty; + int typ, r, ssz, rn; + + if (p->n_op == CM) { + p->n_left = argput(p->n_left); + p->n_right = argput(p->n_right); + return p; + } + + /* first arg may be struct return pointer */ + /* XXX - check if varargs; setup al */ + switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) { + case INTEGER: + case SSE: + if (typ == SSE) + r = XMM0 + nsse++; + else + r = argregsi[ngpr++]; + if (p->n_type < INT || p->n_type == BOOL) + p = cast(p, INT, 0); + p = movtoreg(p, r); + break; + + case X87: + r = nrsp; + nrsp += SZLDOUBLE; + p = movtomem(p, r, STKREG); + break; + + case SSEMEM: + r = nrsp; + nrsp += SZDOUBLE; + p = movtomem(p, r, STKREG); + break; + + case INTMEM: + r = nrsp; + nrsp += SZLONG; + if (p->n_type < INT || p->n_type == BOOL) + p = cast(p, INT, 0); + p = movtomem(p, r, STKREG); + break; + + case STRFI: + case STRIF: + case STRSSE: + case STRREG: /* Struct in registers */ + /* Cast to long/sse pointer and move to the registers */ + /* XXX can overrun struct size */ + ssz = tsize(p->n_type, p->n_df, p->n_ap); + + if (typ == STRSSE || typ == STRFI) { + r = XMM0 + nsse++; + ty = DOUBLE; + } else { + r = argregsi[ngpr++]; + ty = LONG; + } + + p = nfree(p); /* remove STARG */ + p = makety(p, PTR|ty, 0, 0, 0); + ql = tempnode(0, PTR|ty, 0, 0); + rn = regno(ql); + p = buildtree(ASSIGN, ql, p); + ql = tempnode(rn, PTR|ty, 0, 0); + ql = movtoreg(buildtree(UMUL, ql, NIL), r); + p = buildtree(COMOP, p, ql); + + if (ssz > SZLONG) { + if (typ == STRSSE || typ == STRIF) { + r = XMM0 + nsse++; + ty = DOUBLE; + } else { + r = argregsi[ngpr++]; + ty = LONG; + } + + ql = tempnode(rn, PTR|ty, 0, 0); + ql = buildtree(UMUL, buildtree(PLUS, ql, bcon(1)), NIL); + ql = movtoreg(ql, r); + + p = buildtree(CM, p, ql); + } + break; + + case STRX87: + case STRMEM: { + struct symtab s; + NODE *l, *t; + + q = buildtree(UMUL, p->n_left, NIL); + + s.stype = p->n_type; + s.squal = 0; + s.sdf = p->n_df; + s.sap = p->n_ap; + s.soffset = nrsp; + s.sclass = AUTO; + + nrsp += tsize(p->n_type, p->n_df, p->n_ap); + + l = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + slval(l, 0); + regno(l) = STKREG; + + t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap); + t->n_sp = &s; + t = stref(block(STREF, l, t, 0, 0, 0)); + + t = (buildtree(ASSIGN, t, q)); + nfree(p); + p = t->n_left; + nfree(t); + break; + } + + default: + cerror("argument %d", typ); + } + return p; +} + +/* + * Sort arglist so that register assignments ends up last. + */ +static int +argsort(NODE *p) +{ + NODE *q, *r; + int rv = 0; + + if (p->n_op != CM) { + if (p->n_op == ASSIGN && p->n_left->n_op == REG && + coptype(p->n_right->n_op) != LTYPE) { + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + r = ccopy(q); + p->n_right = buildtree(COMOP, + buildtree(ASSIGN, q, p->n_right), r); + } + return rv; + } + if (p->n_right->n_op == CM) { + /* fixup for small structs in regs */ + q = p->n_right->n_left; + p->n_right->n_left = p->n_left; + p->n_left = p->n_right; + p->n_right = p->n_left->n_right; + p->n_left->n_right = q; + } + if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG && + coptype(p->n_right->n_right->n_op) != LTYPE) { + /* move before everything to avoid reg trashing */ + q = tempnode(0, p->n_right->n_type, + p->n_right->n_df, p->n_right->n_ap); + r = ccopy(q); + p->n_right->n_right = buildtree(COMOP, + buildtree(ASSIGN, q, p->n_right->n_right), r); + } + if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) { + if (p->n_left->n_op == CM && + p->n_left->n_right->n_op == STASG) { + q = p->n_left->n_right; + p->n_left->n_right = p->n_right; + p->n_right = q; + rv = 1; + } else if (p->n_left->n_op == STASG) { + q = p->n_left; + p->n_left = p->n_right; + p->n_right = q; + rv = 1; + } + } + return rv | argsort(p->n_left); +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + * Returns p. + */ +NODE * +funcode(NODE *p) +{ + NODE *l, *r; + TWORD t; + int i; + + nsse = ngpr = nrsp = 0; + /* Check if hidden arg needed */ + /* If so, add it in pass2 */ + if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY || + l->n_type == INCREF(FTN)+UNIONTY) { + int ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap); + struct symtab *sp = strmemb(l->n_ap); + if (ssz == 2*SZLDOUBLE && sp->stype == LDOUBLE && + sp->snext->stype == LDOUBLE) + ; /* long complex struct */ + else if (ssz > 2*SZLONG) + ngpr++; + } + + /* Convert just regs to assign insn's */ + p->n_right = argput(p->n_right); + + /* Must sort arglist so that STASG ends up first */ + /* This avoids registers being clobbered */ + while (argsort(p->n_right)) + ; + /* Check if there are varargs */ + if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) { + ; /* Need RAX */ + } else { + union arglist *al = l->n_df->dfun; + + for (; al->type != TELLIPSIS; al++) { + if ((t = al->type) == TNULL) + return p; /* No need */ + if (ISSOU(BTYPE(t))) + al++; + for (i = 0; t > BTMASK; t = DECREF(t)) + if (ISARY(t) || ISFTN(t)) + i++; + if (i) + al++; + } + } + + /* Always emit number of SSE regs used */ + l = movtoreg(bcon(nsse), RAX); + if (p->n_right->n_op != CM) { + p->n_right = block(CM, l, p->n_right, INT, 0, 0); + } else { + for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left) + ; + r->n_left = block(CM, l, r->n_left, INT, 0, 0); + } + return p; +} + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + +/* + * Return return as given by a. + */ +NODE * +builtin_return_address(const struct bitable *bt, NODE *a) +{ + int nframes; + NODE *f; + + nframes = glval(a); + tfree(a); + + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + + while (nframes--) + f = block(UMUL, f, NIL, PTR+VOID, 0, 0); + + f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0); + f = buildtree(UMUL, f, NIL); + + return f; +} + +/* + * Return frame as given by a. + */ +NODE * +builtin_frame_address(const struct bitable *bt, NODE *a) +{ + int nframes; + NODE *f; + + nframes = glval(a); + tfree(a); + + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + + while (nframes--) + f = block(UMUL, f, NIL, PTR+VOID, 0, 0); + + return f; +} + +/* + * Return "canonical frame address". + */ +NODE * +builtin_cfa(const struct bitable *bt, NODE *a) +{ + NODE *f; + + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + return block(PLUS, f, bcon(16), INCREF(PTR+VOID), 0, 0); +} + +int codeatyp(NODE *); +int +codeatyp(NODE *p) +{ + TWORD t; + int typ; + + ngpr = nsse = 0; + t = DECREF(p->n_type); + if (ISSOU(t) == 0) { + p = p->n_left; + t = DECREF(DECREF(p->n_type)); + } + if (ISSOU(t) == 0) + cerror("codeatyp"); + typ = argtyp(t, p->n_df, p->n_ap); + return typ; +} diff --git a/lang/pcc/pcc/arch/amd64/local.c b/lang/pcc/pcc/arch/amd64/local.c new file mode 100644 index 000000000..b0cb31e5d --- /dev/null +++ b/lang/pcc/pcc/arch/amd64/local.c @@ -0,0 +1,945 @@ +/* $Id: local.c,v 1.96 2016/03/05 15:49:36 ragge Exp $ */ +/* + * Copyright (c) 2008 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#ifndef LANG_CXX +#define NODE P1ND +#define ccopy p1tcopy +#define tfree p1tfree +#define nfree p1nfree +#define fwalk p1fwalk +#define talloc p1alloc +#endif + +/* this file contains code which is dependent on the target machine */ + +/* + * Check if a constant is too large for a type. + */ +#ifdef notyet +static int +toolarge(TWORD t, CONSZ con) +{ + U_CONSZ ucon = con; + + switch (t) { + case ULONG: + case LONG: + case ULONGLONG: + case LONGLONG: + break; /* cannot be too large */ +#define SCHK(i) case i: if (con > MAX_##i || con < MIN_##i) return 1; break +#define UCHK(i) case i: if (ucon > MAX_##i) return 1; break + SCHK(INT); + SCHK(SHORT); + case BOOL: + SCHK(CHAR); + UCHK(UNSIGNED); + UCHK(USHORT); + UCHK(UCHAR); + default: + cerror("toolarge"); + } + return 0; +} +#endif + +static char * +getsoname(struct symtab *sp) +{ + struct attr *ap; + return (ap = attr_find(sp->sap, ATTR_SONAME)) ? + ap->sarg(0) : sp->sname; +} + + +#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) + +/* + * Make a symtab entry for PIC use. + */ +static struct symtab * +picsymtab(char *p, char *s, char *s2) +{ + struct symtab *sp = IALLOC(sizeof(struct symtab)); + size_t len = strlen(p) + strlen(s) + strlen(s2) + 1; + + sp->sname = IALLOC(len); + strlcpy(sp->sname, p, len); + strlcat(sp->sname, s, len); + strlcat(sp->sname, s2, len); + sp->sap = attr_new(ATTR_SONAME, 1); + sp->sap->sarg(0) = sp->sname; + sp->sclass = EXTERN; + sp->sflags = sp->slevel = 0; + return sp; +} + +int gotnr; /* tempnum for GOT register */ +int argstacksize; + +/* + * Create a reference for an extern variable or function. + */ +static NODE * +picext(NODE *p) +{ +#if defined(ELFABI) + + NODE *q; + struct symtab *sp; + char *c; + + if (p->n_sp->sflags & SBEENHERE) + return p; +#ifdef GCC_COMPAT + struct attr *ga; + if ((ga = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) && + strcmp(ga->sarg(0), "hidden") == 0) + return p; /* no GOT reference */ +#endif + + c = getexname(p->n_sp); + sp = picsymtab("", c, "@GOTPCREL"); + sp->sflags |= SBEENHERE; + q = block(NAME, NIL, NIL, INCREF(p->n_type), p->n_df, p->n_ap); + q->n_sp = sp; + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = sp; + nfree(p); + return q; + +#elif defined(MACHOABI) + + return p; + +#endif +} + +static NODE * +cmop(NODE *l, NODE *r) +{ + return block(CM, l, r, INT, 0, 0); +} + +static NODE * +mkx(char *s, NODE *p) +{ + p = block(XARG, p, NIL, INT, 0, 0); + p->n_name = s; + return p; +} + +static char * +mk3str(char *s1, char *s2, char *s3) +{ + int len = strlen(s1) + strlen(s2) + strlen(s3) + 1; + char *sd; + + sd = tmpalloc(len); + strlcpy(sd, s1, len); + strlcat(sd, s2, len); + strlcat(sd, s3, len); + return sd; +} + +/* + * Create a reference for a TLS variable. + * This is the "General dynamic" version. + */ +static NODE * +tlspic(NODE *p) +{ + NODE *q, *r, *s; + char *s1, *s2; + + /* + * .byte 0x66 + * leaq x@TLSGD(%rip),%rdi + * .word 0x6666 + * rex64 + * call __tls_get_addr@PLT + */ + + /* Need the .byte stuff around. Why? */ + /* Use inline assembler */ + q = mkx("%rdx", bcon(0)); + q = cmop(q, mkx("%rcx", bcon(0))); + q = cmop(q, mkx("%rsi", bcon(0))); + q = cmop(q, mkx("%rdi", bcon(0))); + q = cmop(q, mkx("%r8", bcon(0))); + q = cmop(q, mkx("%r9", bcon(0))); + q = cmop(q, mkx("%r10", bcon(0))); + q = cmop(q, mkx("%r11", bcon(0))); + + s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap)); + r = mkx("=a", r); + r = block(XASM, r, q, INT, 0, 0); + + /* Create the magic string */ + s1 = ".byte 0x66\n\tleaq "; + s2 = "@TLSGD(%%rip),%%rdi\n" + "\t.word 0x6666\n\trex64\n\tcall __tls_get_addr@PLT"; + if (attr_find(p->n_sp->sap, ATTR_SONAME) == NULL) { + p->n_sp->sap = attr_add(p->n_sp->sap, attr_new(ATTR_SONAME, 1)); + p->n_sp->sap->sarg(0) = p->n_sp->sname; + } + r->n_name = addstring(mk3str(s1, + attr_find(p->n_sp->sap, ATTR_SONAME)->sarg(0), s2)); + + r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap); + r = buildtree(UMUL, r, NIL); + tfree(p); + return r; +} + +#ifdef GCC_COMPAT +/* + * The "initial exec" tls model. + */ +static NODE * +tlsinitialexec(NODE *p) +{ + NODE *q, *r, *s; + char *s1, *s2; + + /* + * movq %fs:0,%rax + * addq x@GOTTPOFF(%rip),%rax + */ + + q = bcon(0); + q->n_type = STRTY; + + s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap)); + r = mkx("=r", r); + r = block(XASM, r, q, INT, 0, 0); + + s1 = "movq %%fs:0,%0\n\taddq "; + s2 = "@GOTTPOFF(%%rip),%0"; + if (attr_find(p->n_sp->sap, ATTR_SONAME) == NULL) { + p->n_sp->sap = attr_add(p->n_sp->sap, attr_new(ATTR_SONAME, 1)); + p->n_sp->sap->sarg(0) = p->n_sp->sname; + } + r->n_name = mk3str(s1, + attr_find(p->n_sp->sap, ATTR_SONAME)->sarg(0), s2); + + r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap); + r = buildtree(UMUL, r, NIL); + tfree(p); + return r; +} +#endif + +static NODE * +tlsref(NODE *p) +{ +#ifdef GCC_COMPAT + struct symtab *sp = p->n_sp; + struct attr *ga; + char *c; + + if ((ga = attr_find(sp->sap, GCC_ATYP_TLSMODEL)) != NULL) { + c = ga->sarg(0); + if (strcmp(c, "initial-exec") == 0) + return tlsinitialexec(p); + else if (strcmp(c, "global-dynamic") == 0) + ; + else + werror("unsupported tls model '%s'", c); + } +#endif + return tlspic(p); +} + +/* clocal() is called to do local transformations on + * an expression tree preparitory to its being + * written out in intermediate code. + * + * the major essential job is rewriting the + * automatic variables and arguments in terms of + * REG and OREG nodes + * conversion ops which are not necessary are also clobbered here + * in addition, any special features (such as rewriting + * exclusive or) are easily handled here as well + */ +NODE * +clocal(NODE *p) +{ + + register struct symtab *q; + register NODE *r, *l; + register int o; + register int m; + TWORD t; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + switch( o = p->n_op ){ + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + slval(r, 0); + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case USTATIC: + if (kflag == 0) + break; + /* FALLTHROUGH */ + case STATIC: +#ifdef TLS + if (q->sflags & STLS) { + p = tlsref(p); + break; + } +#endif + break; + + case REGISTER: + p->n_op = REG; + slval(p, 0); + p->n_rval = q->soffset; + break; + + case EXTERN: + case EXTDEF: + if (q->sflags & STLS) { + p = tlsref(p); + break; + } + if (kflag == 0 || statinit) + break; + if (blevel > 0) + p = picext(p); + break; + } + break; + + case UCALL: + case USTCALL: + /* For now, always clear eax */ + l = block(REG, NIL, NIL, INT, 0, 0); + regno(l) = RAX; + p->n_right = clocal(buildtree(ASSIGN, l, bcon(0))); + p->n_op -= (UCALL-CALL); + break; + + case SCONV: + /* Special-case shifts */ + if (p->n_type == LONG && (l = p->n_left)->n_op == LS && + l->n_type == INT && l->n_right->n_op == ICON) { + p->n_left = l->n_left; + p = buildtree(LS, p, l->n_right); + nfree(l); + break; + } + + l = p->n_left; + + /* Float conversions may need extra casts */ + if (p->n_type == FLOAT || p->n_type == DOUBLE || + p->n_type == LDOUBLE) { + if (l->n_type < INT || l->n_type == BOOL) { + p->n_left = block(SCONV, l, NIL, + ISUNSIGNED(l->n_type) ? UNSIGNED : INT, + l->n_df, l->n_ap); + break; + } + } + + if (p->n_type == l->n_type) { + nfree(p); + return l; + } + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + tsize(p->n_type, p->n_df, p->n_ap) == + tsize(l->n_type, l->n_df, l->n_ap)) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + return l; + } + } + } + + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && + coptype(l->n_op) == BITYPE && l->n_op != COMOP && + l->n_op != QUEST && l->n_op != ASSIGN) { + l->n_type = p->n_type; + nfree(p); + return l; + } + + o = l->n_op; + m = p->n_type; + + if (o == ICON) { + CONSZ val = glval(l); + + /* if named constant and pointer, allow cast + to long/ulong */ + if (!nncon(l) && (l->n_type & TMASK) && + (m == LONG || m == ULONG)) { + l->n_type = m; + l->n_ap = 0; + return nfree(p); + } + + if (ISPTR(l->n_type) && !nncon(l)) + break; /* cannot convert named pointers */ + + if (!ISPTR(m)) /* Pointers don't need to be conv'd */ + switch (m) { + case BOOL: + val = nncon(l) ? (val != 0) : 1; + slval(l, val); + l->n_sp = NULL; + break; + case CHAR: + slval(l, (char)val); + break; + case UCHAR: + slval(l, val & 0377); + break; + case SHORT: + slval(l, (short)val); + break; + case USHORT: + slval(l, val & 0177777); + break; + case UNSIGNED: + slval(l, val & 0xffffffff); + break; + case INT: + slval(l, (int)val); + break; + case LONG: + case LONGLONG: + slval(l, (long long)val); + break; + case ULONG: + case ULONGLONG: + slval(l, val); + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = fltallo(); + FCAST(l->n_dcon)->fp = val; + break; + default: + cerror("unknown type %d", m); + } + l->n_type = m; + l->n_ap = NULL; + nfree(p); + return l; + } else if (l->n_op == FCON) { + CONSZ lv; + if (p->n_type == BOOL) + lv = !FLOAT_ISZERO(FCAST(l->n_dcon)); + else { + FLOAT_FP2INT(lv, FCAST(l->n_dcon), m); + } + slval(l, lv); + l->n_sp = NULL; + l->n_op = ICON; + l->n_type = m; + l->n_ap = NULL; + nfree(p); + return clocal(l); + } + if ((p->n_type == CHAR || p->n_type == UCHAR || + p->n_type == SHORT || p->n_type == USHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left->n_type = INT; + return p; + } + break; + + case MOD: + case DIV: + if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) + break; + if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) + break; + /* make it an int division by inserting conversions */ + p->n_left = makety(p->n_left, INT, 0, 0, 0); + p->n_right = makety(p->n_right, INT, 0, 0, 0); + p = makety(p, p->n_type, 0, 0, 0); + p->n_left->n_type = INT; + break; + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + t = p->n_type; + if (ISITY(t)) + t = t - (FIMAG-FLOAT); + p->n_left->n_rval = p->n_left->n_type == BOOL ? + RETREG(CHAR) : RETREG(t); + break; + + case LS: + case RS: + /* shift count must be in a char */ + if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR) + break; + p->n_right = makety(p->n_right, CHAR, 0, 0, 0); + break; + } +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal end: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + return(p); +} + +void +myp2tree(NODE *p) +{ + struct attr *ap; + struct symtab *sp, sps; + static int dblxor, fltxor; + int codeatyp(NODE *); + + if (p->n_op == STCALL || p->n_op == USTCALL) { + /* save struct encoding */ + p->n_ap = attr_add(p->n_ap, + ap = attr_new(ATTR_AMD64_CMPLRET, 1)); + ap->iarg(0) = codeatyp(p); + } + + if (p->n_op == UMINUS && (p->n_type == FLOAT || p->n_type == DOUBLE)) { + /* Store xor code for sign change */ + if (dblxor == 0) { + dblxor = getlab(); + fltxor = getlab(); + sps.stype = LDOUBLE; + sps.squal = CON >> TSHIFT; + sps.sflags = sps.sclass = 0; + sps.sname = ""; + sps.slevel = 1; + sps.sap = NULL; + sps.soffset = dblxor; + locctr(DATA, &sps); + defloc(&sps); + printf("\t.long 0,0x80000000,0,0\n"); + printf(LABFMT ":\n", fltxor); + printf("\t.long 0x80000000,0,0,0\n"); + } + p->n_ap = attr_add(p->n_ap, + ap = attr_new(ATTR_AMD64_XORLBL, 1)); + ap->iarg(0) = p->n_type == FLOAT ? fltxor : dblxor; + return; + } + if (kflag && (cdope(p->n_op) & CALLFLG) && p->n_left->n_op == NAME) { + /* Convert @GOTPCREL to @PLT */ + char *s; + + sp = p->n_left->n_sp; + if ((s = strstr(sp->sname, "@GOTPCREL")) != NULL) { + memcpy(s, "@PLT", sizeof("@PLT")); + p->n_left->n_op = ICON; + } + return; + } + if (p->n_op != FCON) + return; + +#ifdef mach_amd64 + { + /* Do not lose negative zeros */ + long long ll[2]; + short ss; + memcpy(ll, &p->n_dcon, sizeof(ll)); + memcpy(&ss, &ll[1], sizeof(ss)); + if (ll[0] == 0 && ss == 0) + return; + } +#else +#error fixme +#endif + + /* XXX should let float constants follow */ + sp = IALLOC(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->sap = NULL; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + sp->sname = NULL; + + locctr(DATA, sp); + defloc(sp); + ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + + p->n_op = NAME; + slval(p, 0); + p->n_sp = sp; +} + +/* + * Convert ADDROF NAME to ICON? + */ +int +andable(NODE *p) +{ +#ifdef notdef + /* shared libraries cannot have direct referenced static syms */ + if (p->n_sp->sclass == STATIC || p->n_sp->sclass == USTATIC) + return 1; +#endif + return !kflag; +} + +/* + * Return 1 if a variable of type type is OK to put in register. + */ +int +cisreg(TWORD t) +{ + if (t == LDOUBLE) + return 0; + return 1; +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a storeable node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + p = buildtree(MUL, p, bcon(off/SZCHAR)); + p = buildtree(PLUS, p, bcon(30)); + p = buildtree(AND, p, xbcon(-16, NULL, LONG)); + + /* sub the size from sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + slval(sp, 0); + sp->n_rval = STKREG; + ecomp(buildtree(MINUSEQ, sp, p)); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+LONG, t->n_df, t->n_ap); + slval(sp, 0); + sp->n_rval = STKREG; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + +} + +/* + * print out a constant node, may be associated with a label. + * Do not free the node after use. + * off is bit offset from the beginning of the aggregate + * fsz is the number of bits this is referring to + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; long double l; int i[3]; } u; + + switch (p->n_type) { + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)FCAST(p->n_dcon)->fp; +#if defined(HOST_BIG_ENDIAN) + /* XXX probably broken on most hosts */ + printf("\t.long\t0x%x,0x%x,0x%x,0\n", u.i[2], u.i[1], u.i[0]); +#else + printf("\t.long\t0x%x,0x%x,0x%x,0\n", u.i[0], u.i[1], + u.i[2] & 0xffff); +#endif + break; + case DOUBLE: + u.d = (double)FCAST(p->n_dcon)->fp; +#if defined(HOST_BIG_ENDIAN) + printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]); +#else + printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]); +#endif + break; + case FLOAT: + u.f = (float)FCAST(p->n_dcon)->fp; + printf("\t.long\t0x%x\n", u.i[0]); + break; + default: + return 0; + } + return 1; +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ +#ifdef MACHOABI + +#define NCHNAM 256 + static char text[NCHNAM+1]; + int i; + + if (p == NULL) + return ""; + + text[0] = '_'; + for (i=1; *p && istype, sp->sdf, sp->sap); + SETOFF(off,SZCHAR); + off /= SZCHAR; + al = talign(sp->stype, sp->sap)/SZCHAR; + +#ifdef MACHOABI + if (sp->sclass == STATIC) { + al = ispow2(al); + printf("\t.zerofill __DATA,__bss,"); + if (sp->slevel == 0) { + printf("%s", name); + } else + printf(LABFMT, sp->soffset); + printf(",%d,%d\n", off, al); + } else { + printf("\t.comm %s,0%o,%d\n", name, off, al); + } +#else + if (sp->sclass == STATIC) { + if (sp->slevel == 0) { + printf("\t.local %s\n", name); + } else + printf("\t.local " LABFMT "\n", sp->soffset); + } + if (sp->slevel == 0) { + printf("\t.comm %s,0%o,%d\n", name, off, al); + } else + printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); +#endif +} + +static char * +section2string(char *name) +{ + int len = strlen(name); + + if (strncmp(name, "link_set", 8) == 0) { + const char postfix[] = ",\"aw\",@progbits"; + char *s; + + s = IALLOC(len + sizeof(postfix)); + memcpy(s, name, len); + memcpy(s + len, postfix, sizeof(postfix)); + return s; + } + + return newstring(name, len); +} + +char *nextsect; +static int gottls; +static char *alias; +static int constructor; +static int destructor; + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + char *a2 = pragtok(NULL); + + if (strcmp(str, "tls") == 0 && a2 == NULL) { + gottls = 1; + return 1; + } + if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { + constructor = 1; + return 1; + } + if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { + destructor = 1; + return 1; + } + if (strcmp(str, "section") == 0 && a2 != NULL) { + nextsect = section2string(a2); + return 1; + } + if (strcmp(str, "alias") == 0 && a2 != NULL) { + alias = tmpstrdup(a2); + return 1; + } + + return 0; +} + +/* + * Called when a identifier has been declared. + */ +void +fixdef(struct symtab *sp) +{ + /* may have sanity checks here */ + if (gottls) + sp->sflags |= STLS; + gottls = 0; + +#ifdef GCC_COMPAT + struct attr *ga; + +#ifdef HAVE_WEAKREF + /* not many as'es have this directive */ + if ((ga = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) { + char *wr = ga->sarg(0); + char *sn = getsoname(sp); + if (wr == NULL) { + if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS))) { + wr = ga->sarg(0); + } + } + if (wr == NULL) + printf("\t.weak %s\n", sn); + else + printf("\t.weakref %s,%s\n", sn, wr); + } else +#endif + if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) { + char *an = ga->sarg(0); + char *sn = getsoname(sp); + char *v; + + v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl"; + printf("\t.%s %s\n", v, sn); + printf("\t.set %s,%s\n", sn, an); + } +#endif + if (alias != NULL && (sp->sclass != PARAM)) { + printf("\t.globl %s\n", getexname(sp)); + printf("%s = ", getexname(sp)); + printf("%s\n", exname(alias)); + alias = NULL; + } + if ((constructor || destructor) && (sp->sclass != PARAM)) { + NODE *p = talloc(); + + p->n_op = NAME; + p->n_sp = + (struct symtab *)(constructor ? "constructor" : "destructor"); +#ifdef GCC_COMPAT + sp->sap = attr_add(sp->sap, gcc_attr_parse(p)); +#endif + constructor = destructor = 0; + } +} + +void +pass1_lastchance(struct interpass *ip) +{ +} + diff --git a/lang/pcc/pcc/arch/amd64/local2.c b/lang/pcc/pcc/arch/amd64/local2.c new file mode 100644 index 000000000..3f5f93a75 --- /dev/null +++ b/lang/pcc/pcc/arch/amd64/local2.c @@ -0,0 +1,1245 @@ +/* $Id: local2.c,v 1.62 2015/12/13 09:00:04 ragge Exp $ */ +/* + * Copyright (c) 2008 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" +# include +# include + +static int stkpos; + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static int regoff[MAXREGS]; +static TWORD ftype; +char *rbyte[], *rshort[], *rlong[]; +static int needframe; + +/* + * Print out the prolog assembler. + * addto and regoff are already calculated. + */ +static void +prtprolog(struct interpass_prolog *ipp, int addto) +{ + int i; + + printf("\tpushq %%rbp\n"); + printf("\tmovq %%rsp,%%rbp\n"); + addto = (addto+15) & ~15; /* 16-byte aligned */ + if (addto) + printf("\tsubq $%d,%%rsp\n", addto); + + /* save permanent registers */ + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) + printf("\tmovq %s,-%d(%s)\n", + rnames[i], regoff[i], rnames[FPREG]); +} + +/* + * calculate stack size and offsets + */ +static int +offcalc(struct interpass_prolog *ipp) +{ + int i, addto; + + addto = p2maxautooff; + if (addto >= AUTOINIT/SZCHAR) + addto -= AUTOINIT/SZCHAR; + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) { + addto += SZLONG/SZCHAR; + regoff[i] = addto; + } + return addto; +} + +/* + * Traverse a tree to check if we need to emit a frame at all. + * We emit it if: + * - any function call + * - rsp or rbp referenced + * Return 1 if frame is needed, 0 otherwise. + */ +static int +chkf(NODE *p) +{ + int o = p->n_op; + + if ((o == REG || o == OREG) && (regno(p) == RBP || regno(p) == RSP)) + return 1; + if (callop(o)) + return 1; + if (optype(o) == UTYPE) + return chkf(p->n_left); + else if (optype(o) == BITYPE) + return chkf(p->n_left) || chkf(p->n_right); + return 0; +} + +static int +chkframe(struct interpass_prolog *ipp) +{ + struct interpass *ip; + + DLIST_FOREACH(ip, &ipp->ipp_ip, qelem) { + if (ip->type == IP_EPILOG) + break; + if (ip->type == IP_NODE) { + if (chkf(ip->ip_node)) + return 1; + } + } + return 0; +} + +void +prologue(struct interpass_prolog *ipp) +{ + int addto; + + ftype = ipp->ipp_type; + + if (xdeljumps) + needframe = chkframe(ipp); + else + needframe = 1; + +#ifdef LANG_F77 + if (ipp->ipp_vis) + printf(" .globl %s\n", ipp->ipp_name); + printf(" .align 16\n"); + printf("%s:\n", ipp->ipp_name); +#endif + /* + * We here know what register to save and how much to + * add to the stack. + */ + addto = offcalc(ipp); + if (addto) + needframe = 1; + if (needframe) + prtprolog(ipp, addto); +} + +void +eoftn(struct interpass_prolog *ipp) +{ + int i; + + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + if (needframe) { + /* return from function code */ + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) + printf(" movq -%d(%s),%s\n", + regoff[i], rnames[FPREG], rnames[i]); + + /* struct return needs special treatment */ + if (ftype == STRTY || ftype == UNIONTY) { + printf(" movl 8(%%ebp),%%eax\n"); + printf(" leave\n"); + printf(" ret $%d\n", 4); + } else { + printf(" leave\n"); + printf(" ret\n"); + } + } else + printf("\tret\n"); + +#ifndef MACHOABI + printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name); +#endif +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s%c", str, f); +} + +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(NODE *p) +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + return(SZINT/SZCHAR); + + case LONG: + case ULONG: + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +/* + * Compare two floating point numbers. + */ +static void +fcomp(NODE *p) +{ + + if (p->n_left->n_op != REG) + comperr("bad compare %p\n", p); + if ((p->n_su & DORIGHT) == 0) + expand(p, 0, "\tfxch\n"); + expand(p, 0, "\tfucomip %st(1),%st\n"); /* emit compare insn */ + expand(p, 0, "\tfstp %st(0)\n"); /* pop fromstack */ + zzzcode(p, 'U'); +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + comperr("fldexpand"); + return 0; +} + +static void +stasg(NODE *p) +{ + struct attr *ap = attr_find(p->n_ap, ATTR_P2STRUCT); + expand(p, INAREG, " leaq AL,%rdi\n"); + if (ap->iarg(0) >= 8) + printf("\tmovl $%d,%%ecx\n\trep movsq\n", ap->iarg(0) >> 3); + if (ap->iarg(0) & 4) + printf("\tmovsl\n"); + if (ap->iarg(0) & 2) + printf("\tmovsw\n"); + if (ap->iarg(0) & 1) + printf("\tmovsb\n"); +} + +#define E(x) expand(p, 0, x) +/* + * Generate code to convert an unsigned long to xmm float/double. + */ +static void +ultofd(NODE *p) +{ + + E(" movq AL,A1\n"); + E(" testq A1,A1\n"); + E(" js 2f\n"); + E(" cvtsi2sZfq A1,A3\n"); + E(" jmp 3f\n"); + E("2:\n"); + E(" movq A1,A2\n"); + E(" shrq A2\n"); + E(" andq $1,A1\n"); + E(" orq A1,A2\n"); + E(" cvtsi2sZfq A2,A3\n"); + E(" addsZf A3,A3\n"); + E("3:\n"); +} + +/* + * Generate code to convert an x87 long double to an unsigned long. + * This is ugly :-/ + */ +static void +ldtoul(NODE *p) +{ + + E(" subq $16,%rsp\n"); + E(" movl $0x5f000000,(%rsp)\n"); /* More than long can have */ + E(" flds (%rsp)\n"); + if (p->n_left->n_op == REG) { + E(" fxch\n"); + } else + E(" fldt AL\n"); + E(" fucomi %st(1), %st\n"); + E(" jae 2f\n"); + + E(" fstp %st(1)\n"); /* Pop huge val from stack */ + E(" fnstcw (%rsp)\n"); /* store cw */ + E(" movw $0x0f3f,4(%rsp)\n");/* round towards 0 */ + E(" fldcw 4(%rsp)\n"); /* new cw */ + E(" fistpll 8(%rsp)\n"); /* save val */ + E(" fldcw (%rsp)\n"); /* fetch old cw */ + E(" movq 8(%rsp),A1\n"); + + E(" jmp 3f\n"); + + E("2:\n"); + + E(" fsubp %st, %st(1)\n"); + E(" fnstcw (%rsp)\n"); + E(" movw $0x0f3f,4(%rsp)\n"); + E(" fldcw 4(%rsp)\n"); + E(" fistpll 8(%rsp)\n"); + E(" fldcw (%rsp)\n"); + E(" movabsq $0x8000000000000000,A1\n"); + E(" xorq 8(%rsp),A1\n"); + + E("3: addq $16,%rsp\n"); +} + +/* + * Generate code to convert an SSE float/double to an unsigned long. + */ +static void +fdtoul(NODE *p) +{ + if (p->n_left->n_type == FLOAT) + E(" movabsq $0x5f000000,A1\n"); + else + E(" movabsq $0x43e0000000000000,A1\n"); + E(" movd A1,A3\n"); + E(" ucomisZg A3,AL\n"); + E(" jae 2f\n"); + E(" cvttsZg2siq AL,A1\n"); + E(" jmp 3f\n"); + E("2:\n"); + E(" subsZg A3,AL\n"); + E(" cvttsZg2siq AL,A1\n"); + E(" movabsq $0x8000000000000000,A2\n"); + E(" xorq A2,A1\n"); + E("3:\n"); +} +#undef E + +void +zzzcode(NODE *p, int c) +{ + struct attr *ap, *ap2; + NODE *l; + int pr, lr, s; + char **rt; + + switch (c) { + case 'A': /* swap st0 and st1 if right is evaluated second */ + if ((p->n_su & DORIGHT) == 0) { + if (logop(p->n_op)) + printf(" fxch\n"); + else + printf("r"); + } + break; + + case 'B': /* ldouble to unsigned long cast */ + ldtoul(p); + break; + + case 'b': /* float/double to unsigned long cast */ + fdtoul(p); + break; + + case 'C': /* remove from stack after subroutine call */ + pr = p->n_qual; + if (p->n_op == UCALL) + return; /* XXX remove ZC from UCALL */ + if (pr) + printf(" addq $%d, %s\n", pr, rnames[RSP]); +#define STRREG 6 +#define STRSSE 8 +#define STRIF 9 +#define STRFI 10 +#define STRX87 11 + ap = attr_find(p->n_ap, ATTR_P2STRUCT); + ap2 = attr_find(p->n_ap, ATTR_AMD64_CMPLRET); + if ((p->n_op == STCALL || p->n_op == USTCALL) && + ap->iarg(0) == 32 && ap2->iarg(0) == STRX87) { + printf("\tfstpt -%d(%%rbp)\n", stkpos); + printf("\tfstpt -%d(%%rbp)\n", stkpos-16); + printf("\tleaq -%d(%%rbp),%%rax\n", stkpos); + } + if ((p->n_op == STCALL || p->n_op == USTCALL) && + ap->iarg(0) <= 16) { + /* store reg-passed structs on stack */ + if (ap2->iarg(0) == STRREG || ap2->iarg(0) == STRIF) + printf("\tmovq %%rax,-%d(%%rbp)\n", stkpos); + else + printf("\tmovsd %%xmm0,-%d(%%rbp)\n", stkpos); + if (ap->iarg(0) > 8) { + if (ap2->iarg(0) == STRREG) + printf("\tmovq %%rdx"); + else if (ap2->iarg(0) == STRFI) + printf("\tmovq %%rax"); + else if (ap2->iarg(0) == STRIF) + printf("\tmovsd %%xmm0"); + else + printf("\tmovsd %%xmm1"); + printf(",-%d(%%rbp)\n", stkpos-8); + } + printf("\tleaq -%d(%%rbp),%%rax\n", stkpos); + } + break; + + case 'c': /* xor label */ + if ((ap = attr_find(p->n_ap, ATTR_AMD64_XORLBL)) == NULL) + comperr("missing xor label"); + printf(LABFMT, ap->iarg(0)); + break; + + case 'F': /* Structure argument */ + ap = attr_find(p->n_ap, ATTR_P2STRUCT); + printf(" subq $%d,%%rsp\n", ap->iarg(0)); + printf(" movq %%rsp,%%rsi\n"); + stasg(p); + break; + + case 'G': /* Floating point compare */ + fcomp(p); + break; + + case 'j': /* convert unsigned long to f/d */ + ultofd(p); + break; + + case 'M': /* Output sconv move, if needed */ + l = getlr(p, 'L'); + /* XXX fixneed: regnum */ + pr = DECRA(p->n_reg, 0); + lr = DECRA(l->n_reg, 0); + if (pr == lr) + break; + printf(" movb %s,%s\n", rbyte[lr], rbyte[pr]); + l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */ + break; + + case 'N': /* output long reg name */ + printf("%s", rlong[getlr(p, '1')->n_rval]); + break; + + case 'P': /* Put hidden argument in rdi */ + ap = attr_find(p->n_ap, ATTR_P2STRUCT); + ap2 = attr_find(p->n_ap, ATTR_AMD64_CMPLRET); + if (ap->iarg(0) > 16 && ap2->iarg(0) != STRX87) + printf("\tleaq -%d(%%rbp),%%rdi\n", stkpos); + break; + + case 'Q': /* emit struct assign */ + stasg(p); + break; + + case 'R': /* print opname based on right type */ + case 'L': /* print opname based on left type */ + switch (getlr(p, c)->n_type) { + case CHAR: case UCHAR: s = 'b'; break; + case SHORT: case USHORT: s = 'w'; break; + case INT: case UNSIGNED: s = 'l'; break; + default: s = 'q'; break; + printf("%c", s); + } + break; + + case 'U': { /* output branch insn for ucomi */ + static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" }; + if (p->n_op < EQ || p->n_op > GT) + comperr("bad fp branch"); + if (p->n_op == NE || p->n_op == GT || p->n_op == GE) + expand(p, 0, " jp LC\n"); + else if (p->n_op == EQ) + printf("\tjp 1f\n"); + printf(" %s ", fpcb[p->n_op - EQ]); + expand(p, 0, "LC\n"); + if (p->n_op == EQ) + printf("1:\n"); + break; + } + + case '8': /* special reg name printout (64-bit) */ + case '1': /* special reg name printout (32-bit) */ + l = getlr(p, '1'); + rt = c == '8' ? rnames : rlong; + printf("%s", rt[l->n_rval]); + break; + + case 'g': + p = p->n_left; + /* FALLTHROUGH */ + case 'f': /* float or double */ + printf("%c", p->n_type == FLOAT ? 's' : 'd'); + break; + + case 'q': /* int or long */ + printf("%c", p->n_left->n_type == LONG ? 'q' : ' '); + break; + + default: + comperr("zzzcode %c", c); + } +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left, SOREG))) + return(1); + return(0); +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + comperr("flshape"); + return(0); +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + return 0; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +void +adrcon(CONSZ val) +{ + printf("$" CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + long val = getlval(p); + + switch (p->n_op) { + case ICON: + if (p->n_name[0] != '\0') { + fprintf(fp, "%s", p->n_name); + if (val) + fprintf(fp, "+%ld", val); + } else + fprintf(fp, "%ld", val); + return; + + default: + comperr("illegal conput, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + * XXX - not needed on amd64 + */ +void +upput(NODE *p, int size) +{ + + size /= SZCHAR; + switch (p->n_op) { + case REG: + printf("%%%s", &rnames[p->n_rval][3]); + break; + + case NAME: + case OREG: + setlval(p, getlval(p) + size); + adrput(stdout, p); + setlval(p, getlval(p) - size); + break; + case ICON: + printf("$" CONFMT, getlval(p) >> 32); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *io, NODE *p) +{ + int r; + char **rc; + /* output an address, with offsets, from p */ + + switch (p->n_op) { + + case NAME: + if (p->n_name[0] != '\0') { + if (getlval(p) != 0) + fprintf(io, CONFMT "+", getlval(p)); + fprintf(io, "%s(%%rip)", p->n_name); + } else + fprintf(io, CONFMT, getlval(p)); + return; + + case OREG: + r = p->n_rval; + if (p->n_name[0]) + printf("%s%s", p->n_name, getlval(p) ? "+" : ""); + if (getlval(p)) + fprintf(io, "%lld", getlval(p)); + if (R2TEST(r)) { + int r1 = R2UPK1(r); + int r2 = R2UPK2(r); + int sh = R2UPK3(r); + + fprintf(io, "(%s,%s,%d)", + r1 == MAXREGS ? "" : rnames[r1], + r2 == MAXREGS ? "" : rnames[r2], sh); + } else + fprintf(io, "(%s)", rnames[p->n_rval]); + return; + case ICON: + /* addressable value of the constant */ + fputc('$', io); + conput(io, p); + return; + + case REG: + switch (p->n_type) { + case CHAR: + case UCHAR: + rc = rbyte; + break; + case SHORT: + case USHORT: + rc = rshort; + break; + case INT: + case UNSIGNED: + rc = rlong; + break; + default: + rc = rnames; + break; + } + fprintf(io, "%s", rc[p->n_rval]); + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +static char * +ccbranches[] = { + "je", /* jumpe */ + "jne", /* jumpn */ + "jle", /* jumple */ + "jl", /* jumpl */ + "jge", /* jumpge */ + "jg", /* jumpg */ + "jbe", /* jumple (jlequ) */ + "jb", /* jumpl (jlssu) */ + "jae", /* jumpge (jgequ) */ + "ja", /* jumpg (jgtru) */ +}; + + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + if (o < EQ || o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); +} + +/* + * gcc xasm has the ability to generate different asm types + * via some magic. + * + * Only support AT&T asm for now. + */ +static char * +adjustname(char *s) +{ + int len = strlen(s); + char *d = tmpalloc(len+1); + int i, j, flvl, tlvl; + + flvl = tlvl = 0; + for (i = j = 0; i < len; i++) { + switch (s[i]) { + case '{': tlvl++; break; + case '}': if (tlvl)tlvl--; else flvl--; break; + case '|': tlvl--; flvl++; break; + default: + if (flvl == 0) + d[j++] = s[i]; + break; + } + } + d[j] = 0; + return d; +} + +static void +fixcalls(NODE *p, void *arg) +{ + int ps; + + /* Prepare for struct return by allocating bounce space on stack */ + switch (p->n_op) { + case STCALL: + case USTCALL: + ps = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + if (ps < 16) + ps = 16; + if (ps+p2autooff > stkpos) + stkpos = ps+p2autooff; + break; + case XASM: + p->n_name = adjustname(p->n_name); + break; + } +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + stkpos = p2autooff; + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, fixcalls, 0); + } + if (stkpos > p2autooff) + p2autooff = stkpos; + if (stkpos > p2maxautooff) + p2maxautooff = stkpos; + if (x2debug) + printip(ipole); +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE *p, void *arg) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2, 0); +} + +void +myoptim(struct interpass *ip) +{ +} + +void +rmove(int s, int d, TWORD t) +{ + + switch (t) { + case INT: + case UNSIGNED: + printf(" movl %s,%s\n", rlong[s], rlong[d]); + break; + case CHAR: + case UCHAR: + printf(" movb %s,%s\n", rbyte[s], rbyte[d]); + break; + case SHORT: + case USHORT: + printf(" movw %s,%s\n", rshort[s], rshort[d]); + break; + case FLOAT: + printf(" movss %s,%s\n", rnames[s], rnames[d]); + break; + case DOUBLE: + printf(" movsd %s,%s\n", rnames[s], rnames[d]); + break; + case LDOUBLE: +#ifdef notdef + /* a=b()*c(); will generate this */ + /* XXX can it fail anyway? */ + comperr("bad float rmove: %d %d", s, d); +#endif + break; + default: + printf(" movq %s,%s\n", rnames[s], rnames[d]); + break; + } +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int c, int *r) +{ + + switch (c) { + case CLASSA: + return r[CLASSA] < 14; + case CLASSB: + return r[CLASSB] < 16; + case CLASSC: + return r[CLASSC] < CREGCNT; + } + return 0; /* XXX gcc */ +} + +char *rnames[] = { + "%rax", "%rdx", "%rcx", "%rbx", "%rsi", "%rdi", "%rbp", "%rsp", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", + "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", + "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14", + "%xmm15", +}; + +/* register names for shorter sizes */ +char *rbyte[] = { + "%al", "%dl", "%cl", "%bl", "%sil", "%dil", "%bpl", "%spl", + "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b", +}; +char *rshort[] = { + "%ax", "%dx", "%cx", "%bx", "%si", "%di", "%bp", "%sp", + "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w", +}; +char *rlong[] = { + "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp", + "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d", +}; + + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t == LDOUBLE) + return CLASSC; + if (t == FLOAT || t == DOUBLE) + return CLASSB; + return CLASSA; +} + +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (p->n_left->n_op == REG) + return 0; /* not on stack */ + if (t == LDOUBLE) + return 16; + if (p->n_op == STASG) + return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + return 8; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + size += argsiz(p->n_right); + size += argsiz(p); + size = (size+15) & ~15; + if (size) + printf(" subq $%d,%s\n", size, rnames[RSP]); + op->n_qual = size; /* XXX */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + int o = p->n_op; + + switch (shape) { + case SFUNCALL: + if (o == STCALL || o == USTCALL) + return SRREG; + break; + case SPCON: + if (o != ICON || p->n_name[0] || + getlval(p) < 0 || getlval(p) > 0x7fffffff) + break; + return SRDIR; + case SMIXOR: + return tshape(p, SZERO); + case SMILWXOR: + if (o != ICON || p->n_name[0] || + getlval(p) == 0 || getlval(p) & 0xffffffff) + break; + return SRDIR; + case SMIHWXOR: + if (o != ICON || p->n_name[0] || + getlval(p) == 0 || (getlval(p) >> 32) != 0) + break; + return SRDIR; + case SCON32: + if (o != ICON || p->n_name[0]) + break; + if (getlval(p) < MIN_INT || getlval(p) > MAX_INT) + break; + return SRDIR; + default: + cerror("special: %x\n", shape); + } + return SRNOPE; +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ +} + +/* + * Do something target-dependent for xasm arguments. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + struct interpass *ip2; + int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 }; + NODE *in = 0, *ut = 0; + TWORD t; + char *w; + int reg; + int c, cw, v; + + cw = xasmcode(p->n_name); + if (cw & (XASMASG|XASMINOUT)) + ut = p->n_left; + if ((cw & XASMASG) == 0) + in = p->n_left; + + c = XASMVAL(cw); +retry: switch (c) { + case 'D': reg = RDI; break; + case 'S': reg = RSI; break; + case 'A': + case 'a': reg = RAX; break; + case 'b': reg = RBX; break; + case 'c': reg = RCX; break; + case 'd': reg = RDX; break; + + case 'Q': reg = RDX; break; /* Always dx for now */ + + case 'x': + case 'q': + case 't': + case 'u': + p->n_name = tmpstrdup(p->n_name); + w = strchr(p->n_name, c); + *w = 'r'; /* now reg */ + return c == 'q' || c == 'x' || c == 't' ? 0 : 1; + + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + if (p->n_left->n_op != ICON) { + if ((c = XASMVAL1(cw))) { + if (c == 'r') { + p->n_name++; + return 0; + } + goto retry; + } + uerror("xasm arg not constant"); + } + v = getlval(p->n_left); + if ((c == 'K' && v < -128) || + (c == 'L' && v != 0xff && v != 0xffff) || + (c != 'K' && v < 0) || + (v > Cmax[c-'I'])) + uerror("xasm val out of range"); + p->n_name = "i"; + return 1; + + default: + return 0; + } + /* If there are requested either memory or register, delete memory */ + w = p->n_name = tmpstrdup(p->n_name); + if (*w == '=') + w++; + *w++ = 'r'; + *w = 0; + + t = p->n_left->n_type; + + if (t == FLOAT || t == DOUBLE) { + reg += 16; + } else if (t == LDOUBLE) { + reg += 32; + } + + if (in && ut) + in = tcopy(in); + p->n_left = mklnode(REG, 0, reg, t); + if (ut) { + ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t)); + DLIST_INSERT_AFTER(ip, ip2, qelem); + } + if (in) { + ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t)); + DLIST_INSERT_BEFORE(ip, ip2, qelem); + } + + return 1; +} + +void +targarg(char *w, void *arg, int n) +{ + NODE **ary = arg; + NODE *p, *q; + + if (w[1] < '0' || w[1] > (n + '0')) + uerror("bad xasm arg number %c", w[1]); + if (w[1] == (n + '0')) + p = ary[(int)w[1]-'0' - 1]; /* XXX */ + else + p = ary[(int)w[1]-'0']; + p = p->n_left; + + if (optype(p->n_op) != LTYPE) + comperr("bad xarg op %d", p->n_op); + q = tcopy(p); + if (q->n_op == REG) { + if (*w == 'k') { + q->n_type = INT; + } else if (*w == 'q') { + q->n_type = LONG; + } else if (*w == 'h' || *w == 'b') { + /* Can do this only because we know dx is used */ + printf("%%d%c", *w == 'h' ? 'h' : 'l'); + tfree(q); + return; + } else if (*w != 'w') { + cerror("targarg"); /* XXX ??? */ + if (q->n_type > UCHAR) { + regno(q) = regno(q)*2+8; + if (*w == 'h') + regno(q)++; + } + q->n_type = INT; + } else + q->n_type = SHORT; + } + adrput(stdout, q); + tfree(q); +} + +/* + * target-specific conversion of numeric arguments. + */ +int +numconv(void *ip, void *p1, void *q1) +{ + NODE *p = p1, *q = q1; + int cw = xasmcode(q->n_name); + + switch (XASMVAL(cw)) { + case 'a': + case 'b': + case 'c': + case 'd': + p->n_name = tmpcalloc(2); + p->n_name[0] = XASMVAL(cw); + return 1; + default: + return 0; + } +} + +static struct { + char *name; int num; +} xcr[] = { + { "rax", RAX }, + { "rbx", RBX }, + { "rcx", RCX }, + { "rdx", RDX }, + { "rsi", RSI }, + { "rdi", RDI }, + { "r8", R08 }, + { "r9", R09 }, + { "r10", R10 }, + { "r11", R11 }, + { "r12", R12 }, + { "r13", R13 }, + { "r14", R14 }, + { "r15", R15 }, + { "st", 040 }, + { "st(0)", 040 }, + { "st(1)", 041 }, + { "st(2)", 042 }, + { "st(3)", 043 }, + { "st(4)", 044 }, + { "st(5)", 045 }, + { "st(6)", 046 }, + { "st(7)", 047 }, + { NULL, 0 }, +}; + +/* + * Check for other names of the xasm constraints registers. + */ +int xasmconstregs(char *s) +{ + int i; + + for (i = 0; xcr[i].name; i++) + if (strcmp(xcr[i].name, s) == 0) + return xcr[i].num; + return -1; +} + diff --git a/lang/pcc/pcc/arch/amd64/macdefs.h b/lang/pcc/pcc/arch/amd64/macdefs.h new file mode 100644 index 000000000..554830302 --- /dev/null +++ b/lang/pcc/pcc/arch/amd64/macdefs.h @@ -0,0 +1,295 @@ +/* $Id: macdefs.h,v 1.36 2016/03/05 15:49:36 ragge Exp $ */ +/* + * Copyright (c) 2008 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +#define ARGINIT 128 /* # bits above fp where arguments start */ +#define AUTOINIT 0 /* # bits below fp where automatics start */ + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZBOOL 8 +#define SZSHORT 16 +#define SZINT 32 +#define SZLONG 64 +#define SZPOINT(t) 64 +#define SZLONGLONG 64 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 128 + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALBOOL 8 +#define ALSHORT 16 +#define ALINT 32 +#define ALLONG 64 +#define ALPOINT 64 +#define ALLONGLONG 64 +#define ALFLOAT 32 +#define ALDOUBLE 64 +#define ALLDOUBLE 128 +/* #undef ALSTRUCT amd64 struct alignment is member defined */ +#define ALSTACK 64 +#define ALMAX 128 + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT (-0x7fffffff-1) +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffffU +#define MIN_LONG 0x8000000000000000LL +#define MAX_LONG 0x7fffffffffffffffLL +#define MAX_ULONG 0xffffffffffffffffULL +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +/* Default char is signed */ +#undef CHAR_UNSIGNED +#define BOOL_TYPE UCHAR /* what used to store _Bool */ + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#define LABFMT ".L%d" /* format for printing labels */ +#define STABLBL ".LL%d" /* format for stab (debugging) labels */ +#ifdef LANG_F77 +#define BLANKCOMMON "_BLNK_" +#define MSKIREG (M(TYSHORT)|M(TYLONG)) +#define TYIREG TYLONG +#define FSZLENG FSZLONG +#define AUTOREG EBP +#define ARGREG EBP +#define ARGOFFSET 8 +#endif + +#define BACKAUTO /* stack grows negatively for automatics */ +#define BACKTEMP /* stack grows negatively for temporaries */ + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_LE /* little-endian only */ + +#define FINDMOPS /* i386 has instructions that modifies memory */ + +#define CC_DIV_0 /* division by zero is safe in the compiler */ + +#ifdef MACHOABI +#define HASP2ALIGN +#endif + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&07) +#define wdal(k) (BYTEOFF(k)==0) + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) +#define genfcall(a,b) gencall(a,b) + +/* How many integer registers are needed? (used for stack allocation) */ +#define szty(t) (t < LONG || t == FLOAT ? 1 : t == LDOUBLE ? 4 : 2) + +/* + * The amd64 architecture has a much cleaner interface to its registers + * than the x86, even though a part of the register block comes from + * the x86 architecture. Therefore currently only two non-overlapping + * register classes are used; integer and xmm registers. + * + * All registers are given a sequential number to + * identify it which must match rnames[] in local2.c. + * + * The classes used on amd64 are: + * A - integer registers + * B - xmm registers + * C - x87 registers + */ +#define RAX 000 +#define RDX 001 +#define RCX 002 +#define RBX 003 +#define RSI 004 +#define RDI 005 +#define RBP 006 +#define RSP 007 +#define R08 010 +#define R09 011 +#define R10 012 +#define R11 013 +#define R12 014 +#define R13 015 +#define R14 016 +#define R15 017 + +#define XMM0 020 +#define XMM1 021 +#define XMM2 022 +#define XMM3 023 +#define XMM4 024 +#define XMM5 025 +#define XMM6 026 +#define XMM7 027 +#define XMM8 030 +#define XMM9 031 +#define XMM10 032 +#define XMM11 033 +#define XMM12 034 +#define XMM13 035 +#define XMM14 036 +#define XMM15 037 + +#define MAXREGS 050 /* 40 registers */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, 0, 0, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ + SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ + SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ + SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, + + +/* no overlapping registers at all */ +#define ROVERLAP \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, + + +/* Return a register class based on the type of the node */ +#define PCLASS(p) (p->n_type == FLOAT || p->n_type == DOUBLE ? SBREG : \ + p->n_type == LDOUBLE ? SCREG : SAREG) + +#define NUMCLASS 3 /* highest number of reg classes used */ + +int COLORMAP(int c, int *r); +#define GCLASS(x) (x < 16 ? CLASSA : x < 32 ? CLASSB : CLASSC) +#define DECRA(x,y) (((x) >> (y*8)) & 255) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 8) /* A1 */ +#define ENCRA2(x) ((x) << 16) /* A2 */ +#define ENCRA(x,y) ((x) << (8+y*8)) /* encode regs in int */ + +#define RETREG(x) (x == FLOAT || x == DOUBLE ? XMM0 : \ + x == LDOUBLE ? 32 : RAX) + +/* XXX - to die */ +#define FPREG RBP /* frame pointer */ +#define STKREG RSP /* stack pointer */ + +#define SHSTR (MAXSPECIAL+1) /* short struct */ +#define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */ +#define SPCON (MAXSPECIAL+3) /* positive nonnamed constant */ + +/* + * Specials that indicate the applicability of machine idioms. + */ +#define SMIXOR (MAXSPECIAL+4) +#define SMILWXOR (MAXSPECIAL+5) +#define SMIHWXOR (MAXSPECIAL+6) +#define SCON32 (MAXSPECIAL+7) /* 32-bit constant */ + +/* + * i386-specific symbol table flags. + */ +#define SBEENHERE SLOCAL1 + +/* + * Extended assembler macros. + */ +int xasmconstregs(char *); +void targarg(char *w, void *arg, int n); +#define XASM_TARGARG(w, ary) \ + (w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' || \ + w[1] == 'q' ? w++, targarg(w, ary, n), 1 : 0) +int numconv(void *ip, void *p, void *q); +#define XASM_NUMCONV(ip, p, q) numconv(ip, p, q) +#define XASMCONSTREGS(x) xasmconstregs(x) + +#define HAVE_WEAKREF +#define TARGET_FLT_EVAL_METHOD 0 /* all as their type */ +/* + * builtins. + */ +#define TARGET_VALIST +#define TARGET_STDARGS +#define TARGET_BUILTINS \ + { "__builtin_stdarg_start", amd64_builtin_stdarg_start, \ + 0, 2, 0, VOID }, \ + { "__builtin_va_start", amd64_builtin_stdarg_start, \ + 0, 2, 0, VOID }, \ + { "__builtin_va_arg", amd64_builtin_va_arg, BTNORVAL|BTNOPROTO, \ + 2, 0, 0 }, \ + { "__builtin_va_end", amd64_builtin_va_end, 0, 1, 0, VOID }, \ + { "__builtin_va_copy", amd64_builtin_va_copy, 0, 2, 0, VOID }, + +#ifdef LANG_CXX +#define P1ND struct node +#else +#define P1ND struct p1node +#endif +struct node; +struct bitable; +P1ND *amd64_builtin_stdarg_start(const struct bitable *, P1ND *a); +P1ND *amd64_builtin_va_arg(const struct bitable *, P1ND *a); +P1ND *amd64_builtin_va_end(const struct bitable *, P1ND *a); +P1ND *amd64_builtin_va_copy(const struct bitable *, P1ND *a); +#undef P1ND + +/* target specific attributes */ +#define ATTR_MI_TARGET ATTR_AMD64_CMPLRET, ATTR_AMD64_XORLBL diff --git a/lang/pcc/pcc/arch/amd64/order.c b/lang/pcc/pcc/arch/amd64/order.c new file mode 100644 index 000000000..ac43cda57 --- /dev/null +++ b/lang/pcc/pcc/arch/amd64/order.c @@ -0,0 +1,363 @@ +/* $Id: order.c,v 1.18 2015/12/13 09:00:04 ragge Exp $ */ +/* + * Copyright (c) 2008 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +#include + +int canaddr(NODE *); + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + if (off > MAX_INT || off < MIN_INT) + return 1; /* max signed 32-bit offset */ + return(0); /* YES */ +} + +/* + * Check if LS and try to make it indexable. + * Ignore SCONV to long. + * Return 0 if failed. + */ +static int +findls(NODE *p, int check) +{ + CONSZ c; + + if (p->n_op == SCONV && p->n_type == LONG && p->n_left->n_type == INT) + p = p->n_left; /* Ignore pointless SCONVs here */ + if (p->n_op != LS || p->n_right->n_op != ICON) + return 0; + if ((c = getlval(p->n_right)) != 1 && c != 2 && c != 3) + return 0; + if (check == 1 && p->n_left->n_op != REG) + return 0; + if (!isreg(p->n_left)) + (void)geninsn(p->n_left, INAREG); + return 1; +} + +/* + * Turn a UMUL-referenced node into OREG. + * Be careful about register classes, this is a place where classes change. + * + * AMD64 (and i386) have a quite powerful addressing scheme: + * : 4(%rax) 4 + %rax + * : 4(%rbx,%rax,8) 4 + %rbx + %rax * 8 + * : 4(,%rax) 4 + %rax * 8 + * The 8 above can be 1,2,4 or 8. + */ +void +offstar(NODE *p, int shape) +{ + NODE *l; + + if (x2debug) { + printf("offstar(%p)\n", p); + fwalk(p, e2print, 0); + } + + if (isreg(p)) + return; /* Matched (%rax) */ + + if (findls(p, 0)) + return; /* Matched (,%rax,8) */ + + if ((p->n_op == PLUS || p->n_op == MINUS) && + p->n_left->n_op == ICON && + p->n_left->n_name[0] == '\0' && + notoff(0, 0, getlval(p->n_left), 0) == 0) { + l = p->n_right; + if (isreg(l)) + return; /* Matched 4(%rax) */ + if (findls(l, 0)) + return; /* Matched 4(,%rax,8) */ + if (l->n_op == PLUS && isreg(l->n_right)) { + if (findls(l->n_left, 0)) + return; /* Matched 4(%rbx,%rax,8) */ + (void)geninsn(l->n_left, INAREG); + return; /* Generate 4(%rbx,%rax) */ + } + (void)geninsn(l, INAREG); + return; /* Generate 4(%rbx) */ + } + + if (p->n_op == PLUS) { + if (!isreg(p->n_left)) /* ensure right is REG */ + (void)geninsn(p->n_left, INAREG); + if (isreg(p->n_right)) + return; /* Matched (%rax,%rbx) */ + if (findls(p->n_right, 0)) + return; /* Matched (%rax,%rbx,4) */ + (void)geninsn(p->n_right, INAREG); + return; /* Generate (%rbx,%rax) */ + } + + (void)geninsn(p, INAREG); +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + * For simple OREGs conversion should already be done. + */ +void +myormake(NODE *q) +{ + static int shtbl[] = { 1,2,4,8 }; + NODE *p, *r; + CONSZ c = 0; + int r1, r2, sh; + int mkconv = 0; + char *n = ""; + +#define risreg(p) (p->n_op == REG) + if (x2debug) { + printf("myormake(%p)\n", q); + fwalk(q, e2print, 0); + } + r1 = r2 = MAXREGS; + sh = 1; + + r = p = q->n_left; + + if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_left->n_op == ICON) { + c = getlval(p->n_left); + n = p->n_left->n_name; + p = p->n_right; + } + + if (p->n_op == PLUS && risreg(p->n_left)) { + r1 = regno(p->n_left); + p = p->n_right; + } + + if (findls(p, 1)) { + if (p->n_op == SCONV) + p = p->n_left; + sh = shtbl[(int)getlval(p->n_right)]; + r2 = regno(p->n_left); + mkconv = 1; + } else if (risreg(p)) { + r2 = regno(p); + mkconv = 1; + } //else + // comperr("bad myormake tree"); + + if (mkconv == 0) + return; + + q->n_op = OREG; + setlval(q, c); + q->n_rval = R2PACK(r1, r2, sh); + q->n_name = n; + tfree(r); + if (x2debug) { + printf("myormake converted %p\n", q); + fwalk(q, e2print, 0); + } +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Turns currently anything into OREG on x86 */ + if (shape & SOREG) + return SROREG; + return SRNOPE; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + case SCONV: + if ((q->ltype & TINT) && + q->rtype == (TLONGLONG|TULONGLONG|TLONG|TULONG)) { + static struct rspecial s[] = { + { NLEFT, RAX }, { NRES, RAX }, { 0 } }; + return s; + } + break; + + case DIV: + { + static struct rspecial s[] = { + { NEVER, RAX }, { NEVER, RDX }, + { NLEFT, RAX }, { NRES, RAX }, + { NORIGHT, RDX }, { NORIGHT, RAX }, { 0 } }; + return s; + } + break; + + case MOD: + if (q->ltype & TUCHAR) { + static struct rspecial s[] = { + { NEVER, RAX }, + { NLEFT, RAX }, { NRES, RAX }, + { NORIGHT, RAX }, { 0 } }; + return s; + } else { + static struct rspecial s[] = { + { NEVER, RAX }, { NEVER, RDX }, + { NLEFT, RAX }, { NRES, RDX }, + { NORIGHT, RDX }, { NORIGHT, RAX }, { 0 } }; + return s; + } + break; + + case STARG: + { + static struct rspecial s[] = { + { NEVER, RDI }, + { NLEFT, RSI }, + { NEVER, RCX }, { 0 } }; + return s; + } + + case STASG: + { + static struct rspecial s[] = { + { NEVER, RDI }, + { NRIGHT, RSI }, { NOLEFT, RSI }, + { NOLEFT, RCX }, { NORIGHT, RCX }, + { NEVER, RCX }, { 0 } }; + return s; + } + + case MUL: + if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NEVER, RAX }, + { NLEFT, RAX }, { NRES, RAX }, { 0 } }; + return s; + } + break; + + case LS: + case RS: + { + static struct rspecial s[] = { + { NRIGHT, RCX }, { NOLEFT, RCX }, { 0 } }; + return s; + } + break; + + default: + break; + } + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; /* nothing differs on x86 */ +} + +/* + * set registers in calling conventions live. + */ +int * +livecall(NODE *p) +{ + static int r[NTEMPREG+1]; + NODE *q; + int cr = 0; + + if (optype(p->n_op) != BITYPE) + return r[0] = -1, r; + + for (q = p->n_right; q->n_op == CM; q = q->n_left) { + if (q->n_right->n_op == ASSIGN && + q->n_right->n_left->n_op == REG) + r[cr++] = regno(q->n_right->n_left); + } + if (q->n_op == ASSIGN && q->n_left->n_op == REG) + r[cr++] = regno(q->n_left); + r[cr++] = -1; + return r; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/amd64/table.c b/lang/pcc/pcc/arch/amd64/table.c new file mode 100644 index 000000000..332cadc82 --- /dev/null +++ b/lang/pcc/pcc/arch/amd64/table.c @@ -0,0 +1,1594 @@ +/* $Id: table.c,v 1.55 2015/02/07 08:47:54 ragge Exp $ */ +/* + * Copyright (c) 2008 Michael Shalayeff + * Copyright (c) 2008 Anders Magnusson (ragge@ludd.ltu.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +#define TLL TLONG|TULONG +# define ANYSIGNED TINT|TSHORT|TCHAR +# define ANYUSIGNED TUNSIGNED|TUSHORT|TUCHAR +# define ANYFIXED ANYSIGNED|ANYUSIGNED +# define TUWORD TUNSIGNED +# define TSWORD TINT +# define TWORD TUWORD|TSWORD +#define TANYINT TLL|ANYFIXED +#define SHINT SAREG /* Any integer */ +#define ININT INAREG +#define SHFL SCREG /* shape for long double */ +#define INFL INCREG /* shape for long double */ + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are usually not necessary */ +{ PCONV, INAREG, + SAREG, TLL|TPOINT, + SAREG, TLL|TPOINT, + 0, RLEFT, + "", }, + +{ PCONV, INAREG, + SAREG|SOREG|SNAME, TWORD, + SAREG, TPOINT, + NASL|NAREG, RESC1, + " movl AL,Z1\n", },/* amd64 zero-extends 32-bit movl */ + +{ PCONV, INAREG, + SAREG|SOREG|SNAME, TCHAR, + SAREG, TPOINT, + NAREG|NASL, RESC1, + " movsbq AL,A1\n", }, + +{ PCONV, INAREG, + SAREG|SOREG|SNAME, TUCHAR, + SAREG, TPOINT, + NAREG|NASL, RESC1, + " movsbq AL,A1\n", }, + +/* short to ptr */ +{ PCONV, INAREG, + SAREG|SOREG|SNAME, TSHORT, + SAREG, TPOINT, + NAREG|NASL, RESC1, + " movswq AL,A1\n", }, + +/* ushort to ptr */ +{ PCONV, INAREG, + SAREG|SOREG|SNAME, TUSHORT, + SAREG, TPOINT, + NAREG|NASL, RESC1, + " movzwq AL,A1\n", }, + + +/* + * On amd64 casts from larger to smaller integer type in register do nothing. + */ +/* 64-bit to smaller */ +{ SCONV, INAREG, + SAREG, TLL|TPOINT, + SAREG, TANYINT, + 0, RLEFT, + "", }, + +/* 32-bit to smaller */ +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, ANYFIXED, + 0, RLEFT, + "", }, + +/* 16-bit to smaller */ +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG, TUSHORT|TUCHAR|TSHORT|TCHAR, + 0, RLEFT, + "", }, + +/* 8-bit to 8-bit */ +{ SCONV, INAREG, + SAREG, TCHAR|TUCHAR, + SAREG, TUCHAR|TCHAR, + 0, RLEFT, + "", }, + +/* + * Casts from memory to same or smaller register is equally simple. + */ +/* 64-bit to smaller */ +{ SCONV, INAREG, + SNAME|SOREG, TLL|TPOINT, + SAREG, TANYINT, + NAREG, RESC1, + " movZR AL,A1\n", }, + +/* 32-bit to smaller */ +{ SCONV, INAREG, + SNAME|SOREG, TWORD, + SAREG, ANYFIXED, + NAREG, RESC1, + " movZR AL,A1\n", }, + +/* 16-bit to smaller */ +{ SCONV, INAREG, + SNAME|SOREG, TSHORT|TUSHORT, + SAREG, TUSHORT|TUCHAR|TSHORT|TCHAR, + NAREG, RESC1, + " movZR AL,A1\n", }, + +/* 8-bit to 8-bit */ +{ SCONV, INAREG, + SNAME|SOREG, TCHAR|TUCHAR, + SAREG, TUCHAR|TCHAR, + NAREG, RESC1, + " movZR AL,A1\n", }, + + +/* char to something */ + +/* convert char to (unsigned) short. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TCHAR, + SAREG, TSHORT|TUSHORT, + NASL|NAREG, RESC1, + " movsbw AL,A1\n", }, + +/* convert unsigned char to (u)short. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TUCHAR, + SAREG, TSHORT|TUSHORT, + NASL|NAREG, RESC1, + " movzbw AL,A1\n", }, + +/* convert signed char to int (or pointer). */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TCHAR, + SAREG, TWORD|TPOINT, + NASL|NAREG, RESC1, + " movsbl AL,A1\n", }, + +/* convert unsigned char to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TUCHAR, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movzbl AL,A1\n", }, + +/* convert char to (u)long long */ +{ SCONV, INAREG, + SAREG|SOREG|SNAME, TCHAR, + SANY, TLL, + NAREG|NASL, RESC1, + " movsbq AL,A1\n", }, + +/* convert unsigned char to (u)long long */ +{ SCONV, INAREG, + SAREG|SOREG|SNAME, TUCHAR, + SANY, TLL, + NAREG|NASL, RESC1, + " movzbq AL,A1\n", }, + +/* short to something */ + +/* convert short to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movswl AL,A1\n", }, + +/* convert unsigned short to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TUSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movzwl AL,A1\n", }, + +/* convert short to (u)long long */ +{ SCONV, INAREG, + SAREG|SOREG|SNAME, TSHORT, + SAREG, TLL, + NAREG|NASL, RESC1, + " movswq AL,A1\n", }, + +/* convert unsigned short to (u)long long */ +{ SCONV, INAREG, + SAREG|SOREG|SNAME, TUSHORT, + SAREG, TLL, + NAREG|NASL, RESC1, + " movzwq AL,A1\n", }, + +/* int to something */ + +/* convert signed int to (u)long long */ +{ SCONV, INAREG, + SAREG, TSWORD, + SAREG, TLL, + NASL|NAREG, RESC1, + " movslq AL,A1\n", }, + +/* convert unsigned int to (u)long long */ +{ SCONV, INAREG, + SAREG|SOREG|SNAME, TUWORD, + SAREG, TLL, + NASL|NAREG, RESC1, + " movl AL,Z1\n", },/* amd64 zero-extends 32-bit movl */ + +/* + * Floating point casts. amd64 uses xmm for float/double and x87 + * for long double calculations. + * + * Types smaller than int are casted to int/(unsigned). + */ +/* no casts */ +{ SCONV, INBREG, + SBREG, TFLOAT, + SBREG, TFLOAT, + 0, RLEFT, + "", }, + +{ SCONV, INBREG, + SBREG, TDOUBLE, + SBREG, TDOUBLE, + 0, RLEFT, + "", }, + +{ SCONV, INCREG, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + 0, RLEFT, + "", }, + + +/* convert int/long to float/double */ +{ SCONV, INBREG, + SAREG|SOREG|SNAME, TINT|TLONG, + SBREG, TFLOAT|TDOUBLE, + NBREG, RESC1, + " cvtsi2sZfZq AL,A1\n", }, + +/* convert unsigned int to float/double */ +{ SCONV, INBREG, + SAREG|SOREG|SNAME, TUNSIGNED, + SBREG, TFLOAT|TDOUBLE, + NAREG|NBREG, RESC2, + " movl AL,Z1\n cvtsi2sZfq A1,A2\n", }, + +/* convert unsigned long to float/double */ +{ SCONV, INBREG, + SAREG|SOREG|SNAME, TULONG, + SBREG, TFLOAT|TDOUBLE, + NAREG*2|NASL|NBREG, RESC3, + "Zj", }, + +/* convert float/double to (u)char/(u)short/int */ +{ SCONV, INAREG, + SBREG|SOREG|SNAME, TFLOAT|TDOUBLE, + SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|INT, + NAREG, RESC1, + " cvttsZg2si AL,A1\n", }, + +/* convert float/double to unsigned int/long */ +{ SCONV, INAREG, + SBREG|SOREG|SNAME, TFLOAT|TDOUBLE, + SAREG, TUNSIGNED|TLONG, + NAREG, RESC1, + " cvttsZg2siq AL,Z8\n", }, + +/* convert float to double */ +{ SCONV, INBREG, + SBREG|SNAME|SOREG, TFLOAT, + SBREG, TDOUBLE, + NBREG|NBSL, RESC1, + " cvtss2sd AL,A1\n", }, + +/* convert double to float */ +{ SCONV, INBREG, + SBREG|SNAME|SOREG, TDOUBLE, + SBREG, TFLOAT, + NBREG|NBSL, RESC1, + " cvtsd2ss AL,A1\n", }, + +/* x87 conversions */ +/* float -> ldouble */ +{ SCONV, INCREG, + SBREG, TFLOAT, + SCREG, TLDOUBLE, + NCREG, RESC1, + "\tsubq $4,%rsp\n\tmovss AL,(%rsp)\n" + "\tflds (%rsp)\n\taddq $4,%rsp\n", }, + +/* double -> ldouble */ +{ SCONV, INCREG, + SBREG, TDOUBLE, + SCREG, TLDOUBLE, + NCREG, RESC1, + "\tsubq $8,%rsp\n\tmovsd AL,(%rsp)\n" + "\tfldl (%rsp)\n\taddq $8,%rsp\n", }, + +/* ldouble -> double */ +{ SCONV, INBREG, + SCREG, TLDOUBLE, + SBREG, TDOUBLE, + NBREG, RESC1, + "\tsubq $8,%rsp\n\tfstpl (%rsp)\n" + "\tmovsd (%rsp),A1\n\taddq $8,%rsp\n", }, + +/* ldouble -> float */ +{ SCONV, INBREG, + SCREG, TLDOUBLE, + SBREG, TFLOAT, + NBREG, RESC1, + "\tsubq $4,%rsp\n\tfstps (%rsp)\n" + "\tmovss (%rsp),A1\n\taddq $4,%rsp\n", }, + +/* convert int (in memory) to long double */ +{ SCONV, INCREG, + SOREG|SNAME, TSWORD, + SCREG, TLDOUBLE, + NCREG, RESC1, + " fildl AL\n", }, + +/* convert unsigned int to long double */ +{ SCONV, INCREG, + SAREG, TUWORD, + SCREG, TLDOUBLE, + NAREG|NASL|NCREG, RESC2, + " subq $16,%rsp\n" + " movl AL,Z1\n" + " movq A1,(%rsp)\n" + " fildll (%rsp)\n" + " addq $16,%rsp\n", }, + +/* convert int (in register) to long double */ +{ SCONV, INCREG, + SAREG, TSWORD, + SCREG, TLDOUBLE, + NCREG, RESC1, + " subq $4,%rsp\n" + " movl AL,(%rsp)\n" + " fildl (%rsp)\n" + " addq $4,%rsp\n", }, + +/* unsigned long (in reg) to long double */ +{ SCONV, INCREG, + SAREG, TULONG, + SCREG, TLDOUBLE, + NCREG, RESC1, + " subq $16,%rsp\n" + " movq AL,(%rsp)\n" + " fildll (%rsp)\n" + " cmpq $0,AL\n" + " jns 1f\n" + " movl $1602224128,(%rsp)\n" + " fadds (%rsp)\n" + " addq $16,%rsp\n" + "1:\n", }, + +/* unsigned long (in mem) to long double */ +{ SCONV, INCREG, + SNAME|SOREG, TULONG, + SCREG, TLDOUBLE, + NCREG, RESC1, + " fildll AL\n" + " cmpq $0,AL\n" + " jns 1f\n" + " push $1602224128\n" + " fadds (%rsp)\n" + " addq $8,%rsp\n" + "1:\n", }, + +/* convert float/double to unsigned long */ +{ SCONV, INAREG, + SBREG, TFLOAT|TDOUBLE, + SAREG, TULONG, + (NAREG*2)|NBREG, RESC1, + "Zb\n", }, + +/* long double to unsigned long */ +{ SCONV, INAREG, + SCREG|SNAME|SOREG, TLDOUBLE, + SAREG, TULONG, + NAREG, RESC1, + "ZB", }, + +/* ldouble -> long XXX merge with int */ +{ SCONV, INAREG, + SCREG, TLDOUBLE, + SAREG, TLONG, + NAREG, RESC1, + " subq $16,%rsp\n" + " fnstcw (%rsp)\n" + " fnstcw 4(%rsp)\n" + " movb $12,1(%rsp)\n" + " fldcw (%rsp)\n" + " fistpll 8(%rsp)\n" + " movq 8(%rsp),A1\n" + " fldcw 4(%rsp)\n" + " addq $16,%rsp\n", }, + +/* ldouble -> (u)int */ +{ SCONV, INAREG, + SCREG, TLDOUBLE, + SAREG, TINT|TUNSIGNED, + NAREG, RESC1, + " subq $16,%rsp\n" + " fnstcw (%rsp)\n" + " fnstcw 4(%rsp)\n" + " movb $12,1(%rsp)\n" + " fldcw (%rsp)\n" + " fistpq 8(%rsp)\n" + " movl 8(%rsp),A1\n" + " fldcw 4(%rsp)\n" + " addq $16,%rsp\n", }, + +/* long (in mem) -> ldouble */ +{ SCONV, INCREG, + SNAME|SOREG, TLONG, + SCREG, TLDOUBLE, + NCREG, RESC1, + " fildll AL\n", }, + +/* long (in reg) -> ldouble */ +{ SCONV, INCREG, + SAREG, TLONG, + SCREG, TLDOUBLE, + NCREG, RESC1, + " subq $16,%rsp\n" + " movq AL,(%rsp)\n" + " fildll (%rsp)\n" + " addq $16,%rsp\n", }, + + + +/* slut sconv */ + +/* + * Subroutine calls. + */ + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " call CL\nZC", }, + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " call CL\n", }, + +{ CALL, INAREG, + SCON, TANY, + SAREG, TLL|ANYFIXED|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INAREG, + SCON, TANY, + SAREG, TLL|ANYFIXED|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\n", }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INBREG, + SCON, TANY, + SBREG, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ CALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +/* struct return */ +{ USTCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + "ZP call CL\nZC", }, + +{ USTCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call CL\nZC", }, + +{ USTCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call *AL\nZC", }, + +{ STCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + "ZP call CL\nZC", }, + +{ STCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call CL\nZC", }, + +{ STCALL, FOREFF, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, 0, /* should be 0 */ + "ZP call *AL\nZC", }, + +{ STCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call *AL\nZC", }, + +/* + * The next rules handle all binop-style operators. + */ +/* floating point add */ +{ PLUS, INBREG, + SBREG, TFLOAT|TDOUBLE, + SBREG|SNAME|SOREG, TFLOAT|TDOUBLE, + 0, RLEFT, + " addsZf AR,AL\n", }, + +{ PLUS, INCREG|FOREFF, + SHFL, TLDOUBLE, + SHFL, TLDOUBLE, + 0, RLEFT, + " faddp\n", }, + + +{ PLUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TLL|TPOINT, + SONE, TANY, + 0, RLEFT, + " incq AL\n", }, + +{ PLUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD, + SONE, TANY, + 0, RLEFT, + " incl AL\n", }, + +{ PLUS, INAREG, + SAREG, TLL|TPOINT, + SCON, TWORD, + NAREG|NASL, RESC1, + " leaq CR(AL),A1\n", }, + +#ifdef notdef +/* older binutils are missing leal */ +{ PLUS, INAREG, + SAREG, TWORD, + SCON, TANY, + NAREG|NASL, RESC1, + " leal CR(AL),A1\n", }, +#endif + +{ PLUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SONE, TANY, + 0, RLEFT, + " incw AL\n", }, + +{ PLUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SONE, TANY, + 0, RLEFT, + " incb AL\n", }, + +#ifdef notdef +/* older binutils are missing leal */ +{ PLUS, INAREG, + SAREG, TWORD, + SAREG, TWORD, + NAREG|NASL|NASR, RESC1, + " leal (AL,AR),A1\n", }, +#endif + +{ MINUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TLL|TPOINT, + SONE, TANY, + 0, RLEFT, + " decq AL\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD, + SONE, TANY, + 0, RLEFT, + " decl AL\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SONE, TANY, + 0, RLEFT, + " decw AL\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SONE, TANY, + 0, RLEFT, + " decb AL\n", }, + +/* address as register offset, negative */ +{ MINUS, INAREG, + SAREG, TLL|TPOINT, + SPCON, TANY, + NAREG|NASL, RESC1, + " leaq -CR(AL),A1\n", }, + +{ MINUS, INBREG|FOREFF, + SBREG, TDOUBLE|TFLOAT, + SBREG|SNAME|SOREG, TDOUBLE|TFLOAT, + 0, RLEFT, + " subsZf AR,AL\n", }, + +{ MINUS, INCREG|FOREFF, + SHFL, TLDOUBLE, + SHFL, TLDOUBLE, + 0, RLEFT, + " fsubZAp\n", }, + +/* Simple r/m->reg ops */ +/* m/r |= r */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG|SNAME|SOREG, TLL|TPOINT, + SAREG, TLL|TPOINT, + 0, RLEFT|RESCC, + " Oq AR,AL\n", }, + +/* r |= r/m */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG, TLL|TPOINT, + SAREG|SNAME|SOREG, TLL|TPOINT, + 0, RLEFT|RESCC, + " Oq AR,AL\n", }, + +/* m/r |= r */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG|SNAME|SOREG, TWORD, + SAREG, TWORD, + 0, RLEFT|RESCC, + " Ol AR,AL\n", }, + +/* r |= r/m */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG, TWORD, + SAREG|SNAME|SOREG, TWORD, + 0, RLEFT|RESCC, + " Ol AR,AL\n", }, + +/* m/r |= r */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + SHINT, TSHORT|TUSHORT, + 0, RLEFT|RESCC, + " Ow AR,AL\n", }, + +/* r |= r/m */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SHINT, TSHORT|TUSHORT, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + 0, RLEFT|RESCC, + " Ow AR,AL\n", }, + +/* m/r |= r */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG, TCHAR|TUCHAR, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + " Ob AR,AL\n", }, + +/* r |= r/m */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG, TCHAR|TUCHAR, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + " Ob AR,AL\n", }, + +/* m/r |= const */ +#ifdef notdef /* amd64 lacks immediate 64-bit simple ops */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG|SNAME|SOREG, TLL|TPOINT, + SCON, TANY, + 0, RLEFT|RESCC, + " Oq AR,AL\n", }, +#endif + +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG|SNAME|SOREG, TWORD, + SCON, TANY, + 0, RLEFT|RESCC, + " Ol AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF|FORCC, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RLEFT|RESCC, + " Ow AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT|RESCC, + " Ob AR,AL\n", }, + +/* + * The next rules handle all shift operators. + */ +/* r/m <<= r */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TLL, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " salq AR,AL\n", }, + +/* r/m <<= const */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TLL, + SCON, TANY, + 0, RLEFT, + " salq AR,AL\n", }, + +/* r/m <<= r */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sall AR,AL\n", }, + +/* r/m <<= const */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD, + SCON, TANY, + 0, RLEFT, + " sall AR,AL\n", }, + +/* r/m <<= r */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shlw AR,AL\n", }, + +/* r/m <<= const */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RLEFT, + " shlw AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " salb AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT, + " salb AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TLONG|TLONGLONG, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarq AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TLONG|TLONGLONG, + SCON, TANY, + 0, RLEFT, + " sarq AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TULONG|TULONGLONG, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrq AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TULONG|TULONGLONG, + SCON, TANY, + 0, RLEFT, + " shrq AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSWORD, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSWORD, + SCON, TANY, + 0, RLEFT, + " sarl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUWORD, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUWORD, + SCON, TANY, + 0, RLEFT, + " shrl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SCON, TANY, + 0, RLEFT, + " sarw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SCON, TANY, + 0, RLEFT, + " shrw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TCHAR, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarb AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TCHAR, + SCON, TANY, + 0, RLEFT, + " sarb AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUCHAR, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrb AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUCHAR, + SCON, TANY, + 0, RLEFT, + " shrb AR,AL\n", }, + +/* + * The next rules takes care of assignments. "=". + */ +{ ASSIGN, FORCC|FOREFF|INAREG, + SAREG, TLL|TPOINT, + SMIXOR, TANY, + 0, RDEST, + " xorq AL,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TLL|TPOINT, + SCON, TANY, + 0, RDEST, + " movabs AR,AL\n", }, + +{ ASSIGN, FORCC|FOREFF|INAREG, + SAREG, TWORD, + SMIXOR, TANY, + 0, RDEST, + " xorl AL,AL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TWORD, + SCON, TANY, + 0, 0, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD, + SCON, TANY, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FORCC|FOREFF|INAREG, + SAREG, TSHORT|TUSHORT, + SMIXOR, TANY, + 0, RDEST, + " xorw AL,AL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, 0, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RDEST, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, 0, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RDEST, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TLL|TPOINT, + SAREG, TLL|TPOINT, + 0, RDEST, + " movq AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TWORD, + SAREG, TWORD, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD, + SAREG|SNAME|SOREG, TWORD, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TPOINT, + SAREG|SNAME|SOREG, TPOINT, + 0, RDEST, + " movq AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RDEST, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR|TWORD, + 0, RDEST, + " movb AR,AL\n", }, + +{ ASSIGN, INBREG|FOREFF, + SBREG, TFLOAT|TDOUBLE, + SBREG|SOREG|SNAME, TFLOAT|TDOUBLE, + 0, RDEST, + " movsZf AR,AL\n", }, + +{ ASSIGN, INBREG|FOREFF, + SBREG|SOREG|SNAME, TFLOAT|TDOUBLE, + SBREG, TFLOAT|TDOUBLE, + 0, RDEST, + " movsZf AR,AL\n", }, + +/* x87 entries */ +{ ASSIGN, INDREG|FOREFF, + SHFL, TLDOUBLE, + SHFL, TLDOUBLE, + 0, RDEST, + "", }, /* This will always be in the correct register */ + +/* order of table entries is very important here! */ +{ ASSIGN, INFL, + SNAME|SOREG, TLDOUBLE, + SHFL, TLDOUBLE, + 0, RDEST, + " fstpt AL\n fldt AL\n", }, /* XXX */ + +{ ASSIGN, FOREFF, + SNAME|SOREG, TLDOUBLE, + SHFL, TLDOUBLE, + 0, 0, + " fstpt AL\n", }, + +/* end very important order */ + +{ ASSIGN, INFL|FOREFF, + SHFL, TLDOUBLE, + SHFL|SOREG|SNAME, TLDOUBLE, + 0, RDEST, + " fldt AR\n", }, + +/* end x87 */ + +/* Do not generate memcpy if return from funcall */ +#if 0 +{ STASG, INAREG|FOREFF, + SOREG|SNAME|SAREG, TPTRTO|TSTRUCT, + SFUNCALL, TPTRTO|TSTRUCT, + 0, RRIGHT, + "", }, +#endif + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG, TPTRTO|TANY, + NSPECIAL|NAREG, RDEST, + "F movq AR,A1\nZQF movq A1,AR\n", }, + +/* + * DIV/MOD/MUL + */ +{ DIV, INAREG, + SAREG, TLONG, + SAREG|SNAME|SOREG, TLL, + NSPECIAL, RDEST, + " cqto\n idivq AR\n", }, + +{ DIV, INAREG, + SAREG, TULONG|TPOINT, + SAREG|SNAME|SOREG, TLL|TPOINT, + NSPECIAL, RDEST, + " xorq %rdx,%rdx\n divq AR\n", }, + +{ DIV, INAREG, + SAREG, TSWORD, + SAREG|SNAME|SOREG, TWORD, + NSPECIAL, RDEST, + " cltd\n idivl AR\n", }, + +{ DIV, INAREG, + SAREG, TUWORD, + SAREG|SNAME|SOREG, TWORD, + NSPECIAL, RDEST, + " xorl %edx,%edx\n divl AR\n", }, + +{ DIV, INAREG, + SAREG, TUSHORT, + SAREG|SNAME|SOREG, TUSHORT, + NSPECIAL, RDEST, + " xorl %edx,%edx\n divw AR\n", }, + +{ DIV, INAREG, + SAREG, TUCHAR, + SAREG|SNAME|SOREG, TUCHAR, + NSPECIAL, RDEST, + " xorb %ah,%ah\n divb AR\n", }, + +{ DIV, INBREG, + SBREG, TFLOAT|TDOUBLE, + SBREG|SNAME|SOREG, TFLOAT|TDOUBLE, + 0, RLEFT, + " divsZf AR,AL\n", }, + +{ DIV, INCREG, + SHFL, TLDOUBLE, + SHFL, TLDOUBLE, + 0, RLEFT, + " fdivZAp\n", }, + +{ MOD, INAREG, + SAREG, TLONG, + SAREG|SNAME|SOREG, TLONG, + NAREG|NSPECIAL, RESC1, + " cqto\n idivq AR\n", }, + +{ MOD, INAREG, + SAREG, TLL|TPOINT, + SAREG|SNAME|SOREG, TULONG|TPOINT, + NAREG|NSPECIAL, RESC1, + " xorq %rdx,%rdx\n divq AR\n", }, + +{ MOD, INAREG, + SAREG, TSWORD, + SAREG|SNAME|SOREG, TSWORD, + NAREG|NSPECIAL, RESC1, + " cltd\n idivl AR\n", }, + +{ MOD, INAREG, + SAREG, TWORD, + SAREG|SNAME|SOREG, TUWORD, + NAREG|NSPECIAL, RESC1, + " xorl %edx,%edx\n divl AR\n", }, + +{ MOD, INAREG, + SAREG, TUSHORT, + SAREG|SNAME|SOREG, TUSHORT, + NAREG|NSPECIAL, RESC1, + " xorl %edx,%edx\n divw AR\n", }, + +{ MOD, INAREG, + SAREG, TUCHAR, + SAREG|SNAME|SOREG, TUCHAR, + NAREG|NSPECIAL, RESC1, + " xorb %ah,%ah\n divb AR\n movb %ah,%al\n", }, + +{ MUL, INAREG, + SAREG, TLL|TPOINT, + SAREG|SNAME|SOREG, TLL|TPOINT, + 0, RLEFT, + " imulq AR,AL\n", }, + +{ MUL, INAREG, + SAREG, TWORD, + SAREG|SNAME|SOREG|SCON, TWORD, + 0, RLEFT, + " imull AR,AL\n", }, + +{ MUL, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + 0, RLEFT, + " imulw AR,AL\n", }, + +{ MUL, INAREG, + SAREG, TCHAR|TUCHAR, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " imulb AR\n", }, + +{ MUL, INBREG, + SBREG, TFLOAT|TDOUBLE, + SBREG|SNAME|SOREG, TFLOAT|TDOUBLE, + 0, RLEFT, + " mulsZf AR,AL\n", }, + +{ MUL, INCREG, + SHFL, TLDOUBLE, + SHFL, TLDOUBLE, + 0, RLEFT, + " fmulp\n", }, + +/* + * Indirection operators. + */ +{ UMUL, INAREG, + SANY, TANY, + SOREG, TLL|TPOINT, + NAREG, RESC1, + " movq AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TWORD, + SOREG, TWORD, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " movb AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " movw AL,A1\n", }, + +{ UMUL, INBREG, + SANY, TANY, + SOREG, TFLOAT|TDOUBLE, + NBREG|NBSL, RESC1, + " movsZf AL,A1\n", }, + +{ UMUL, INCREG, + SANY, TANY, + SOREG, TLDOUBLE, + NCREG|NCSL, RESC1, + " fldt AL\n", }, + +/* + * Logical/branching operators + */ + +/* Comparisions, take care of everything */ + +{ OPLOG, FORCC, + SAREG, TLL|TPOINT, + SAREG|SOREG|SNAME, TLL|TPOINT, + 0, RESCC, + " cmpq AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TLL|TPOINT, + SAREG, TLL|TPOINT, + 0, RESCC, + " cmpq AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TLL|TPOINT, + SCON32, TANY, + 0, RESCC, + " cmpq AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TWORD, + SCON|SAREG, TWORD, + 0, RESCC, + " cmpl AR,AL\n", }, + +{ OPLOG, FORCC, + /* SCON| XXX fix switch in tree of L/R */ SAREG, TWORD, + SAREG|SOREG|SNAME, TWORD, + 0, RESCC, + " cmpl AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + SCON|SAREG, TANY, + 0, RESCC, + " cmpw AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TCHAR|TUCHAR, + SCON|SAREG, TANY, + 0, RESCC, + " cmpb AR,AL\n", }, + +{ OPLOG, FORCC, + SBREG, TDOUBLE|TFLOAT, + SBREG|SNAME|SOREG, TDOUBLE|TFLOAT, + 0, RNOP, + " ucomisZg AR,AL\nZU\n", }, + +/* x87 */ +{ OPLOG, FORCC, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + 0, RNOP, + "ZG", }, + +{ OPLOG, FORCC, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "diediedie!", }, + +/* AND/OR/ER/NOT */ +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TLL, + SCON, TWORD, + 0, RLEFT, + " andq AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TLL, + SAREG, TLL, + 0, RLEFT, + " andq AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TLL, + SAREG|SOREG|SNAME, TLL, + 0, RLEFT, + " andq AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TWORD, + SCON|SAREG, TWORD, + 0, RLEFT, + " andl AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TWORD, + SAREG|SOREG|SNAME, TWORD, + 0, RLEFT, + " andl AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + SCON|SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " andw AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TSHORT|TUSHORT, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + 0, RLEFT, + " andw AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TCHAR|TUCHAR, + SCON|SAREG, TCHAR|TUCHAR, + 0, RLEFT, + " andb AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TCHAR|TUCHAR, + SAREG|SOREG|SNAME, TCHAR|TUCHAR, + 0, RLEFT, + " andb AR,AL\n", }, +/* AND/OR/ER/NOT */ + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jmp LL\n", }, + +#if defined(GCC_COMPAT) || defined(LANG_F77) +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " jmp *AL\n", }, +#endif + +/* + * Convert LTYPE to reg. + */ +{ OPLTYPE, FORCC|INAREG, + SAREG, TLL|TPOINT, + SMIXOR, TANY, + NAREG, RESC1, + " xorq A1,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON, TLL|TPOINT, + NAREG, RESC1, + " movabsq AL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TLL|TPOINT, + NAREG, RESC1, + " movq AL,A1\n", }, + +{ OPLTYPE, FORCC|INAREG, + SAREG, TWORD, + SMIXOR, TANY, + NAREG|NASL, RESC1, + " xorl A1,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TWORD, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, + NAREG, RESC1, + " movb AL,A1\n", }, + +{ OPLTYPE, FORCC|INAREG, + SAREG, TSHORT|TUSHORT, + SMIXOR, TANY, + NAREG, RESC1, + " xorw A1,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT, + NAREG, RESC1, + " movw AL,A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TFLOAT|TDOUBLE, + SOREG|SNAME|SBREG, TFLOAT|TDOUBLE, + NBREG, RESC1, + " movsZf AL,A1\n", }, + +/* x87 entry */ +{ OPLTYPE, INCREG, + SANY, TLDOUBLE, + SOREG|SNAME, TLDOUBLE, + NCREG, RESC1, + " fldt AL\n", }, + +/* load float 0.0 */ +{ FCON, INBREG, + SANY, TFLOAT|TDOUBLE, + SANY, TFLOAT|TDOUBLE, + NBREG, RESC1, + " xorpZf A1,A1\n", }, + +{ FCON, INCREG, + SANY, TLDOUBLE, + SANY, TLDOUBLE, + NCREG, RESC1, + " fldz\n", }, + + +/* + * Negate a word. + */ + +{ UMINUS, INAREG|FOREFF, + SAREG, TLL|TPOINT, + SAREG, TLL|TPOINT, + 0, RLEFT, + " negq AL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TWORD, + SAREG, TWORD, + 0, RLEFT, + " negl AL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " negw AL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + 0, RLEFT, + " negb AL\n", }, + +{ UMINUS, INBREG, + SBREG, TDOUBLE|TFLOAT, + SBREG, TDOUBLE|TFLOAT, + 0, RLEFT, + " xorpZf Zc(%rip),AL\n", }, + +{ UMINUS, INCREG, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + 0, RLEFT, + " fchs\n", }, + +{ COMPL, INAREG, + SAREG, TLL, + SANY, TANY, + 0, RLEFT, + " notq AL\n", }, + +{ COMPL, INAREG, + SAREG, TWORD, + SANY, TANY, + 0, RLEFT, + " notl AL\n", }, + +{ COMPL, INAREG, + SAREG, TSHORT|TUSHORT, + SANY, TANY, + 0, RLEFT, + " notw AL\n", }, + +{ COMPL, INAREG, + SAREG, TCHAR|TUCHAR, + SANY, TANY, + 0, RLEFT, + " notb AL\n", }, + +{ STARG, FOREFF, + SAREG|SOREG|SNAME|SCON, TANY, + SANY, TSTRUCT, + NSPECIAL, 0, + "ZF", }, + +{ ADDROF, INAREG, + SNAME, TANY, + SANY, TANY, + NAREG, RESC1, + " leaq AL,A1\n", }, + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +/* { INIT, DF(INIT), }, */ + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/arm/code.c b/lang/pcc/pcc/arch/arm/code.c new file mode 100644 index 000000000..cdd41fde4 --- /dev/null +++ b/lang/pcc/pcc/arch/arm/code.c @@ -0,0 +1,897 @@ +/* $Id: code.c,v 1.30 2016/03/09 18:19:56 ragge Exp $ */ +/* + * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org). + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Stuff for pass1. + */ + +#include + +#include "pass1.h" +#include "pass2.h" + +#ifdef LANG_CXX +#define p1listf listf +#define p1tfree tfree +#else +#define NODE P1ND +#define talloc p1alloc +#define tcopy p1tcopy +#define nfree p1nfree +#endif + +static int rvnr; + +/* + * Print out assembler segment name. + */ +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + case DATA: + case LDATA: name = ".data"; break; + case UDATA: break; + case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break; + case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; + case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; + case STRNG: + case RDATA: name = ".section .rodata"; break; + case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; + case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; + case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; + case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; + case NMSEG: + printf("\t.section %s,\"a%c\",@progbits\n", name, + cftnsp ? 'x' : 'w'); + return; + } + printf("\t%s\n", name); +} + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + char *n; + + n = getexname(sp); +#ifdef USE_GAS + if (ISFTN(t)) + printf("\t.type %s,%%function\n", n); +#endif + if (sp->sclass == EXTDEF) + printf("\t.global %s\n", n); + if (sp->slevel == 0) + printf("%s:\n", n); + else + printf(LABFMT ":\n", sp->soffset); +} + +/* Put a symbol in a temporary + * used by bfcode() and its helpers + */ +static void +putintemp(struct symtab *sym) +{ + NODE *p; + + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + p = buildtree(ASSIGN, p, nametree(sym)); + sym->soffset = regno(p->n_left); + sym->sflags |= STNODE; + ecomp(p); +} + +/* setup a 64-bit parameter (double/ldouble/longlong) + * used by bfcode() */ +static void +param_64bit(struct symtab *sym, int *argofsp, int dotemps) +{ + int argofs = *argofsp; + NODE *p, *q; + int navail; + +#if ALLONGLONG == 64 + /* alignment */ + ++argofs; + argofs &= ~1; + *argofsp = argofs; +#endif + + navail = NARGREGS - argofs; + + if (navail < 2) { + /* half in and half out of the registers */ + if (features(FEATURE_BIGENDIAN)) { + cerror("param_64bit"); + p = q = NULL; + } else { + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = R0 + argofs; + if (dotemps) { + q = block(SCONV, q, NIL, + ULONGLONG, 0, 0); + p = nametree(sym); + p->n_type = ULONGLONG; + p->n_df = 0; + p->n_ap = NULL; + p = block(LS, p, bcon(32), ULONGLONG, 0, 0); + q = block(PLUS, p, q, ULONGLONG, 0, 0); + p = tempnode(0, ULONGLONG, 0, 0); + sym->soffset = regno(p); + sym->sflags |= STNODE; + } else { + p = nametree(sym); + regno(p) = sym->soffset; + p->n_type = INT; + p->n_df = 0; + p->n_ap = NULL; + } + } + p = buildtree(ASSIGN, p, q); + ecomp(p); + *argofsp = argofs + 2; + return; + } + + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); + regno(q) = R0R1 + argofs; + if (dotemps) { + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + sym->soffset = regno(p); + sym->sflags |= STNODE; + } else { + p = nametree(sym); + } + p = buildtree(ASSIGN, p, q); + ecomp(p); + *argofsp = argofs + 2; +} + +/* setup a 32-bit param on the stack + * used by bfcode() */ +static void +param_32bit(struct symtab *sym, int *argofsp, int dotemps) +{ + NODE *p, *q; + + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); + regno(q) = R0 + (*argofsp)++; + if (dotemps) { + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + sym->soffset = regno(p); + sym->sflags |= STNODE; + } else { + p = nametree(sym); + } + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + +/* setup a double param on the stack + * used by bfcode() */ +static void +param_double(struct symtab *sym, int *argofsp, int dotemps) +{ + NODE *p, *q, *t; + int tmpnr; + + /* + * we have to dump the float from the general register + * into a temp, since the register allocator doesn't like + * floats to be in CLASSA. This may not work for -xtemps. + */ + + t = tempnode(0, ULONGLONG, 0, 0); + tmpnr = regno(t); + q = block(REG, NIL, NIL, INT, 0, 0); + q->n_rval = R0R1 + (*argofsp)++; + p = buildtree(ASSIGN, t, q); + ecomp(p); + + if (dotemps) { + sym->soffset = tmpnr; + sym->sflags |= STNODE; + } else { + q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); + p = nametree(sym); + p = buildtree(ASSIGN, p, q); + ecomp(p); + } +} + +/* setup a float param on the stack + * used by bfcode() */ +static void +param_float(struct symtab *sym, int *argofsp, int dotemps) +{ + NODE *p, *q, *t; + int tmpnr; + + /* + * we have to dump the float from the general register + * into a temp, since the register allocator doesn't like + * floats to be in CLASSA. This may not work for -xtemps. + */ + + t = tempnode(0, INT, 0, 0); + tmpnr = regno(t); + q = block(REG, NIL, NIL, INT, 0, 0); + q->n_rval = R0 + (*argofsp)++; + p = buildtree(ASSIGN, t, q); + ecomp(p); + + if (dotemps) { + sym->soffset = tmpnr; + sym->sflags |= STNODE; + } else { + q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); + p = nametree(sym); + p = buildtree(ASSIGN, p, q); + ecomp(p); + } +} + +/* setup the hidden pointer to struct return parameter + * used by bfcode() */ +static void +param_retstruct(void) +{ + NODE *p, *q; + + p = tempnode(0, PTR-FTN+cftnsp->stype, 0, cftnsp->sap); + rvnr = regno(p); + q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); + regno(q) = R0; + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + + +/* setup struct parameter + * push the registers out to memory + * used by bfcode() */ +static void +param_struct(struct symtab *sym, int *argofsp) +{ + int argofs = *argofsp; + NODE *p, *q; + int navail; + int sz; + int off; + int num; + int i; + + navail = NARGREGS - argofs; + sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT; + off = ARGINIT/SZINT + argofs; + num = sz > navail ? navail : sz; + for (i = 0; i < num; i++) { + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = R0 + argofs++; + p = block(REG, NIL, NIL, INT, 0, 0); + regno(p) = SP; + p = block(PLUS, p, bcon(4*off++), INT, 0, 0); + p = block(UMUL, p, NIL, INT, 0, 0); + p = buildtree(ASSIGN, p, q); + ecomp(p); + } + + *argofsp = argofs; +} + + +/* + * Beginning-of-function code: + * + * 'sp' is an array of indices in symtab for the arguments + * 'cnt' is the number of arguments + */ +void +bfcode(struct symtab **sp, int cnt) +{ + union arglist *usym; + int saveallargs = 0; + int i, argofs = 0; + + /* + * Detect if this function has ellipses and save all + * argument registers onto stack. + */ + usym = cftnsp->sdf->dfun; + while (usym && usym->type != TNULL) { + if (usym->type == TELLIPSIS) { + saveallargs = 1; + break; + } + ++usym; + } + + /* if returning a structure, move the hidden argument into a TEMP */ + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + param_retstruct(); + ++argofs; + } + + /* recalculate the arg offset and create TEMP moves */ + for (i = 0; i < cnt; i++) { + + if (sp[i] == NULL) + continue; + + if ((argofs >= NARGREGS) && !xtemps) + break; + + if (argofs > NARGREGS) { + putintemp(sp[i]); + } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) { + param_struct(sp[i], &argofs); + } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) { + param_64bit(sp[i], &argofs, xtemps && !saveallargs); + } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) { + if (features(FEATURE_HARDFLOAT)) + param_double(sp[i], &argofs, + xtemps && !saveallargs); + else + param_64bit(sp[i], &argofs, + xtemps && !saveallargs); + } else if (sp[i]->stype == FLOAT) { + if (features(FEATURE_HARDFLOAT)) + param_float(sp[i], &argofs, + xtemps && !saveallargs); + else + param_32bit(sp[i], &argofs, + xtemps && !saveallargs); + } else { + param_32bit(sp[i], &argofs, xtemps && !saveallargs); + } + } + + /* if saveallargs, save the rest of the args onto the stack */ + while (saveallargs && argofs < NARGREGS) { + NODE *p, *q; + int off = ARGINIT/SZINT + argofs; + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = R0 + argofs++; + p = block(REG, NIL, NIL, INT, 0, 0); + regno(p) = FPREG; + p = block(PLUS, p, bcon(4*off), INT, 0, 0); + p = block(UMUL, p, NIL, INT, 0, 0); + p = buildtree(ASSIGN, p, q); + ecomp(p); + } + +} + +/* + * End-of-Function code: + */ +void +efcode(void) +{ + NODE *p, *q; + int tempnr; + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + + /* + * At this point, the address of the return structure on + * has been FORCEd to RETREG, which is R0. + * We want to copy the contents from there to the address + * we placed into the tempnode "rvnr". + */ + + /* move the pointer out of R0 to a tempnode */ + q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); + q->n_rval = R0; + p = tempnode(0, PTR+STRTY, 0, cftnsp->sap); + tempnr = regno(p); + p = buildtree(ASSIGN, p, q); + ecomp(p); + + /* get the address from the tempnode */ + q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->sap); + q = buildtree(UMUL, q, NIL); + + /* now, get the structure destination */ + p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->sap); + p = buildtree(UMUL, p, NIL); + + /* struct assignment */ + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + +/* + * End-of-job: called just before final exit. + */ +void +ejobcode(int flag) +{ + printf("\t.ident \"PCC: %s\"\n", VERSSTR); +} + +/* + * Beginning-of-job: called before compilation starts + * + * Initialise data structures specific for the local machine. + */ +void +bjobcode(void) +{ +} + +/* + * fix up type of field p + */ +void +fldty(struct symtab *p) +{ +} + +/* + * Build target-dependent switch tree/table. + * + * Return 1 if successfull, otherwise return 0 and the + * target-independent tree will be used. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + + +/* + * Straighten a chain of CM ops so that the CM nodes + * only appear on the left node. + * + * CM CM + * CM CM CM b + * x y a b CM a + * x y + */ +static NODE * +straighten(NODE *p) +{ + NODE *r = p->n_right; + + if (p->n_op != CM || r->n_op != CM) + return p; + + p->n_right = r->n_left; + r->n_left = p; + + return r; +} + +static NODE * +reverse1(NODE *p, NODE *a) +{ + NODE *l = p->n_left; + NODE *r = p->n_right; + + a->n_right = r; + p->n_left = a; + + if (l->n_op == CM) { + return reverse1(l, p); + } else { + p->n_right = l; + return p; + } +} + +/* + * Reverse a chain of CM ops + */ +static NODE * +reverse(NODE *p) +{ + NODE *l = p->n_left; + NODE *r = p->n_right; + + p->n_left = r; + + if (l->n_op == CM) + return reverse1(l, p); + + p->n_right = l; + + return p; +} + + +/* push arg onto the stack */ +/* called by moveargs() */ +static NODE * +pusharg(NODE *p, int *regp) +{ + NODE *q; + int sz; + + /* convert to register size, if smaller */ + sz = tsize(p->n_type, p->n_df, p->n_ap); + if (sz < SZINT) + p = block(SCONV, p, NIL, INT, 0, 0); + + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = SP; + + if (szty(p->n_type) == 1) { + ++(*regp); + q = block(MINUSEQ, q, bcon(4), INT, 0, 0); + } else { + (*regp) += 2; + q = block(MINUSEQ, q, bcon(8), INT, 0, 0); + } + + q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_ap); + + return buildtree(ASSIGN, q, p); +} + +/* setup call stack with 32-bit argument */ +/* called from moveargs() */ +static NODE * +movearg_32bit(NODE *p, int *regp) +{ + int reg = *regp; + NODE *q; + + q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); + regno(q) = reg++; + q = buildtree(ASSIGN, q, p); + + *regp = reg; + return q; +} + +/* setup call stack with 64-bit argument */ +/* called from moveargs() */ +static NODE * +movearg_64bit(NODE *p, int *regp) +{ + int reg = *regp; + NODE *q, *r; + +#if ALLONGLONG == 64 + /* alignment */ + ++reg; + reg &= ~1; + *regp = reg; +#endif + + if (reg > R3) { + q = pusharg(p, regp); + } else if (reg == R3) { + /* half in and half out of the registers */ + r = tcopy(p); + if (!features(FEATURE_BIGENDIAN)) { + q = block(SCONV, p, NIL, INT, 0, 0); + q = movearg_32bit(q, regp); /* little-endian */ + r = buildtree(RS, r, bcon(32)); + r = block(SCONV, r, NIL, INT, 0, 0); + r = pusharg(r, regp); /* little-endian */ + } else { + q = buildtree(RS, p, bcon(32)); + q = block(SCONV, q, NIL, INT, 0, 0); + q = movearg_32bit(q, regp); /* big-endian */ + r = block(SCONV, r, NIL, INT, 0, 0); + r = pusharg(r, regp); /* big-endian */ + } + q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_ap)); + } else { + q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); + regno(q) = R0R1 + (reg - R0); + q = buildtree(ASSIGN, q, p); + *regp = reg + 2; + } + + return q; +} + +/* setup call stack with float/double argument */ +/* called from moveargs() */ +static NODE * +movearg_float(NODE *p, int *regp) +{ + NODE *q, *r; + TWORD ty = INCREF(p->n_type); + int tmpnr; + + /* + * Floats are passed in the general registers for + * compatibily with libraries compiled to handle soft-float. + */ + + if (xtemps) { + /* bounce on TOS */ + r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap); + regno(r) = SP; + r = block(PLUS, r, bcon(-4), ty, p->n_df, p->n_ap); + r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap); + r = buildtree(ASSIGN, r, p); + ecomp(r); + + /* bounce into temp */ + r = block(REG, NIL, NIL, PTR+INT, 0, 0); + regno(r) = SP; + r = block(PLUS, r, bcon(-8), PTR+INT, 0, 0); + r = block(UMUL, r, NIL, INT, 0, 0); + q = tempnode(0, INT, 0, 0); + tmpnr = regno(q); + r = buildtree(ASSIGN, q, r); + ecomp(r); + } else { + /* copy directly into temp */ + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(q); + r = buildtree(ASSIGN, q, p); + ecomp(r); + } + + /* copy from temp to register parameter */ + r = tempnode(tmpnr, INT, 0, 0); + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = (*regp)++; + p = buildtree(ASSIGN, q, r); + + return p; +} + +/* setup call stack with float/double argument */ +/* called from moveargs() */ +static NODE * +movearg_double(NODE *p, int *regp) +{ + NODE *q, *r; + TWORD ty = INCREF(p->n_type); + int tmpnr; + + if (xtemps) { + /* bounce on TOS */ + r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap); + regno(r) = SP; + r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_ap); + r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap); + r = buildtree(ASSIGN, r, p); + ecomp(r); + + /* bounce into temp */ + r = block(REG, NIL, NIL, PTR+LONGLONG, 0, 0); + regno(r) = SP; + r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, 0); + r = block(UMUL, r, NIL, LONGLONG, 0, 0); + q = tempnode(0, LONGLONG, 0, 0); + tmpnr = regno(q); + r = buildtree(ASSIGN, q, r); + ecomp(r); + } else { + /* copy directly into temp */ + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(q); + r = buildtree(ASSIGN, q, p); + ecomp(r); + } + + /* copy from temp to register parameter */ + r = tempnode(tmpnr, LONGLONG, 0, 0); + q = block(REG, NIL, NIL, LONGLONG, 0, 0); + regno(q) = R0R1 - R0 + (*regp); + p = buildtree(ASSIGN, q, r); + + (*regp) += 2; + + return p; +} + + +/* setup call stack with a structure */ +/* called from moveargs() */ +static NODE * +movearg_struct(NODE *p, int *regp) +{ + int reg = *regp; + NODE *l, *q, *t, *r; + int tmpnr; + int navail; + int num; + int sz; + int ty; + int i; + + assert(p->n_op == STARG); + + navail = NARGREGS - (reg - R0); + navail = navail < 0 ? 0 : navail; + sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT; + num = sz > navail ? navail : sz; + + /* remove STARG node */ + l = p->n_left; + nfree(p); + ty = l->n_type; + + /* + * put it into a TEMP, rather than tcopy(), since the tree + * in p may have side-affects + */ + t = tempnode(0, ty, l->n_df, l->n_ap); + tmpnr = regno(t); + q = buildtree(ASSIGN, t, l); + + /* copy structure into registers */ + for (i = 0; i < num; i++) { + t = tempnode(tmpnr, ty, 0, 0); + t = block(SCONV, t, NIL, PTR+INT, 0, 0); + t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); + t = buildtree(UMUL, t, NIL); + + r = block(REG, NIL, NIL, INT, 0, 0); + regno(r) = reg++; + r = buildtree(ASSIGN, r, t); + + q = block(CM, q, r, INT, 0, 0); + } + + /* put the rest of the structure on the stack */ + for (i = num; i < sz; i++) { + t = tempnode(tmpnr, ty, 0, 0); + t = block(SCONV, t, NIL, PTR+INT, 0, 0); + t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); + t = buildtree(UMUL, t, NIL); + r = pusharg(t, ®); + q = block(CM, q, r, INT, 0, 0); + } + + q = reverse(q); + + *regp = reg; + return q; +} + + +static NODE * +moveargs(NODE *p, int *regp) +{ + NODE *r, **rp; + int reg; + + if (p->n_op == CM) { + p->n_left = moveargs(p->n_left, regp); + r = p->n_right; + rp = &p->n_right; + } else { + r = p; + rp = &p; + } + + reg = *regp; + + if (reg > R3 && r->n_op != STARG) { + *rp = pusharg(r, regp); + } else if (r->n_op == STARG) { + *rp = movearg_struct(r, regp); + } else if (DEUNSIGN(r->n_type) == LONGLONG) { + *rp = movearg_64bit(r, regp); + } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { + *rp = movearg_double(r, regp); + } else if (r->n_type == FLOAT) { + *rp = movearg_float(r, regp); + } else { + *rp = movearg_32bit(r, regp); + } + + return straighten(p); +} + +/* + * Fixup arguments to pass pointer-to-struct as first argument. + * + * called from funcode(). + */ +static NODE * +retstruct(NODE *p) +{ + NODE *l, *r, *t, *q; + TWORD ty; + + l = p->n_left; + r = p->n_right; + + ty = DECREF(l->n_type) - FTN; + +// assert(tsize(ty, l->n_df, l->n_ap) == SZINT); + + /* structure assign */ + q = tempnode(0, ty, l->n_df, l->n_ap); + q = buildtree(ADDROF, q, NIL); + + /* insert hidden assignment at beginning of list */ + if (r->n_op != CM) { + p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap); + } else { + for (t = r; t->n_left->n_op == CM; t = t->n_left) + ; + t->n_left = block(CM, q, t->n_left, INCREF(ty), + l->n_df, l->n_ap); + } + + return p; +} + +NODE * +builtin_frame_address(const struct bitable *bt, NODE *a) +{ + assert(0); + return NULL; +} + +NODE * +builtin_return_address(const struct bitable *bt, NODE *a) +{ + assert(0); + return NULL; +} + +NODE * +builtin_cfa(const struct bitable *bt, NODE *a) +{ + assert(0); + return NULL; +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + */ +NODE * +funcode(NODE *p) +{ + int reg = R0; + + if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) { + p = retstruct(p); + reg = R1; + } + + p->n_right = moveargs(p->n_right, ®); + + if (p->n_right == NULL) + p->n_op += (UCALL - CALL); + + return p; +} diff --git a/lang/pcc/pcc/arch/arm/local.c b/lang/pcc/pcc/arch/arm/local.c new file mode 100644 index 000000000..18c456423 --- /dev/null +++ b/lang/pcc/pcc/arch/arm/local.c @@ -0,0 +1,696 @@ +/* $Id: local.c,v 1.34 2016/03/09 18:19:56 ragge Exp $ */ +/* + * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org). + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * We define location operations which operate on the expression tree + * during the first pass (before sending to the backend for code generation.) + */ + +#include + +#include "pass1.h" + +#undef NIL +#define NIL NULL + +#ifdef LANG_CXX +#define p1listf listf +#define p1tfree tfree +#else +#define NODE P1ND +#define talloc p1alloc +#define tcopy p1tcopy +#define nfree p1nfree +#endif + +extern void defalign(int); + +static char * +getsoname(struct symtab *sp) +{ + struct attr *ap; + return (ap = attr_find(sp->sap, ATTR_SONAME)) ? + ap->sarg(0) : sp->sname; +} + + +/* + * clocal() is called to do local transformations on + * an expression tree before being sent to the backend. + */ +NODE * +clocal(NODE *p) +{ + struct symtab *q; + NODE *l, *r, *t; + int o; + int ty; + int tmpnr, isptrvoid = 0; + char *n; + + o = p->n_op; + switch (o) { + + case STASG: + + l = p->n_left; + r = p->n_right; + if (r->n_op != STCALL && r->n_op != USTCALL) + return p; + + /* assign left node as first argument to function */ + nfree(p); + t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap); + l->n_rval = R0; + l = buildtree(ADDROF, l, NIL); + l = buildtree(ASSIGN, t, l); + + if (r->n_right->n_op != CM) { + r->n_right = block(CM, l, r->n_right, INT, 0, 0); + } else { + for (t = r->n_right; t->n_left->n_op == CM; + t = t->n_left) + ; + t->n_left = block(CM, l, t->n_left, INT, 0, 0); + } + return r; + + case CALL: + case STCALL: + case USTCALL: + if (p->n_type == VOID) + break; + /* + * if the function returns void*, ecode() invokes + * delvoid() to convert it to uchar*. + * We just let this happen on the ASSIGN to the temp, + * and cast the pointer back to void* on access + * from the temp. + */ + if (p->n_type == PTR+VOID) + isptrvoid = 1; + r = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(r); + r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap); + + p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); + if (isptrvoid) { + p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0); + } + p = buildtree(COMOP, r, p); + break; + + case NAME: + if ((q = p->n_sp) == NULL) + return p; + if (blevel == 0) + return p; + + switch (q->sclass) { + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + slval(r, 0); + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + case REGISTER: + p->n_op = REG; + slval(p, 0); + p->n_rval = q->soffset; + break; + case STATIC: + if (q->slevel > 0) { + slval(p, 0); + p->n_sp = q; + } + /* FALL-THROUGH */ + default: + ty = p->n_type; + n = getsoname(p->n_sp); + if (strncmp(n, "__builtin", 9) == 0) + break; + p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_ap); + p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap); + break; + } + break; + + case STNAME: + if ((q = p->n_sp) == NULL) + return p; + if (q->sclass != STNAME) + return p; + ty = p->n_type; + p = block(ADDROF, p, NIL, INCREF(ty), + p->n_df, p->n_ap); + p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap); + break; + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + p->n_left->n_rval = p->n_left->n_type == BOOL ? + RETREG(BOOL_TYPE) : RETREG(p->n_type); + break; + + case SCONV: + l = p->n_left; + if (p->n_type == l->n_type) { + nfree(p); + return l; + } + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + return l; + } + } + } + + if (l->n_op == ICON) { + CONSZ val = glval(l); + CONSZ lval; + + if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */ + switch (p->n_type) { + case BOOL: + slval(l, glval(l) != 0); + break; + case CHAR: + lval = (char)val; + break; + case UCHAR: + lval = val & 0377; + break; + case SHORT: + lval = (short)val; + break; + case USHORT: + lval = val & 0177777; + break; + case ULONG: + case UNSIGNED: + lval = val & 0xffffffff; + break; + case LONG: + case INT: + lval = (int)val; + break; + case LONGLONG: + lval = (long long)val; + break; + case ULONGLONG: + lval = val; + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + ((FLT *)l->n_dcon)->fp = val; + break; + default: + cerror("unknown type %d", l->n_type); + } + if (p->n_type < FLOAT) + slval(l, lval); + l->n_type = p->n_type; + l->n_ap = 0; + nfree(p); + return l; + } else if (p->n_op == FCON) { + slval(l, ((FLT *)l->n_dcon)->fp); + l->n_sp = NULL; + l->n_op = ICON; + l->n_type = p->n_type; + l->n_ap = 0; + nfree(p); + return clocal(l); + } + if ((DEUNSIGN(p->n_type) == CHAR || + DEUNSIGN(p->n_type) == SHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left->n_type = INT; + return p; + } + break; + + case PCONV: + l = p->n_left; + if (l->n_op == ICON) { + slval(l, (unsigned)glval(l)); + goto delp; + } + if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { + p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); + break; + } + if (l->n_op == SCONV) + break; + if (l->n_op == ADDROF && l->n_left->n_op == TEMP) + goto delp; + if (p->n_type > BTMASK && l->n_type > BTMASK) + goto delp; + break; + + delp: + l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_ap = p->n_ap; + nfree(p); + p = l; + break; + } + + return p; +} + +/* + * Called before sending the tree to the backend. + */ +void +myp2tree(NODE *p) +{ + struct symtab *sp; + + if (p->n_op != FCON) + return; + +#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) + + sp = IALLOC(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->sap = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + + defloc(sp); + ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + + p->n_op = NAME; + slval(p, 0); + p->n_sp = sp; +} + +/* + * Called during the first pass to determine if a NAME can be addressed. + * + * Return nonzero if supported, otherwise return 0. + */ +int +andable(NODE *p) +{ + if (blevel == 0) + return 1; + if (ISFTN(p->n_type)) + return 1; + return 0; +} + +/* + * Return 1 if a variable of type 't' is OK to put in register. + */ +int +cisreg(TWORD t) +{ + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return 0; /* not yet */ + return 1; +} + +/* + * Allocate bits from the stack for dynamic-sized arrays. + * + * 'p' is the tree which represents the type being allocated. + * 'off' is the number of 'p's to be allocated. + * 't' is the storeable node where the address is written. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ + + /* sub the size from sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + slval(sp, 0); + sp->n_rval = SP; + ecomp(buildtree(MINUSEQ, sp, p)); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); + slval(sp, 0); + sp->n_rval = SP; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); +} + +/* + * Print an integer constant node, may be associated with a label. + * Do not free the node after use. + * 'off' is bit offset from the beginning of the aggregate + * 'fsz' is the number of bits this is referring to + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; int i[2]; } u; + struct symtab *q; + TWORD t; + int i, j; + + t = p->n_type; + if (t > BTMASK) + t = p->n_type = INT; /* pointer */ + + if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) + uerror("element not constant"); + + switch (t) { + case LONGLONG: + case ULONGLONG: + i = (glval(p) >> 32); + j = (glval(p) & 0xffffffff); + p->n_type = INT; + if (features(FEATURE_BIGENDIAN)) { + slval(p, i); + ninval(off+32, 32, p); + slval(p, j); + ninval(off, 32, p); + } else { + slval(p, j); + ninval(off, 32, p); + slval(p, i); + ninval(off+32, 32, p); + } + break; + case INT: + case UNSIGNED: + printf("\t.word 0x%x", (int)glval(p)); + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0)) { + printf("+" LABFMT, q->soffset); + } else + printf("+%s", getexname(q)); + } + printf("\n"); + break; + case LDOUBLE: + case DOUBLE: + u.d = (double)((FLT *)p->n_dcon)->fp; +#if defined(HOST_BIG_ENDIAN) + if (features(FEATURE_BIGENDIAN)) +#else + if (!features(FEATURE_BIGENDIAN)) +#endif + printf("\t.word\t0x%x\n\t.word\t0x%x\n", + u.i[0], u.i[1]); + else + printf("\t.word\t0x%x\n\t.word\t0x%x\n", + u.i[1], u.i[0]); + break; + case FLOAT: + u.f = (float)((FLT *)p->n_dcon)->fp; + printf("\t.word\t0x%x\n", u.i[0]); + break; + default: + return 0; + } + return 1; +} + +/* + * Prefix a leading underscore to a global variable (if necessary). + */ +char * +exname(char *p) +{ + return (p == NULL ? "" : p); +} + +/* + * Map types which are not defined on the local machine. + */ +TWORD +ctype(TWORD type) +{ + switch (BTYPE(type)) { + case LONG: + MODTYPE(type,INT); + break; + case ULONG: + MODTYPE(type,UNSIGNED); + break; + } + return (type); +} + +/* + * Before calling a function do any tree re-writing for the local machine. + * + * 'p' is the function tree (NAME) + * 'q' is the CM-separated list of arguments. + */ +void +calldec(NODE *p, NODE *q) +{ +} + +/* + * While handling uninitialised variables, handle variables marked extern. + */ +void +extdec(struct symtab *q) +{ +} + +/* make a common declaration for id, if reasonable */ +void +defzero(struct symtab *sp) +{ + int off; + + off = tsize(sp->stype, sp->sdf, sp->sap); + off = (off+(SZCHAR-1))/SZCHAR; + printf(" .%scomm ", sp->sclass == STATIC ? "l" : ""); + if (sp->slevel == 0) + printf("%s,0%o\n", getexname(sp), off); + else + printf(LABFMT ",0%o\n", sp->soffset, off); +} + +/* + * va_start(ap, last) implementation. + * + * f is the NAME node for this builtin function. + * a is the argument list containing: + * CM + * ap last + */ +NODE * +arm_builtin_stdarg_start(const struct bitable *bt, NODE *a) +{ + NODE *p, *q; + int sz = 1; + + /* check num args and type */ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || + !ISPTR(a->n_left->n_type)) + goto bad; + + /* must first deal with argument size; use int size */ + p = a->n_right; + if (p->n_type < INT) { + /* round up to word */ + sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap); + } + + p = buildtree(ADDROF, p, NIL); /* address of last arg */ + p = optim(buildtree(PLUS, p, bcon(sz))); + q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); + q = buildtree(CAST, q, p); + p = q->n_right; + nfree(q->n_left); + nfree(q); + p = buildtree(ASSIGN, a->n_left, p); + nfree(a); + + return p; + +bad: + uerror("bad argument to __builtin_stdarg_start"); + return bcon(0); +} + +NODE * +arm_builtin_va_arg(const struct bitable *bt, NODE *a) +{ + NODE *p, *q, *r; + int sz, tmpnr; + + /* check num args and type */ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || + !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE) + goto bad; + + r = a->n_right; + + /* get type size */ + sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR; + if (sz < SZINT/SZCHAR) { + werror("%s%s promoted to int when passed through ...", + ISUNSIGNED(r->n_type) ? "unsigned " : "", + DEUNSIGN(r->n_type) == SHORT ? "short" : "char"); + sz = SZINT/SZCHAR; + } + + /* alignment */ + p = tcopy(a->n_left); + if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) { + p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1)); + p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap); + } + + /* create a copy to a temp node */ + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(q); + p = buildtree(ASSIGN, q, p); + + q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap); + q = buildtree(PLUS, q, bcon(sz)); + q = buildtree(ASSIGN, a->n_left, q); + + q = buildtree(COMOP, p, q); + + nfree(a->n_right); + nfree(a); + + p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap); + p = buildtree(UMUL, p, NIL); + p = buildtree(COMOP, q, p); + + return p; + +bad: + uerror("bad argument to __builtin_va_arg"); + return bcon(0); +} + +NODE * +arm_builtin_va_end(const struct bitable *bt, NODE *a) +{ + p1tfree(a); + + return bcon(0); +} + +NODE * +arm_builtin_va_copy(const struct bitable *bt, NODE *a) +{ + NODE *f; + + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM) + goto bad; + f = buildtree(ASSIGN, a->n_left, a->n_right); + nfree(a); + return f; + +bad: + uerror("bad argument to __buildtin_va_copy"); + return bcon(0); +} + +char *nextsect; +static int constructor; +static int destructor; + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + char *a2 = pragtok(NULL); + + if (strcmp(str, "tls") == 0) { + uerror("thread-local storage not supported for this target"); + return 1; + } + if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { + constructor = 1; + return 1; + } + if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { + destructor = 1; + return 1; + } + if (strcmp(str, "section") == 0 && a2 != NULL) { + nextsect = newstring(a2, strlen(a2)); + return 1; + } + + return 0; +} + +/* + * Called when a identifier has been declared, to give target last word. + */ +void +fixdef(struct symtab *sp) +{ + if ((constructor || destructor) && (sp->sclass != PARAM)) { + printf("\t.section .%ctors,\"aw\",@progbits\n", + constructor ? 'c' : 'd'); + printf("\t.p2align 2\n"); + printf("\t.long %s\n", exname(sp->sname)); + printf("\t.previous\n"); + constructor = destructor = 0; + } +} + +void +pass1_lastchance(struct interpass *ip) +{ +} diff --git a/lang/pcc/pcc/arch/arm/local2.c b/lang/pcc/pcc/arch/arm/local2.c new file mode 100644 index 000000000..1ada05421 --- /dev/null +++ b/lang/pcc/pcc/arch/arm/local2.c @@ -0,0 +1,1531 @@ +/* $Id: local2.c,v 1.39 2016/03/09 18:19:56 ragge Exp $ */ +/* + * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org). + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 +#include +#include +#include + +#include "pass2.h" + +extern void defalign(int); + +#define exname(x) x + +char *rnames[] = { + "r0", "r1", "r2", "r3","r4","r5", "r6", "r7", + "r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc", + "r0r1", "r1r2", "r2r3", "r3r4", "r4r5", "r5r6", + "r6r7", "r7r8", "r8r9", "r9r10", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", +}; + +/* + * Handling of integer constants. We have 8 bits + an even + * number of rotates available as a simple immediate. + * If a constant isn't trivially representable, use an ldr + * and a subsequent sequence of orr operations. + */ + +static int +trepresent(const unsigned int val) +{ + int i; +#define rotate_left(v, n) (v << n | v >> (32 - n)) + + for (i = 0; i < 32; i += 2) + if (rotate_left(val, i) <= 0xff) + return 1; + return 0; +} + +/* + * Return values are: + * 0 - output constant as is (should be covered by trepresent() above) + * 1 - 4 generate 1-4 instructions as needed. + */ +static int +encode_constant(int constant, int *values) +{ + int tmp = constant; + int i = 0; + int first_bit, value; + + while (tmp) { + first_bit = ffs(tmp); + first_bit -= 1; /* ffs indexes from 1, not 0 */ + first_bit &= ~1; /* must use even bit offsets */ + + value = tmp & (0xff << first_bit); + values[i++] = value; + tmp &= ~value; + } + return i; +} + +#if 0 +static void +load_constant(NODE *p) +{ + int v = p->n_lval & 0xffffffff; + int reg = DECRA(p->n_reg, 1); + + load_constant_into_reg(reg, v); +} +#endif + +static void +load_constant_into_reg(int reg, int v) +{ + if (trepresent(v)) + printf("\tmov %s,#%d\n", rnames[reg], v); + else if (trepresent(-v)) + printf("\tmvn %s,#%d\n", rnames[reg], -v); + else { + int vals[4], nc, i; + + nc = encode_constant(v, vals); + for (i = 0; i < nc; i++) { + if (i == 0) { + printf("\tmov %s,#%d" COM "load constant %d\n", + rnames[reg], vals[i], v); + } else { + printf("\torr %s,%s,#%d\n", + rnames[reg], rnames[reg], vals[i]); + } + } + } +} + +static TWORD ftype; + +/* + * calculate stack size and offsets + */ +static int +offcalc(struct interpass_prolog *ipp) +{ + int addto; + +#ifdef PCC_DEBUG + if (x2debug) + printf("offcalc: p2maxautooff=%d\n", p2maxautooff); +#endif + + addto = p2maxautooff; + +#if 0 + addto += 7; + addto &= ~7; +#endif + +#ifdef PCC_DEBUG + if (x2debug) + printf("offcalc: addto=%d\n", addto); +#endif + + addto -= AUTOINIT / SZCHAR; + + return addto; +} + +void +prologue(struct interpass_prolog *ipp) +{ + int addto; + int vals[4], nc, i; + +#ifdef PCC_DEBUG + if (x2debug) + printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%lx, autos=%d, tmpnum=%d, lblnum=%d\n", + ipp->ipp_ip.type, + ipp->ipp_ip.lineno, + ipp->ipp_name, + ipp->ipp_vis, + ipp->ipp_type, + ipp->ipp_regs[0], + ipp->ipp_autos, + ipp->ip_tmpnum, + ipp->ip_lblnum); +#endif + + ftype = ipp->ipp_type; + +#if 0 + printf("\t.align 2\n"); + if (ipp->ipp_vis) + printf("\t.global %s\n", exname(ipp->ipp_name)); + printf("\t.type %s,%%function\n", exname(ipp->ipp_name)); +#endif + printf("%s:\n", exname(ipp->ipp_name)); + + /* + * We here know what register to save and how much to + * add to the stack. + */ + addto = offcalc(ipp); + + printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], 16); + printf("\tmov %s,%s\n", rnames[IP], rnames[SP]); + printf("\tstmfd %s!,{%s,%s,%s,%s}\n", rnames[SP], rnames[FP], + rnames[IP], rnames[LR], rnames[PC]); + printf("\tsub %s,%s,#4\n", rnames[FP], rnames[IP]); + + if (addto == 0) + return; + + if (trepresent(addto)) { + printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], addto); + } else { + nc = encode_constant(addto, vals); + for (i = 0; i < nc; i++) + printf("\tsub %s,%s,#%d\n", + rnames[SP], rnames[SP], vals[i]); + } +} + +void +eoftn(struct interpass_prolog *ipp) +{ + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + /* struct return needs special treatment */ + if (ftype == STRTY || ftype == UNIONTY) { + assert(0); + } else { + printf("\tldmea %s,{%s,%s,%s}\n", rnames[FP], rnames[FP], + rnames[SP], rnames[PC]); + printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], 16); + } + printf("\t.size %s,.-%s\n", exname(ipp->ipp_name), + exname(ipp->ipp_name)); +} + + +/* + * these mnemonics match the order of the preprocessor decls + * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT + */ + +static char * +ccbranches[] = { + "beq", /* branch if equal */ + "bne", /* branch if not-equal */ + "ble", /* branch if less-than-or-equal */ + "blt", /* branch if less-than */ + "bge", /* branch if greater-than-or-equal */ + "bgt", /* branch if greater-than */ + /* what should these be ? */ + "bls", /* branch if lower-than-or-same */ + "blo", /* branch if lower-than */ + "bhs", /* branch if higher-than-or-same */ + "bhi", /* branch if higher-than */ +}; + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + str = "orr"; + break; + case ER: + str = "eor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s%c", str, f); +} + +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(NODE *p) +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +/* + * Emit code to compare two longlong numbers. + */ +static void +twollcomp(NODE *p) +{ + int o = p->n_op; + int s = getlab2(); + int e = p->n_label; + int cb1, cb2; + + if (o >= ULE) + o -= (ULE-LE); + switch (o) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 4, cb2 += 4; + expand(p, 0, "\tcmp UR,UL" COM "compare 64-bit values (upper)\n"); + if (cb1) cbgen(cb1, s); + if (cb2) cbgen(cb2, e); + expand(p, 0, "\tcmp AR,AL" COM "(and lower)\n"); + cbgen(p->n_op, e); + deflab(s); +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + CONSZ val; + int shft; + + if (p->n_op == ASSIGN) + p = p->n_left; + + if (features(FEATURE_BIGENDIAN)) + shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval); + else + shft = UPKFOFF(p->n_rval); + + switch (**cp) { + case 'S': + printf("#%d", UPKFSZ(p->n_rval)); + break; + case 'H': + printf("#%d", shft); + break; + case 'M': + case 'N': + val = (CONSZ)1 << UPKFSZ(p->n_rval); + --val; + val <<= shft; + printf("%lld", (**cp == 'M' ? val : ~val) & 0xffffffff); + break; + default: + comperr("fldexpand"); + } + return 1; +} + + +/* + * Structure assignment. + */ +static void +stasg(NODE *p) +{ + NODE *l = p->n_left; + int val = getlval(l); + + /* R0 = dest, R1 = src, R2 = len */ + load_constant_into_reg(R2, attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); + if (l->n_op == OREG) { + if (R2TEST(regno(l))) { + int r = regno(l); + printf("\tadd %s,%s,lsl #%d\n", + rnames[R0], rnames[R2UPK2(r)], R2UPK3(r)); + printf("\tadd %s,%s,%s\n", rnames[R0], rnames[R0], + rnames[R2UPK1(r)]); + } else { + if (trepresent(val)) { + printf("\tadd %s,%s,#%d\n", + rnames[R0], rnames[regno(l)], val); + } else { + load_constant_into_reg(R0, val); + printf("\tadd %s,%s,%s\n", rnames[R0], + rnames[R0], rnames[regno(l)]); + } + } + } else if (l->n_op == NAME) { + cerror("not implemented"); + } + + printf("\tbl %s\n", exname("memcpy")); +} + +static void +shiftop(NODE *p) +{ + NODE *r = p->n_right; + TWORD ty = p->n_type; + char *shifttype; + + if (p->n_op == LS && r->n_op == ICON && getlval(r) < 32) { + expand(p, INBREG, "\tmov A1,AL,lsr "); + printf(CONFMT COM "64-bit left-shift\n", 32 - getlval(r)); + expand(p, INBREG, "\tmov U1,UL,asl AR\n"); + expand(p, INBREG, "\torr U1,U1,A1\n"); + expand(p, INBREG, "\tmov A1,AL,asl AR\n"); + } else if (p->n_op == LS && r->n_op == ICON && getlval(r) < 64) { + expand(p, INBREG, "\tmov A1,#0" COM "64-bit left-shift\n"); + expand(p, INBREG, "\tmov U1,AL"); + if (getlval(r) - 32 != 0) + printf(",asl " CONFMT, getlval(r) - 32); + printf("\n"); + } else if (p->n_op == LS && r->n_op == ICON) { + expand(p, INBREG, "\tmov A1,#0" COM "64-bit left-shift\n"); + expand(p, INBREG, "\tmov U1,#0\n"); + } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 32) { + expand(p, INBREG, "\tmov U1,UL,asl "); + printf(CONFMT COM "64-bit right-shift\n", 32 - getlval(r)); + expand(p, INBREG, "\tmov A1,AL,lsr AR\n"); + expand(p, INBREG, "\torr A1,A1,U1\n"); + if (ty == LONGLONG) + expand(p, INBREG, "\tmov U1,UL,asr AR\n"); + else + expand(p, INBREG, "\tmov U1,UL,lsr AR\n"); + } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 64) { + if (ty == LONGLONG) { + expand(p, INBREG, "\tmvn U1,#1" COM "64-bit right-shift\n"); + expand(p, INBREG, "\tmov A1,UL"); + shifttype = "asr"; + }else { + expand(p, INBREG, "\tmov U1,#0" COM "64-bit right-shift\n"); + expand(p, INBREG, "\tmov A1,UL"); + shifttype = "lsr"; + } + if (getlval(r) - 32 != 0) + printf(",%s " CONFMT, shifttype, getlval(r) - 32); + printf("\n"); + } else if (p->n_op == RS && r->n_op == ICON) { + expand(p, INBREG, "\tmov A1,#0" COM "64-bit right-shift\n"); + expand(p, INBREG, "\tmov U1,#0\n"); + } +} + +/* + * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines + */ +static void +fpemul(NODE *p) +{ + NODE *l = p->n_left; + char *ch = NULL; + + if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3"; + else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3"; + else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "adddf3"; + + else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3"; + else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3"; + else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subdf3"; + + else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3"; + else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3"; + else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "muldf3"; + + else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3"; + else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3"; + else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divdf3"; + + else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2"; + else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2"; + else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negdf2"; + + else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2"; + else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2"; + else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqdf2"; + + else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2"; + else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2"; + else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "nedf2"; + + else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2"; + else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2"; + else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "gedf2"; + + else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2"; + else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2"; + else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "ledf2"; + + else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2"; + else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2"; + else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gtdf2"; + + else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2"; + else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2"; + else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "ltdf2"; + + else if (p->n_op == SCONV && p->n_type == FLOAT) { + if (l->n_type == DOUBLE) ch = "truncdfsf2"; + else if (l->n_type == LDOUBLE) ch = "truncdfsf2"; + else if (l->n_type == ULONGLONG) ch = "floatunsdisf"; + else if (l->n_type == LONGLONG) ch = "floatdisf"; + else if (l->n_type == LONG) ch = "floatsisf"; + else if (l->n_type == ULONG) ch = "floatunsisf"; + else if (l->n_type == INT) ch = "floatsisf"; + else if (l->n_type == UNSIGNED) ch = "floatunsisf"; + } else if (p->n_op == SCONV && p->n_type == DOUBLE) { + if (l->n_type == FLOAT) ch = "extendsfdf2"; + else if (l->n_type == LDOUBLE) ch = "trunctfdf2"; + else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; + else if (l->n_type == LONGLONG) ch = "floatdidf"; + else if (l->n_type == LONG) ch = "floatsidf"; + else if (l->n_type == ULONG) ch = "floatunsidf"; + else if (l->n_type == INT) ch = "floatsidf"; + else if (l->n_type == UNSIGNED) ch = "floatunsidf"; + } else if (p->n_op == SCONV && p->n_type == LDOUBLE) { + if (l->n_type == FLOAT) ch = "extendsfdf2"; + else if (l->n_type == DOUBLE) ch = "extenddftd2"; + else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; + else if (l->n_type == LONGLONG) ch = "floatdidf"; + else if (l->n_type == LONG) ch = "floatsidf"; + else if (l->n_type == ULONG) ch = "floatunsidf"; + else if (l->n_type == INT) ch = "floatsidf"; + else if (l->n_type == UNSIGNED) ch = "floatunsidf"; + } else if (p->n_op == SCONV && p->n_type == ULONGLONG) { + if (l->n_type == FLOAT) ch = "fixunssfdi"; + else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; + else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; + } else if (p->n_op == SCONV && p->n_type == LONGLONG) { + if (l->n_type == FLOAT) ch = "fixsfdi"; + else if (l->n_type == DOUBLE) ch = "fixdfdi"; + else if (l->n_type == LDOUBLE) ch = "fixdfdi"; + } else if (p->n_op == SCONV && p->n_type == LONG) { + if (l->n_type == FLOAT) ch = "fixsfsi"; + else if (l->n_type == DOUBLE) ch = "fixdfsi"; + else if (l->n_type == LDOUBLE) ch = "fixdfsi"; + } else if (p->n_op == SCONV && p->n_type == ULONG) { + if (l->n_type == FLOAT) ch = "fixunssfdi"; + else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; + else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; + } else if (p->n_op == SCONV && p->n_type == INT) { + if (l->n_type == FLOAT) ch = "fixsfsi"; + else if (l->n_type == DOUBLE) ch = "fixdfsi"; + else if (l->n_type == LDOUBLE) ch = "fixdfsi"; + } else if (p->n_op == SCONV && p->n_type == UNSIGNED) { + if (l->n_type == FLOAT) ch = "fixunssfsi"; + else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; + else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; + } + + if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op); + + printf("\tbl __%s" COM "softfloat operation\n", exname(ch)); + + if (p->n_op >= EQ && p->n_op <= GT) + printf("\tcmp %s,#0\n", rnames[R0]); +} + + +/* + * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines + */ + +static void +emul(NODE *p) +{ + char *ch = NULL; + + if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3"; + else if (p->n_op == LS && DEUNSIGN(p->n_type) == LONG) ch = "ashlsi3"; + else if (p->n_op == LS && DEUNSIGN(p->n_type) == INT) ch = "ashlsi3"; + + else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3"; + else if (p->n_op == RS && p->n_type == ULONG) ch = "lshrsi3"; + else if (p->n_op == RS && p->n_type == UNSIGNED) ch = "lshrsi3"; + + else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3"; + else if (p->n_op == RS && p->n_type == LONG) ch = "ashrsi3"; + else if (p->n_op == RS && p->n_type == INT) ch = "ashrsi3"; + + else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3"; + else if (p->n_op == DIV && p->n_type == LONG) ch = "divsi3"; + else if (p->n_op == DIV && p->n_type == INT) ch = "divsi3"; + + else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3"; + else if (p->n_op == DIV && p->n_type == ULONG) ch = "udivsi3"; + else if (p->n_op == DIV && p->n_type == UNSIGNED) ch = "udivsi3"; + + else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3"; + else if (p->n_op == MOD && p->n_type == LONG) ch = "modsi3"; + else if (p->n_op == MOD && p->n_type == INT) ch = "modsi3"; + + else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3"; + else if (p->n_op == MOD && p->n_type == ULONG) ch = "umodsi3"; + else if (p->n_op == MOD && p->n_type == UNSIGNED) ch = "umodsi3"; + + else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3"; + else if (p->n_op == MUL && p->n_type == LONG) ch = "mulsi3"; + else if (p->n_op == MUL && p->n_type == INT) ch = "mulsi3"; + + else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2"; + else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2"; + else if (p->n_op == UMINUS && p->n_type == INT) ch = "negsi2"; + + else ch = 0, comperr("ZE"); + printf("\tbl __%s" COM "emulated operation\n", exname(ch)); +} + +static void +halfword(NODE *p) +{ + NODE *r = getlr(p, 'R'); + NODE *l = getlr(p, 'L'); + int idx0 = 0, idx1 = 1; + CONSZ lval; + + if (features(FEATURE_BIGENDIAN)) { + idx0 = 1; + idx1 = 0; + } + + if (p->n_op == ASSIGN && r->n_op == OREG) { + /* load */ + lval = getlval(r); + expand(p, 0, "\tldrb A1,"); + printf("[%s," CONFMT "]\n", rnames[r->n_rval], lval+idx0); + expand(p, 0, "\tldrb AL,"); + printf("[%s," CONFMT "]\n", rnames[r->n_rval], lval+idx1); + expand(p, 0, "\torr AL,A1,AL,asl #8\n"); + } else if (p->n_op == ASSIGN && l->n_op == OREG) { + /* store */ + lval = getlval(l); + expand(p, 0, "\tstrb AR,"); + printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx0); + expand(p, 0, "\tmov A1,AR,asr #8\n"); + expand(p, 0, "\tstrb A1,"); + printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx1); + } else if (p->n_op == SCONV || p->n_op == UMUL) { + /* load */ + lval = getlval(l); + expand(p, 0, "\tldrb A1,"); + printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx0); + expand(p, 0, "\tldrb A2,"); + printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx1); + expand(p, 0, "\torr A1,A1,A2,asl #8\n"); + } else if (p->n_op == NAME || p->n_op == ICON || p->n_op == OREG) { + /* load */ + lval = getlval(p); + expand(p, 0, "\tldrb A1,"); + printf("[%s," CONFMT "]\n", rnames[p->n_rval], lval+idx0); + expand(p, 0, "\tldrb A2,"); + printf("[%s," CONFMT "]\n", rnames[p->n_rval], lval+idx1); + expand(p, 0, "\torr A1,A1,A2,asl #8\n"); + } else { + comperr("halfword"); + } +} + +static void +bfext(NODE *p) +{ + int sz; + + if (ISUNSIGNED(p->n_right->n_type)) + return; + sz = 32 - UPKFSZ(p->n_left->n_rval); + + expand(p, 0, "\tmov AD,AD,asl "); + printf("#%d\n", sz); + expand(p, 0, "\tmov AD,AD,asr "); + printf("#%d\n", sz); +} + +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (t < LONGLONG || t == FLOAT || t > BTMASK) + return 4; + if (t == LONGLONG || t == ULONGLONG) + return 8; + if (t == DOUBLE || t == LDOUBLE) + return 8; + if (t == STRTY || t == UNIONTY) + return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + comperr("argsiz"); + return 0; +} + +void +zzzcode(NODE *p, int c) +{ + int pr; + + switch (c) { + + case 'B': /* bit-field sign extension */ + bfext(p); + break; + + case 'C': /* remove from stack after subroutine call */ + pr = p->n_qual; +#if 0 + if (p->n_op == STCALL || p->n_op == USTCALL) + pr += 4; +#endif + if (p->n_op == UCALL) + return; /* XXX remove ZC from UCALL */ + if (pr > 0) + printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], pr); + break; + + case 'D': /* Long long comparision */ + twollcomp(p); + break; + + case 'E': /* print out emulated ops */ + emul(p); + break; + + case 'F': /* print out emulated floating-point ops */ + fpemul(p); + break; + + case 'H': /* do halfword access */ + halfword(p); + break; + + case 'I': /* init constant */ + if (p->n_name[0] != '\0') + comperr("named init"); + load_constant_into_reg(DECRA(p->n_reg, 1), + getlval(p) & 0xffffffff); + break; + + case 'J': /* init longlong constant */ + load_constant_into_reg(DECRA(p->n_reg, 1) - R0R1, + getlval(p) & 0xffffffff); + load_constant_into_reg(DECRA(p->n_reg, 1) - R0R1 + 1, + (getlval(p) >> 32)); + break; + + case 'O': /* 64-bit left and right shift operators */ + shiftop(p); + break; + + case 'Q': /* emit struct assign */ + stasg(p); + break; + + default: + comperr("zzzcode %c", c); + } +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + int o = p->n_op; + + if (o == OREG || o == REG || o == NAME) + return SRDIR; /* Direct match */ + if (o == UMUL && shumul(p->n_left, SOREG)) + return SROREG; /* Convert into oreg */ + return SRREG; /* put it into a register */ +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + return 0; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +void +adrcon(CONSZ val) +{ + printf(CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + char *s; + int val = getlval(p); + + switch (p->n_op) { + case ICON: +#if 0 + if (p->n_sp) + printf(" [class=%d,level=%d] ", p->n_sp->sclass, p->n_sp->slevel); +#endif +#ifdef notdef /* ICON cannot ever use sp here */ + /* If it does, it's a giant bug */ + if (p->n_sp == NULL || ( + (p->n_sp->sclass == STATIC && p->n_sp->slevel > 0))) + s = p->n_name; + else + s = exname(p->n_name); +#else + s = p->n_name; +#endif + + if (*s != '\0') { + fprintf(fp, "%s", s); + if (val > 0) + fprintf(fp, "+%d", val); + else if (val < 0) + fprintf(fp, "-%d", -val); + } else + fprintf(fp, CONFMT, (CONSZ)val); + return; + + default: + comperr("illegal conput, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + + size /= SZCHAR; + switch (p->n_op) { + case REG: + printf("%s", rnames[p->n_rval-R0R1+1]); + break; + + case NAME: + case OREG: + setlval(p, getlval(p) + size); + adrput(stdout, p); + setlval(p, getlval(p) - size); + break; + case ICON: + printf(CONFMT, getlval(p) >> 32); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *io, NODE *p) +{ + int r; + /* output an address, with offsets, from p */ + + if (p->n_op == FLD) + p = p->n_left; + + switch (p->n_op) { + + case NAME: + if (p->n_name[0] != '\0') { + fputs(p->n_name, io); + if (getlval(p) != 0) + fprintf(io, "+%lld", getlval(p)); + } else + fprintf(io, CONFMT, getlval(p)); + return; + + case OREG: + r = p->n_rval; + if (R2TEST(r)) + fprintf(io, "[%s, %s, lsl #%d]", + rnames[R2UPK1(r)], + rnames[R2UPK2(r)], + R2UPK3(r)); + else + fprintf(io, "[%s,#%d]", rnames[p->n_rval], (int)getlval(p)); + return; + + case ICON: + /* addressable value of the constant */ + conput(io, p); + return; + + case REG: + switch (p->n_type) { + case DOUBLE: + case LDOUBLE: + if (features(FEATURE_HARDFLOAT)) { + fprintf(io, "%s", rnames[p->n_rval]); + break; + } + /* FALLTHROUGH */ + case LONGLONG: + case ULONGLONG: + fprintf(io, "%s", rnames[p->n_rval-R0R1]); + break; + default: + fprintf(io, "%s", rnames[p->n_rval]); + } + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + if (o < EQ || o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf("\t%s " LABFMT COM "conditional branch\n", + ccbranches[o-EQ], lab); +} + +/* + * The arm can only address 4k to get a NAME, so there must be some + * rewriting here. Strategy: + * For first 1000 nodes found, print out the word directly. + * For the following 1000 nodes, group them together in asm statements + * and create a jump over. + * For the last <1000 statements, print out the words last. + */ +struct addrsymb { + SLIST_ENTRY(addrsymb) link; + char *name; /* symbol name */ + int num; /* symbol offset */ + char *str; /* replace label */ +}; +SLIST_HEAD(, addrsymb) aslist; +static struct interpass *ipbase; +static int prtnumber, nodcnt, notfirst; +#define PRTLAB ".LY%d" /* special for here */ + +static struct interpass * +anode(char *p) +{ + extern int thisline; + struct interpass *ip = tmpalloc(sizeof(struct interpass)); + + ip->ip_asm = p; + ip->type = IP_ASM; + ip->lineno = thisline; + return ip; +} + +static void +flshlab(void) +{ + struct interpass *ip; + struct addrsymb *el; + int lab = prtnumber++; + char *c; + + if (SLIST_FIRST(&aslist) == NULL) + return; + + snprintf(c = tmpalloc(32), 32, "\tb " PRTLAB "\n", lab); + ip = anode(c); + DLIST_INSERT_BEFORE(ipbase, ip, qelem); + + SLIST_FOREACH(el, &aslist, link) { + /* insert each node as asm */ + int l = 32+strlen(el->name); + c = tmpalloc(l); + if (el->num) + snprintf(c, l, "%s:\n\t.word %s+%d\n", + el->str, el->name, el->num); + else + snprintf(c, l, "%s:\n\t.word %s\n", el->str, el->name); + ip = anode(c); + DLIST_INSERT_BEFORE(ipbase, ip, qelem); + } + /* generate asm label */ + snprintf(c = tmpalloc(32), 32, PRTLAB ":\n", lab); + ip = anode(c); + DLIST_INSERT_BEFORE(ipbase, ip, qelem); +} + +static void +prtaddr(NODE *p, void *arg) +{ + NODE *l = p->n_left; + struct addrsymb *el; + int found = 0; + int lab; + + nodcnt++; + + if (p->n_op == ASSIGN && p->n_right->n_op == ICON && + p->n_right->n_name[0] != '\0') { + /* named constant */ + p = p->n_right; + + /* Restore addrof */ + l = mklnode(NAME, getlval(p), 0, 0); + l->n_name = p->n_name; + p->n_left = l; + p->n_op = ADDROF; + } + + if (p->n_op != ADDROF || l->n_op != NAME) + return; + + /* if we passed 1k nodes printout list */ + if (nodcnt > 1000) { + if (notfirst) + flshlab(); + SLIST_INIT(&aslist); + notfirst = 1; + nodcnt = 0; + } + + /* write address to byte stream */ + + SLIST_FOREACH(el, &aslist, link) { + if (el->num == getlval(l) && el->name[0] == l->n_name[0] && + strcmp(el->name, l->n_name) == 0) { + found = 1; + break; + } + } + + if (!found) { + /* we know that this is text segment */ + lab = prtnumber++; + if (nodcnt <= 1000 && notfirst == 0) { + if (getlval(l)) + printf(PRTLAB ":\n\t.word %s+%lld\n", + lab, l->n_name, getlval(l)); + else + printf(PRTLAB ":\n\t.word %s\n", + lab, l->n_name); + } + el = tmpalloc(sizeof(struct addrsymb)); + el->num = getlval(l); + el->name = l->n_name; + el->str = tmpalloc(32); + snprintf(el->str, 32, PRTLAB, lab); + SLIST_INSERT_LAST(&aslist, el, link); + } + + nfree(l); + p->n_op = NAME; + setlval(p, 0); + p->n_name = el->str; +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + SLIST_INIT(&aslist); + notfirst = nodcnt = 0; + + DLIST_FOREACH(ip, ipole, qelem) { + switch (ip->type) { + case IP_NODE: + lineno = ip->lineno; + ipbase = ip; + walkf(ip->ip_node, prtaddr, 0); + break; + case IP_EPILOG: + ipbase = ip; + if (notfirst) + flshlab(); + break; + default: + break; + } + } + if (x2debug) + printip(ipole); +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE *p, void *arg) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR+SHORT) || p->n_type == (PTR+USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2, 0); +} + +void +myoptim(struct interpass *ipp) +{ +} + +/* + * Register move: move contents of register 's' to register 'r'. + */ +void +rmove(int s, int d, TWORD t) +{ + switch (t) { + case DOUBLE: + case LDOUBLE: + if (features(FEATURE_HARDFLOAT)) { + printf("\tfmr %s,%s" COM "rmove\n", + rnames[d], rnames[s]); + break; + } + /* FALLTHROUGH */ + case LONGLONG: + case ULONGLONG: +#define LONGREG(x, y) rnames[(x)-(R0R1-(y))] + if (s == d+1) { + /* dh = sl, copy low word first */ + printf("\tmov %s,%s" COM "rmove\n", + LONGREG(d,0), LONGREG(s,0)); + printf("\tmov %s,%s\n", + LONGREG(d,1), LONGREG(s,1)); + } else { + /* copy high word first */ + printf("\tmov %s,%s" COM "rmove\n", + LONGREG(d,1), LONGREG(s,1)); + printf("\tmov %s,%s\n", + LONGREG(d,0), LONGREG(s,0)); + } +#undef LONGREG + break; + case FLOAT: + if (features(FEATURE_HARDFLOAT)) { + printf("\tmr %s,%s" COM "rmove\n", + rnames[d], rnames[s]); + break; + } + /* FALLTHROUGH */ + default: + printf("\tmov %s,%s" COM "rmove\n", rnames[d], rnames[s]); + } +} + +/* + * Can we assign a register from class 'c', given the set + * of number of assigned registers in each class 'r'. + * + * On ARM, we have: + * 11 CLASSA registers (32-bit hard registers) + * 10 CLASSB registers (64-bit composite registers) + * 8 or 32 CLASSC registers (floating-point) + * + * There is a problem calculating the available composite registers + * (ie CLASSB). The algorithm below assumes that given any two + * registers, we can make a composite register. But this isn't true + * here (or with other targets), since the number of combinations + * of register pairs could become very large. Additionally, + * having so many combinations really isn't so practical, since + * most register pairs cannot be used to pass function arguments. + * Consequently, when there is pressure composite registers, + * "beenhere" compilation failures are common. + * + * [We need to know which registers are allocated, not simply + * the number in each class] + */ +int +COLORMAP(int c, int *r) +{ + int num = 0; /* number of registers used */ + +#if 0 + static const char classes[] = { 'X', 'A', 'B', 'C', 'D' }; + printf("COLORMAP: requested class %c\n", classes[c]); + printf("COLORMAP: class A: %d\n", r[CLASSA]); + printf("COLORMAP: class B: %d\n", r[CLASSB]); +#endif + + switch (c) { + case CLASSA: + num += r[CLASSA]; + num += 2*r[CLASSB]; + return num < 11; + case CLASSB: + num += 2*r[CLASSB]; + num += r[CLASSA]; + return num < 6; /* XXX see comments above */ + case CLASSC: + num += r[CLASSC]; + if (features(FEATURE_FPA)) + return num < 8; + else if (features(FEATURE_VFP)) + return num < 8; + else + cerror("colormap 1"); + } + cerror("colormap 2"); + return 0; /* XXX gcc */ +} + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t == DOUBLE || t == LDOUBLE) { + if (features(FEATURE_HARDFLOAT)) + return CLASSC; + else + return CLASSB; + } + if (t == FLOAT) { + if (features(FEATURE_HARDFLOAT)) + return CLASSC; + else + return CLASSA; + } + if (DEUNSIGN(t) == LONGLONG) + return CLASSB; + return CLASSA; +} + +int +retreg(int t) +{ + int c = gclass(t); + if (c == CLASSB) + return R0R1; + else if (c == CLASSC) + return F0; + return R0; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + size += argsiz(p->n_right); + size += argsiz(p); + op->n_qual = size - 16; /* XXX */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + return SRNOPE; +} + +/* + * default to ARMv2 + */ +#ifdef TARGET_BIG_ENDIAN +#define DEFAULT_FEATURES FEATURE_BIGENDIAN | FEATURE_MUL +#else +#define DEFAULT_FEATURES FEATURE_MUL +#endif + +static int fset = DEFAULT_FEATURES; + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ + if (strcasecmp(str, "little-endian") == 0) { + fset &= ~FEATURE_BIGENDIAN; + } else if (strcasecmp(str, "big-endian") == 0) { + fset |= FEATURE_BIGENDIAN; + } else if (strcasecmp(str, "fpe=fpa") == 0) { + fset &= ~(FEATURE_VFP | FEATURE_FPA); + fset |= FEATURE_FPA; + } else if (strcasecmp(str, "fpe=vfp") == 0) { + fset &= ~(FEATURE_VFP | FEATURE_FPA); + fset |= FEATURE_VFP; + } else if (strcasecmp(str, "fpe=vfpv3-d16") == 0) { + fset &= ~(FEATURE_VFP | FEATURE_FPA); + fset |= FEATURE_VFP; + } else if (strcasecmp(str, "soft-float") == 0) { + fset &= ~(FEATURE_VFP | FEATURE_FPA); + } else if (strcasecmp(str, "arch=armv1") == 0) { + fset &= ~FEATURE_HALFWORDS; + fset &= ~FEATURE_EXTEND; + fset &= ~FEATURE_MUL; + fset &= ~FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv2") == 0) { + fset &= ~FEATURE_HALFWORDS; + fset &= ~FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset &= ~FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv2a") == 0) { + fset &= ~FEATURE_HALFWORDS; + fset &= ~FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset &= ~FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv3") == 0) { + fset &= ~FEATURE_HALFWORDS; + fset &= ~FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset &= ~FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv4") == 0) { + fset |= FEATURE_HALFWORDS; + fset &= ~FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv4t") == 0) { + fset |= FEATURE_HALFWORDS; + fset &= ~FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv4tej") == 0) { + fset |= FEATURE_HALFWORDS; + fset &= ~FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv5") == 0) { + fset |= FEATURE_HALFWORDS; + fset &= ~FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv5te") == 0) { + fset |= FEATURE_HALFWORDS; + fset &= ~FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv5tej") == 0) { + fset |= FEATURE_HALFWORDS; + fset &= ~FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv6") == 0) { + fset |= FEATURE_HALFWORDS; + fset |= FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv6t2") == 0) { + fset |= FEATURE_HALFWORDS; + fset |= FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv6kz") == 0) { + fset |= FEATURE_HALFWORDS; + fset |= FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv6k") == 0) { + fset |= FEATURE_HALFWORDS; + fset |= FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv7") == 0) { + fset |= FEATURE_HALFWORDS; + fset |= FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset |= FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv7-m") == 0 || strcasecmp(str, "arch=armv7e-m") == 0) { + fset |= FEATURE_HALFWORDS; + fset |= FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset |= FEATURE_DIV; + } else if (strcasecmp(str, "arch=armv7-a") == 0) { + fset |= FEATURE_HALFWORDS; + fset |= FEATURE_EXTEND; + fset |= FEATURE_MUL; + fset |= FEATURE_MULL; + fset &= ~FEATURE_DIV; + } else { + fprintf(stderr, "unknown m option '%s'\n", str); + exit(1); + } +} + +int +features(int mask) +{ + if (mask == FEATURE_HARDFLOAT) + return ((fset & mask) != 0); + return ((fset & mask) == mask); +} + +/* + * Define the current location as an internal label. + */ +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +/* + * Do something target-dependent for xasm arguments. + * Supposed to find target-specific constraints and rewrite them. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + return 0; +} diff --git a/lang/pcc/pcc/arch/arm/macdefs.h b/lang/pcc/pcc/arch/arm/macdefs.h new file mode 100644 index 000000000..fbf8e6405 --- /dev/null +++ b/lang/pcc/pcc/arch/arm/macdefs.h @@ -0,0 +1,269 @@ +/* $Id: macdefs.h,v 1.19 2016/03/09 18:19:56 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZBOOL 32 +#define SZINT 32 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 64 +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 64 +#define SZPOINT(t) 32 + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALBOOL 32 +#define ALINT 32 +#define ALFLOAT 32 +#define ALDOUBLE 32 +#define ALLDOUBLE 32 +#define ALLONG 32 +#define ALLONGLONG 32 +#define ALSHORT 16 +#define ALPOINT 32 +#define ALSTRUCT 32 +#define ALSTACK 32 + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT -1 +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffff +#define MIN_LONG MIN_INT +#define MAX_LONG MAX_INT +#define MAX_ULONG MAX_UNSIGNED +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +#define BOOL_TYPE INT /* what used to store _Bool */ + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "#%lld" /* format for printing constants */ +#define LABFMT ".L%d" /* format for printing labels */ +#define STABLBL "LL%d" /* format for stab (debugging) labels */ +#define STAB_LINE_ABSOLUTE /* S_LINE fields use absolute addresses */ + +#undef FIELDOPS /* no bit-field instructions */ + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&03) +#define wdal(k) (BYTEOFF(k)==0) + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) + +#define szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \ + (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) + +#define R0 0 +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define SL R10 +#define FP R11 +#define IP R12 +#define SP R13 +#define LR R14 +#define PC R15 + +#define R0R1 16 +#define R1R2 17 +#define R2R3 18 +#define R3R4 19 +#define R4R5 20 +#define R5R6 21 +#define R6R7 22 +#define R7R8 23 +#define R8R9 24 +#define R9R10 25 + +#define F0 26 +#define F1 27 +#define F2 28 +#define F3 29 +#define F4 30 +#define F5 31 +#define F6 32 +#define F7 33 + +#define NUMCLASS 3 +#define MAXREGS 34 + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + 0, 0, 0, 0, 0, \ + SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, \ + +#define ROVERLAP \ + { R0R1, -1 }, \ + { R0R1, R1R2, -1 }, \ + { R1R2, R2R3, -1 }, \ + { R2R3, R3R4, -1 }, \ + { R3R4, R4R5, -1 }, \ + { R4R5, R5R6, -1 }, \ + { R5R6, R6R7, -1 }, \ + { R6R7, R7R8, -1 }, \ + { R7R8, R8R9, -1 }, \ + { R8R9, R9R10, -1 }, \ + { R9R10, -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { R0, R1, R1R2, -1 }, \ + { R1, R2, R0R1, R2R3, -1 }, \ + { R2, R3, R1R2, R3R4, -1 }, \ + { R3, R4, R2R3, R4R5, -1 }, \ + { R4, R5, R3R4, R5R6, -1 }, \ + { R5, R6, R4R5, R6R7, -1 }, \ + { R6, R7, R5R6, R7R8, -1 }, \ + { R7, R8, R6R7, R8R9, -1 }, \ + { R8, R9, R7R8, R9R10, -1 }, \ + { R9, R10, R8R9, -1 }, \ + { -1, }, \ + { -1, }, \ + { -1, }, \ + { -1, }, \ + { -1, }, \ + { -1, }, \ + { -1, }, \ + { -1, }, \ + +#define BACKTEMP /* stack grows negatively for temporaries */ +#define BACKAUTO /* stack grows negatively for automatics */ + +#define ARGINIT (4*8) /* # bits above fp where arguments start */ +#define AUTOINIT (12*8) /* # bits above fp where automatics start */ + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_LE + +/* XXX - to die */ +#define FPREG FP /* frame pointer */ + +/* Return a register class based on the type of the node */ +#define PCLASS(p) (1 << gclass((p)->n_type)) + +#define GCLASS(x) (x < 16 ? CLASSA : x < 26 ? CLASSB : CLASSC) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ +#define RETREG(x) retreg(x) + +int COLORMAP(int c, int *r); +int retreg(int ty); +int features(int f); + +#define FEATURE_BIGENDIAN 0x00010000 +#define FEATURE_HALFWORDS 0x00020000 /* ldrsh/ldrh, ldrsb */ +#define FEATURE_EXTEND 0x00040000 /* sxth, sxtb, uxth, uxtb */ +#define FEATURE_MUL 0x00080000 +#define FEATURE_MULL 0x00100000 +#define FEATURE_DIV 0x00200000 +#define FEATURE_FPA 0x10000000 +#define FEATURE_VFP 0x20000000 +#define FEATURE_HARDFLOAT (FEATURE_FPA|FEATURE_VFP) + +#if 0 +#define TARGET_STDARGS +#define TARGET_BUILTINS \ + { "__builtin_stdarg_start", arm_builtin_stdarg_start }, \ + { "__builtin_va_arg", arm_builtin_va_arg }, \ + { "__builtin_va_end", arm_builtin_va_end }, \ + { "__builtin_va_copy", arm_builtin_va_copy }, +#endif + +#undef NODE +#ifdef LANG_CXX +#define NODE struct node +#else +#define NODE struct p1node +#endif +struct node; +struct bitable; +NODE *arm_builtin_stdarg_start(const struct bitable *bt, NODE *a); +NODE *arm_builtin_va_arg(const struct bitable *bt, NODE *a); +NODE *arm_builtin_va_end(const struct bitable *bt, NODE *a); +NODE *arm_builtin_va_copy(const struct bitable *bt, NODE *a); +#undef NODE + +#define COM "\t@ " +#define NARGREGS 4 diff --git a/lang/pcc/pcc/arch/arm/order.c b/lang/pcc/pcc/arch/arm/order.c new file mode 100644 index 000000000..1d42ebdd8 --- /dev/null +++ b/lang/pcc/pcc/arch/arm/order.c @@ -0,0 +1,339 @@ +/* $Id: order.c,v 1.10 2016/03/09 18:19:56 ragge Exp $ */ +/* + * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org). + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Machine-dependent code-generation strategy (pass 2). + */ + +#include +#include + +#include "pass2.h" + +/* + * Check size of offset in OREG. Called by oregok() to see if an + * OREG can be generated. + */ +int +notoff(TWORD ty, int r, CONSZ off, char *cp) +{ + if (cp && cp[0]) return 1; + if (DEUNSIGN(ty) == INT || ty == UCHAR) + return !(off < 4096 && off > -4096); + else + return !(off < 256 && off > -256); +} + +/* + * Generate instructions for an OREG. Why is this routine MD? + * Called by swmatch(). + */ +void +offstar(NODE *p, int shape) +{ + NODE *r; + + if (isreg(p)) + return; /* Is already OREG */ + + r = p->n_right; + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( r->n_op == ICON ){ + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + /* usually for arraying indexing: */ + if (r->n_op == LS && r->n_right->n_op == ICON && + getlval(r->n_right) == 2 && p->n_op == PLUS) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + if (isreg(r->n_left) == 0) + (void)geninsn(r->n_left, INAREG); + return; + } + } + (void)geninsn(p, INAREG); +} + +/* + * Unable to convert to OREG (notoff() returned failure). Output + * suitable instructions to replace OREG. + */ +void +myormake(NODE *q) +{ + NODE *p, *r; + + if (x2debug) + printf("myormake(%p)\n", q); + + p = q->n_left; + + /* + * This handles failed OREGs conversions, due to the offset + * being too large for an OREG. + */ + if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + if (isreg(p->n_right) == 0) + (void)geninsn(p->n_right, INAREG); + (void)geninsn(p, INAREG); + } else if (p->n_op == REG) { + q->n_op = OREG; + setlval(q, getlval(p)); + q->n_rval = p->n_rval; + tfree(p); + } else if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && + r->n_right->n_op == ICON && getlval(r->n_right) == 2 && + p->n_left->n_op == REG && r->n_left->n_op == REG) { + q->n_op = OREG; + setlval(q, 0); + q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, + getlval(r->n_right)); + tfree(p); + } +} + +/* + * Check to if the UMUL node can be converted into an OREG. + */ +int +shumul(NODE *p, int shape) +{ + /* Turns currently anything into OREG */ + if (shape & SOREG) + return SROREG; + return SRNOPE; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of a failed table lookup. + * + * Return nonzero to retry table search on new tree, or zero to fail. + */ +int +setbin(NODE *p) +{ + return 0; + +} + +/* + * Rewrite assignment operations. + * Called as a result of a failed table lookup. + * + * Return nonzero to retry table search on new tree, or zero to fail. + */ +int +setasg(NODE *p, int cookie) +{ + return 0; +} + +/* + * Rewrite UMUL operation. + * Called as a result of a failed table lookup. + * + * Return nonzero to retry table search on new tree, or zero to fail. + */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + * + * Called as a result of specifying NSPECIAL in the table. + */ +struct rspecial * +nspecial(struct optab *q) +{ + + switch (q->op) { + +#if !defined(ARM_HAS_FPA) && !defined(ARM_HAS_VFP) + case UMINUS: + case SCONV: + if (q->lshape == SBREG && q->rshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R0R1 }, + { NRES, R0 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG && q->rshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R0 }, + { NRES, R0R1 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG && q->rshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R0 }, + { NRES, R0 }, + { 0 } + }; + return s; + } else if (q->lshape == SBREG && q->rshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R0R1 }, + { NRES, R0R1 }, + { 0 } + }; + return s; + } + + case OPLOG: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R0R1 }, + { NRIGHT, R2R3 }, + { NRES, R0 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R0 }, + { NRIGHT, R1 }, + { NRES, R0 }, + { 0 } + }; + return s; + } + case PLUS: + case MINUS: + case MUL: +#endif + case MOD: + case DIV: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R0R1 }, + { NRIGHT, R2R3 }, + { NRES, R0R1 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R0 }, + { NRIGHT, R1 }, + { NRES, R0 }, + { 0 } + }; + return s; + } + case LS: + case RS: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R0R1 }, + { NRIGHT, R2 }, + { NRES, R0R1 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R0 }, + { NRIGHT, R1 }, + { NRES, R0 }, + { 0 } + }; + return s; + } + case STASG: + { + static struct rspecial s[] = { + { NEVER, R0 }, + { NRIGHT, R1 }, + { NEVER, R2 }, + { 0 } }; + return s; + } + break; + + default: + break; + } + +#ifdef PCC_DEBUG + comperr("nspecial entry %d [0x%x]: %s", q - table, q->op, q->cstring); +#endif + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node ('+','-', '*', '/', etc) if it + * differs from default. + */ +int +setorder(NODE *p) +{ + return 0; +} + +/* + * Set registers "live" at function calls (like arguments in registers). + * This is for liveness analysis of registers. + */ +int * +livecall(NODE *p) +{ + static int r[] = { R3, R2, R1, R0, -1 }; + int num = 1; + + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return &r[4-0]; + + for (p = p->n_right; p->n_op == CM; p = p->n_left) + num += szty(p->n_right->n_type); + num += szty(p->n_right->n_type); + + num = (num > 4 ? 4 : num); + + return &r[4 - num]; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return features(op->visit & 0xffff0000); +} diff --git a/lang/pcc/pcc/arch/arm/table.c b/lang/pcc/pcc/arch/arm/table.c new file mode 100644 index 000000000..b98745e00 --- /dev/null +++ b/lang/pcc/pcc/arch/arm/table.c @@ -0,0 +1,1847 @@ +/* $Id: table.c,v 1.20 2011/11/13 22:30:18 gmcgarry Exp $ */ +/*- + * Copyright (c) 2007 Gregory McGarry + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * A template has five logical sections: + * + * 1) subtree (operator); goal to achieve (cookie) + * 2) left node descendent of operator (node class; type) + * 3) right node descendent of operator (node class; type) + * 4) resource requirements (number of scratch registers); + * subtree rewriting rule + * 5) emitted instructions + */ + +#include "pass2.h" + +#define TUWORD TUNSIGNED|TULONG +#define TSWORD TINT|TLONG +#define TWORD TUWORD|TSWORD + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are not necessary */ +{ PCONV, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + COM "pointer conversion\n", }, + + +/* + * Conversions of integral types + * + * For each deunsigned type, they look something like this: + * + * signed -> bigger signed - nothing to do + * signed -> bigger unsigned - clear the top bits (of source type) + * + * signed -> smaller signed - sign-extend the bits (to dest type) + * signed -> smaller unsigned - clear the top bits (of dest type) + * unsigned -> smaller signed - sign-extend top bits (to dest type) + * unsigned -> smaller unsigned - clear the top bits (of dest type) + * + * unsigned -> bigger - nothing to do + */ + +{ SCONV, INAREG, + SAREG, TCHAR, + SAREG, TSWORD|TSHORT, + 0, RLEFT, + COM "convert char to short/int\n", }, + +{ SCONV, INAREG, + SAREG, TCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + NAREG|NASL, RESC1, + " and A1,AL,#255" COM "convert char to uchar/ushort/uint\n", }, + +{ SCONV, INAREG | FEATURE_EXTEND, + SAREG, TUCHAR, + SAREG, TCHAR, + NAREG|NASL, RESC1, + " sxtb A1,AL" COM "convert uchar to char\n", }, + +{ SCONV, INAREG, + SAREG, TUCHAR, + SAREG, TCHAR, + NAREG|NASL, RESC1, + " mov A1,AL,asl #24" COM "convert uchar to char\n" + " mov A1,A1,asr #24\n", }, + +{ SCONV, INAREG, + SAREG, TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT, + 0, RLEFT, + COM "convert uchar to (u)short/(u)int\n", }, + +{ SCONV, INAREG, + SAREG, TSHORT, + SAREG, TSWORD, + 0, RLEFT, + COM "convert short to int\n", }, + +{ SCONV, INAREG | FEATURE_EXTEND, + SAREG, TSHORT, + SAREG, TUWORD|TUSHORT, + NAREG|NASL, RESC1, + " uxth A1,AL" COM "convert short to uint\n", }, + +{ SCONV, INAREG, + SAREG, TSHORT, + SAREG, TUWORD|TUSHORT, + NAREG|NASL, RESC1, + " mov A1,AL,asl #16" COM "convert short to uint\n" + " mov A1,AL,lsr #16\n", }, + +{ SCONV, INAREG | FEATURE_EXTEND, + SAREG, TUSHORT, + SAREG, TSHORT, + NAREG|NASL, RESC1, + " sxth A1,AL" COM "convert ushort to short\n", }, + +{ SCONV, INAREG, + SAREG, TUSHORT, + SAREG, TSHORT, + NAREG|NASL, RESC1, + " mov A1,AL,asl #16" COM "convert ushort to short\n" + " mov A1,A1,asr #16\n", }, + +{ SCONV, INAREG | FEATURE_EXTEND, + SAREG, TSHORT|TUSHORT, + SAREG, TCHAR, + NAREG|NASL, RESC1, + " sxtb A1,AL" COM "convert (u)short to char\n", }, + +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG, TCHAR, + NAREG|NASL, RESC1, + " mov A1,AL,asl #24" COM "convert (u)short to char\n" + " mov A1,A1,asr #24\n", }, + +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG, TCHAR, + NAREG|NASL, RESC1, + " sxtb A1,AL" COM "convert (u)short to char\n", }, + +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG, TUCHAR, + NAREG|NASL, RESC1, + " and A1,AL,#255" COM "convert (u)short to uchar\n", }, + +{ SCONV, INAREG, + SAREG, TUSHORT, + SAREG, TWORD, + 0, RLEFT, + COM "convert ushort to (u)int\n", }, + +{ SCONV, INAREG | FEATURE_EXTEND, + SAREG, TWORD, + SAREG, TCHAR, + NAREG|NASL, RESC1, + " sxtb A1,AL" COM "convert (u)int to char\n", }, + +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TCHAR, + NAREG|NASL, RESC1, + " mov A1,AL,asl #24" COM "convert (u)int to char\n" + " mov A1,A1,asr #24\n", }, + +{ SCONV, INAREG | FEATURE_EXTEND, + SAREG, TWORD, + SAREG, TSHORT, + NAREG|NASL, RESC1, + " sxth A1,AL" COM "convert (u)int to short\n", }, + +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TSHORT, + NAREG|NASL, RESC1, + " mov A1,AL,asl #16" COM "convert (u)int to short\n" + " mov A1,A1,asr #16\n", }, + +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TUCHAR, + NAREG|NASL, RESC1, + " and A1,AL,#255" COM "convert uchar to char\n", }, + +{ SCONV, INAREG | FEATURE_EXTEND, + SAREG, TWORD, + SAREG, TUSHORT, + NAREG|NASL, RESC1, + " uxth A1,AL" COM "convert int to ushort\n", }, + +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TUSHORT, + NAREG|NASL, RESC1, + " mov A1,AL,asl #16" COM "convert int to ushort\n" + " mov A1,AL,lsr #16\n", }, + +{ SCONV, INAREG, + SAREG, TPOINT|TWORD, + SAREG, TWORD|TPOINT, + 0, RLEFT, + COM "convert between pointers and words\n", }, + +{ SCONV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RLEFT, + COM "convert (u)longlong to (u)longlong\n", }, + +/* convert (u)char/(u)short/(u)int to longlong */ +{ SCONV, INBREG, + SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " mov A1,AL" COM "convert (u)char/(u)short/(u)int to (u)longlong\n" + " mov U1,AL,asr #31\n", }, + +{ SCONV, INAREG | FEATURE_EXTEND, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TCHAR, + NAREG, RESC1, + " sxtb A1,AL" COM "convert (u)longlong to char\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TCHAR, + NAREG, RESC1, + " mov A1,AL,asl #24" COM "convert (u)longlong to char\n" + " mov A1,A1,asr #24\n", }, + +{ SCONV, INAREG | FEATURE_EXTEND, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TSHORT, + NAREG, RESC1, + " sxth A1,AL" COM "convert (u)longlong to short\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TSHORT, + NAREG, RESC1, + " mov A1,AL,asl #16" COM "convert (u)longlong to short\n" + " mov A1,A1,asr #16\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TWORD, + NAREG, RESC1, + " mov A1,AL" COM "convert (u)longlong to (u)int\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TUCHAR, + NAREG, RESC1, + " and A1,AL,#255" COM "convert (u)longlong to uchar\n", }, + +{ SCONV, INAREG | FEATURE_EXTEND, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TUSHORT, + NAREG, RESC1, + " uxth A1,AL" COM "convert (u)longlong to ushort\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TUSHORT, + NAREG, RESC1, + " mov A1,AL,asl #16" COM "convert (u)longlong to ushort\n" + " mov A1,A1,lsr #16\n", }, + +/* conversions on load from memory */ + +/* char */ +{ SCONV, INAREG, + SOREG, TCHAR, + SAREG, TWORD, + NASL|NAREG, RESC1, + " ldrsb A1,AL" COM "convert char to int/long\n", }, + +/* uchar */ +{ SCONV, INAREG, + SOREG, TUCHAR, + SAREG, TWORD, + NASL|NAREG, RESC1, + " ldrb A1,AL" COM "convert uchar to int/long\n", }, + +/* short */ +{ SCONV, INAREG | FEATURE_HALFWORDS, + SOREG, TSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " ldrsh A1,AL" COM "convert short to int/long\n", }, + +/* ushort */ +{ SCONV, INAREG | FEATURE_HALFWORDS, + SOREG, TSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " ldrh A1,AL" COM "convert ushort to int/long\n", }, + +/* short */ +{ SCONV, INAREG, + SOREG, TSHORT|TUSHORT, + SAREG, TWORD, + 2*NAREG|NASL, RESC1, + "ZH", }, + +{ SCONV, INAREG | FEATURE_FPA, + SCREG, TFLOAT, + SAREG, TWORD, + NAREG, RESC1, + " fix AL,AR" COM "convert float to int\n", }, + +{ SCONV, INAREG | FEATURE_VFP, + SCREG, TFLOAT, + SAREG, TSWORD, + NAREG, RESC1, + " ftosis AL,AR" COM "convert float to int\n", }, + +{ SCONV, INAREG | FEATURE_VFP, + SCREG, TFLOAT, + SAREG, TSWORD, + NAREG, RESC1, + " ftouis AL,AR" COM "convert float to int\n", }, + +{ SCONV, INAREG, + SAREG, TFLOAT, + SAREG, TWORD, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ SCONV, INBREG | FEATURE_FPA, + SCREG, TFLOAT, + SBREG, TULONGLONG|TLONGLONG, + NBREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INBREG | FEATURE_VFP, + SCREG, TFLOAT, + SBREG, TULONGLONG|TLONGLONG, + NBREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INBREG, + SAREG, TFLOAT, + SBREG, TULONGLONG|TLONGLONG, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INAREG | FEATURE_FPA, + SCREG, TDOUBLE|TLDOUBLE, + SAREG, TWORD, + NAREG, RESC1, + " fix AL,AR" COM "convert double/ldouble to int\n", }, + +{ SCONV, INAREG | FEATURE_VFP, + SCREG, TDOUBLE|TLDOUBLE, + SAREG, TSWORD, + NAREG, RESC1, + " ftosid AL,AR" COM "convert double/ldouble to int\n", }, + +{ SCONV, INAREG | FEATURE_VFP, + SCREG, TDOUBLE|TLDOUBLE, + SAREG, TUWORD, + NAREG, RESC1, + " ftouid AL,AR" COM "convert double/ldouble to int\n", }, + +{ SCONV, INAREG, + SBREG, TDOUBLE|TLDOUBLE, + SAREG, TWORD, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ SCONV, INBREG | FEATURE_FPA, + SCREG, TDOUBLE|TLDOUBLE, + SBREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INBREG | FEATURE_VFP, + SCREG, TDOUBLE|TLDOUBLE, + SBREG, TULONGLONG|TLONGLONG, + NBREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TULONGLONG|TLONGLONG, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_FPA, + SAREG, TWORD, + SCREG, TFLOAT, + NCREG, RESC1, + " flts AL,AR" COM "convert int to float\n" }, + +{ SCONV, INCREG | FEATURE_VFP, + SAREG, TSWORD, + SCREG, TFLOAT, + NCREG, RESC1, + " fsitos AL,AR" COM "convert int to float\n" }, + +{ SCONV, INCREG | FEATURE_VFP, + SAREG, TUWORD, + SCREG, TFLOAT, + NCREG, RESC1, + " fuitos AL,AR" COM "convert int to float\n" }, + +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_FPA, + SBREG, TULONGLONG|TLONGLONG, + SCREG, TFLOAT, + NCREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INCREG | FEATURE_VFP, + SBREG, TULONGLONG|TLONGLONG, + SCREG, TFLOAT, + NCREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INAREG, + SBREG, TULONGLONG|TLONGLONG, + SAREG, TFLOAT, + NAREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INCREG | FEATURE_FPA, + SAREG, TWORD, + SCREG, TDOUBLE, + NCREG, RESC1, + " fltd AL,AR" COM "convert int to double\n" }, + +{ SCONV, INCREG | FEATURE_VFP, + SAREG, TSWORD, + SCREG, TDOUBLE, + NCREG, RESC1, + " fsitod AL,AR" COM "convert int to double\n" }, + +{ SCONV, INCREG | FEATURE_VFP, + SAREG, TUWORD, + SCREG, TDOUBLE, + NCREG, RESC1, + " fuitod AL,AR" COM "convert int to double\n" }, + +{ SCONV, INBREG, + SAREG, TWORD, + SBREG, TDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_FPA, + SBREG, TLONGLONG|TULONGLONG, + SCREG, TDOUBLE, + NCREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INCREG | FEATURE_VFP, + SBREG, TLONGLONG|TULONGLONG, + SCREG, TDOUBLE, + NCREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_FPA, + SAREG, TWORD, + SCREG, TLDOUBLE, + NCREG, RESC1, + " flte AL,AR" COM "convert int to ldouble\n" }, + +{ SCONV, INCREG | FEATURE_VFP, + SAREG, TSWORD, + SCREG, TLDOUBLE, + NCREG, RESC1, + " fsitod AL,AR" COM "convert int to ldouble\n" }, + +{ SCONV, INCREG | FEATURE_VFP, + SAREG, TUWORD, + SCREG, TLDOUBLE, + NCREG, RESC1, + " fuitod AL,AR" COM "convert uint to ldouble\n" }, + +{ SCONV, INBREG, + SAREG, TWORD, + SBREG, TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_FPA, + SBREG, TLONGLONG|TULONGLONG, + SCREG, TLDOUBLE, + NCREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INCREG | FEATURE_VFP, + SBREG, TLONGLONG|TULONGLONG, + SCREG, TLDOUBLE, + NCREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_FPA, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TFLOAT, + NCREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INCREG | FEATURE_VFP, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TFLOAT, + NCREG, RESC1, + " fcvtds AL,AR" COM "convert float to double\n" }, + +{ SCONV, INAREG, + SBREG, TDOUBLE|TLDOUBLE, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_FPA, + SCREG, TFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + COM "unimplemented\n", }, + +{ SCONV, INCREG | FEATURE_VFP, + SCREG, TFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " fcvtsd AL,AR" COM "convert float to double\n" }, + +{ SCONV, INBREG, + SAREG, TFLOAT, + SBREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_FPA, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + COM "convert (l)double to (l)double", }, + +{ SCONV, INCREG | FEATURE_VFP, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + COM "convert (l)double to (l)double", }, + +{ SCONV, INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + COM "convert (l)double to (l)double", }, + +/* + * Subroutine calls. + */ + +{ CALL, FOREFF, + SCON|SNAME, TANY, + SANY, TANY, + 0, 0, + " bl CL" COM "call (args, no result) to scon/sname (CL)\n" + "ZC", }, + +{ UCALL, FOREFF, + SCON|SNAME, TANY, + SANY, TANY, + 0, 0, + " bl CL" COM "call (no args, no result) to scon/sname (CL)\n", }, + +{ CALL, INAREG, + SCON|SNAME, TANY, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result in r0) to scon/sname (CL)\n" + "ZC", }, + +{ CALL, INBREG, + SCON|SNAME, TANY, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" + "ZC", }, + +{ CALL, INCREG | FEATURE_FPA, + SCON|SNAME, TANY, + SCREG, TFLOAT, + NCREG|NCSL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result r0) to scon/sname (CL)\n" + "ZC", }, + +{ CALL, INCREG | FEATURE_FPA, + SCON|SNAME, TANY, + SCREG, TDOUBLE|TLDOUBLE, + NCREG|NCSL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" + "ZC", }, + +{ CALL, INAREG, + SCON|SNAME, TANY, + SAREG, TFLOAT, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result r0) to scon/sname (CL)\n" + "ZC", }, + +{ CALL, INBREG, + SCON|SNAME, TANY, + SBREG, TDOUBLE|TLDOUBLE, + NBREG|NBSL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" + "ZC", }, + +{ UCALL, INAREG, + SCON|SNAME, TANY, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", }, + +{ UCALL, INBREG, + SCON|SNAME, TANY, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", }, + +{ UCALL, INCREG | FEATURE_FPA, + SCON|SNAME, TANY, + SCREG, TFLOAT, + NCREG|NCSL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", }, + +{ UCALL, INCREG | FEATURE_FPA, + SCON|SNAME, TANY, + SCREG, TDOUBLE|TLDOUBLE, + NCREG|NCSL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " mov lr,pc\n" + " mov pc,AL\n" + "ZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " mov lr,pc\n" + " mov pc,AL\n", }, + +{ CALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG, RESC1, + " mov lr,pc\n" + " mov pc,AL\n" + "ZC", }, + +{ UCALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG, RESC1, + " mov lr,pc\n" + " mov pc,AL\n", }, + +{ CALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG, RESC1, + " mov lr,pc\n" + " mov pc,AL\n" + "ZC", }, + +{ UCALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG, RESC1, + " mov lr,pc\n" + " mov pc,AL\n", }, + +/* struct return */ +{ USTCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " bl CL\n", }, + +{ USTCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL\n", }, + +{ USTCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " mov lr,pc\n" + " mov pc,AL\n", }, + +{ STCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " bl CL\n" + "ZC", }, + +{ STCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL\n" + "ZC", }, + +{ STCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " mov lr,pc\n" + " mov pc,AL\n" + "ZC", }, + +/* + * The next rules handle all binop-style operators. + */ + +{ PLUS, INAREG, + SAREG, TWORD|TPOINT, + SCCON, TANY, + NAREG, RESC1, + " add A1,AL,AR" COM "addition of constant\n", }, + +{ PLUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SSCON, TANY, + NBREG|NBSL, RESC1, + " adds A1,AL,AR" COM "64-bit addition of constant\n" + " adc U1,UL,UR\n", }, + +{ PLUS, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + " add A1,AL,AR" COM "addition\n", }, + +{ PLUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " adds A1,AL,AR" COM "64-bit addition\n" + " adc U1,UL,UR\n", }, + +{ PLUS, INCREG | FEATURE_FPA, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " adfs A1,AL,AR" COM "float add\n", }, + +{ PLUS, INCREG | FEATURE_VFP, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " fadds A1,AL,AR" COM "float add\n", }, + +{ PLUS, INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ PLUS, INCREG | FEATURE_FPA, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESC1, + " adfd A1,AL,AR" COM "double add\n", }, + +{ PLUS, INCREG | FEATURE_VFP, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESC1, + " faddd A1,AL,AR" COM "double add\n", }, + +{ PLUS, INBREG, + SBREG, TDOUBLE, + SBREG, TDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ PLUS, INCREG | FEATURE_FPA, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + NCREG, RESC1, + " adfe A1,AL,AR" COM "ldouble add\n", }, + +{ PLUS, INCREG | FEATURE_VFP, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + NCREG, RESC1, + " faddd A1,AL,AR" COM "ldouble add\n", }, + +{ PLUS, INBREG, + SBREG, TLDOUBLE, + SBREG, TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ MINUS, INAREG, + SAREG, TWORD|TPOINT, + SCCON, TANY, + NAREG|NASL, RESC1, + " sub A1,AL,AR" COM "subtraction of constant\n", }, + +{ MINUS, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + " sub A1,AL,AR" COM "subtraction\n", }, + +{ MINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCCON, TANY, + NBREG|NBSL, RESC1, + " subs A1,AL,AR" COM "64-bit subtraction of constant\n" + " rsc U1,UL,AR\n", }, + +{ MINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " subs A1,AL,AR" COM "64-bit subtraction\n" + " sbc U1,UL,AR\n", }, + +{ MINUS, INCREG | FEATURE_FPA, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " sufs A1,AL,AR" COM "float subtraction\n", }, + +{ MINUS, INCREG | FEATURE_VFP, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " fsubs A1,AL,AR" COM "float subtraction\n", }, + +{ MINUS, INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ MINUS, INCREG | FEATURE_FPA, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESC1, + " sufd A1,AL,AR" COM "double subtraction\n", }, + +{ MINUS, INCREG | FEATURE_VFP, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESC1, + " fsubd A1,AL,AR" COM "double subtraction\n", }, + +{ MINUS, INBREG, + SBREG, TDOUBLE, + SBREG, TDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ MINUS, INCREG | FEATURE_FPA, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + NCREG, RESC1, + " sufe A1,AL,AR" COM "ldouble subtraction\n", }, + +{ MINUS, INCREG | FEATURE_VFP, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + NCREG, RESC1, + " fsubd A1,AL,AR" COM "double subtraction\n", }, + +{ MINUS, INBREG, + SBREG, TLDOUBLE, + SBREG, TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +/* + * The next rules handle all shift operators. + */ + +{ LS, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TANY, + NAREG|NASL, RESC1, + " mov A1,AL,asl AR" COM "left shift\n", }, + +{ LS, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SCCON, TANY, + NAREG|NASL, RESC1, + " mov A1,AL,asl AR" COM "left shift by constant\n", }, + +{ LS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCON, TANY, + NBREG, RESC1, + "ZO" }, + +{ LS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TANY, + NSPECIAL|NBREG, RESC1, + "ZE" }, + +{ RS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TANY, + NAREG|NASL, RESC1, + " mov A1,AL,asr AR" COM "right shift\n", }, + +{ RS, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TANY, + NAREG|NASL, RESC1, + " mov A1,AL,lsr AR" COM "right shift\n", }, + +{ RS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SCCON, TANY, + NAREG|NASL, RESC1, + " mov A1,AL,asr AR" COM "right shift by constant\n", }, + +{ RS, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SCCON, TANY, + NAREG|NASL, RESC1, + " mov A1,AL,lsr AR" COM "right shift by constant\n", }, + +{ RS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCON, TANY, + NBREG, RESC1, + "ZO" }, + +{ RS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TANY, + NSPECIAL|NBREG, RESC1, + "ZE" }, + + +/* + * The next rules takes care of assignments. "=". + */ + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " str AR,AL" COM "assign word\n", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG|SNAME, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RDEST, + " str AR,AL" COM "assign 64-bit value\n" + " str UR,UL\n", }, + +/* XXX don't know if this works */ +{ ASSIGN, FOREFF|INBREG, + SAREG, TPTRTO|TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RDEST, + " stmdb AL,{AR-UR}" COM "assign 64-bit value\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + 0, RDEST, + " strb AR,AL" COM "assign (u)char\n", }, + +{ ASSIGN, FOREFF|INAREG | FEATURE_HALFWORDS, + SOREG|SNAME, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RDEST, + " strh AR,AL" COM "assign (u)short\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + NAREG|NASL, RDEST, + "ZH", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, + SOREG|SNAME, TFLOAT, + SCREG, TFLOAT, + 0, RDEST, + " stfs AR,AL" COM "assign float\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, + SOREG|SNAME, TFLOAT, + SCREG, TFLOAT, + 0, RDEST, + COM "unimplemented\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TFLOAT, + SAREG, TFLOAT, + 0, RDEST, + " str AR,AL" COM "assign float (soft-float)\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, + SOREG|SNAME, TDOUBLE, + SCREG, TDOUBLE, + 0, RDEST, + " stfd AR,AL" COM "assign double\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, + SOREG|SNAME, TDOUBLE, + SCREG, TDOUBLE, + 0, RDEST, + COM "unimplemented\n", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG|SNAME, TDOUBLE, + SBREG, TDOUBLE, + 0, RDEST, + " str AR,AL" COM "assign double (soft-float)\n" + " str UR,UL\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, + SOREG|SNAME, TLDOUBLE, + SCREG, TLDOUBLE, + 0, RDEST, + " stfe AR,AL" COM "assign ldouble\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, + SOREG|SNAME, TLDOUBLE, + SCREG, TLDOUBLE, + 0, RDEST, + COM "not implemented", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG|SNAME, TLDOUBLE, + SBREG, TLDOUBLE, + 0, RDEST, + " str AR,AL" COM "assign ldouble (soft-float)\n" + " str UR,UL\n", }, + +/* assign register to register */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, RDEST, + " mov AL,AR" COM "assign AR to AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RDEST, + " mov AL,AR" COM "assign UR:AR to UL:AL\n" + " mov UL,UR\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, + SCREG, TFLOAT, + SCREG, TFLOAT, + 0, RDEST, + " mvf AL,AR" COM "assign float reg to float reg\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, + SCREG, TFLOAT, + SCREG, TFLOAT, + 0, RDEST, + " fcpys AL,AR" COM "assign float reg to float reg\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + 0, RDEST, + " mov AL,AR" COM "assign float reg to float reg\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_FPA, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " mvf AL,AR" COM "assign float reg to float reg\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_VFP, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " fcpyd AL,AR" COM "assign float reg to float reg\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " mov AL,AR" COM "assign (l)double reg to (l)double reg\n" + " mov UL,UR\n", }, + +{ ASSIGN, FOREFF|INAREG, + SFLD, TANY, + SOREG|SNAME, TANY, + 3*NAREG, RDEST, + " ldr A1,AR" COM "bit-field assignment\n" + " ldr A2,AL\n" + " ldr A3,=M\n" + " mov A1,A1,asl H\n" + " and A1,A1,A3\n" + " bic A2,A2,A3\n" + " orr A3,A2,A1\n" + " str A3,AL\n" + "F ldr AD,AR\n" + "FZB", }, + +{ ASSIGN, FOREFF|INAREG, + SFLD, TANY, + SAREG, TANY, + 3*NAREG, RDEST, + " ldr A2,AL" COM "bit-field assignment\n" + " ldr A3,=M\n" + " mov A1,AR,asl H\n" + " and A1,A1,A3\n" + " bic A2,A2,A3\n" + " orr A3,A2,A1\n" + " str A3,AL\n" + "F mov AD,AR\n" + "FZB", }, + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG, TPTRTO|TANY, + NSPECIAL, RDEST, + "ZQ", }, + +/* + * DIV/MOD/MUL + */ + +{ DIV, INAREG, + SAREG, TWORD, + SAREG, TWORD, + NSPECIAL|NAREG|NASL, RESC1, + "ZE", }, + +{ DIV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG|NBSL, RESC1, + "ZE", }, + +{ DIV, INCREG | FEATURE_FPA, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " dvfs A1,AL,AL" COM "fast (float) divide\n", }, + +{ DIV, INCREG | FEATURE_VFP, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " fdivs A1,AL,AL" COM "fast (float) divide\n", }, + +{ DIV, INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ DIV, INCREG | FEATURE_FPA, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESC1, + " dvfd A1,AL,AL" COM "double divide\n", }, + +{ DIV, INCREG | FEATURE_VFP, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESC1, + " fdivd A1,AL,AL" COM "double divide\n", }, + +{ DIV, INBREG, + SBREG, TDOUBLE, + SBREG, TDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ DIV, INCREG | FEATURE_FPA, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + NCREG, RESC1, + " dvfe A1,AL,AR" COM "long double load\n", }, + +{ DIV, INCREG | FEATURE_VFP, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + NCREG, RESC1, + " fdivd A1,AL,AL" COM "double divide\n", }, + +{ DIV, INBREG, + SBREG, TLDOUBLE, + SBREG, TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ MOD, INAREG, + SAREG, TWORD, + SAREG, TWORD, + NSPECIAL|NAREG, RESC1, + "ZE", }, + +{ MOD, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ MUL, INAREG | FEATURE_MUL, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG, RESC1, + " mul A1,AL,AR\n", }, + +{ MUL, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NSPECIAL|NAREG, RESC1, + "ZE", }, + +{ MUL, INBREG | FEATURE_MULL, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + NBREG, RESC1, + " smull U1,A1,AL,AR\n", }, + +{ MUL, INBREG | FEATURE_MUL, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + NBREG, RESC1, + " mul A1,AL,AR\n" + " mov U1,A1,asr #31\n", }, + +{ MUL, INBREG, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ MUL, INBREG | FEATURE_MULL, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NBREG, RESC1, + " umull U1,A1,AL,AR\n", }, + +{ MUL, INBREG | FEATURE_MUL, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NBREG, RESC1, + " mul A1,AL,AR\n" + " mov U1,#0\n", }, + +{ MUL, INBREG, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ MUL, INBREG | FEATURE_MULL, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " umull U1,A1,AL,AR\n", }, + +{ MUL, INBREG | FEATURE_MUL, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " mul A1,AL,AR\n" + " mov U1,A1,asr #31\n", }, + +{ MUL, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ MUL, INCREG | FEATURE_FPA, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " fmls A1,AL,AL" COM "fast (float) multiply\n", }, + +{ MUL, INCREG | FEATURE_VFP, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " fmuls A1,AL,AL" COM "float multiply\n", }, + +{ MUL, INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ MUL, INCREG | FEATURE_FPA, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " mufd A1,AL,AL" COM "fast (l)double multiply\n", }, + +{ MUL, INCREG | FEATURE_VFP, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " muld A1,AL,AL" COM "(l)double multiply\n", }, + +{ MUL, INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +/* + * Indirection operators. + */ + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TWORD|TPOINT, + NAREG, RESC1, + " ldr A1,AL" COM "word load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TCHAR, + NAREG, RESC1, + " ldrsb A1,AL" COM "char load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TUCHAR, + NAREG, RESC1, + " ldrb A1,AL" COM "uchar load\n", }, + +{ UMUL, INAREG | FEATURE_HALFWORDS, + SANY, TANY, + SOREG|SNAME, TUSHORT, + NAREG, RESC1, + " ldrh A1,AL" COM "short load\n", }, + +{ UMUL, INAREG | FEATURE_HALFWORDS, + SANY, TANY, + SOREG|SNAME, TSHORT, + NAREG, RESC1, + " ldrsh A1,AL" COM "short load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TSHORT|TUSHORT, + 2*NAREG|NASL, RESC1, + "ZH", }, + +{ UMUL, INBREG, + SANY, TANY, + SOREG|SNAME, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " ldr A1,AL" COM "64-bit load\n" + " ldr U1,UL\n", }, + +{ UMUL, INCREG | FEATURE_FPA, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NCREG, RESC1, + " ldfs A1,AL" COM "float load\n", }, + +{ UMUL, INCREG | FEATURE_VFP, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NCREG, RESC1, + COM "not implemented\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NAREG, RESC1, + " ldr A1,AL" COM "float load\n", }, + +{ UMUL, INCREG | FEATURE_FPA, + SANY, TANY, + SOREG|SNAME, TDOUBLE, + NCREG, RESC1, + " ldfd A1,AL" COM "double load\n", }, + +{ UMUL, INCREG | FEATURE_VFP, + SANY, TANY, + SOREG|SNAME, TDOUBLE, + NCREG, RESC1, + COM "not implemented\n", }, + +{ UMUL, INBREG, + SANY, TANY, + SOREG|SNAME, TDOUBLE, + NBREG, RESC1, + " ldr A1,AL" COM "double load\n" + " ldr U1,UL\n", }, + +{ UMUL, INCREG | FEATURE_FPA, + SANY, TANY, + SOREG|SNAME, TLDOUBLE, + NCREG, RESC1, + " ldfe A1,AL" COM "long double load\n", }, + +{ UMUL, INCREG | FEATURE_VFP, + SANY, TANY, + SOREG|SNAME, TLDOUBLE, + NCREG, RESC1, + COM "not implemented\n", }, + +{ UMUL, INBREG, + SANY, TANY, + SOREG|SNAME, TLDOUBLE, + NBREG, RESC1, + " ldr A1,AL" COM "long double load (soft-float)\n" + " ldr U1,UL\n", }, + +/* + * Logical/branching operators + */ + +/* compare with register */ +{ OPLOG, FORCC, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + 0, RESCC, + " cmp AL,AR" COM "AR-AL (sets flags)\n", }, + +/* compare with register */ +{ OPLOG, FORCC, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + 0, RESCC, + " cmp AL,AR" COM "AR-AL (sets flags)\n", }, + +/* compare with register */ +{ OPLOG, FORCC, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RESCC, + "ZD", }, + +{ OPLOG, FORCC | FEATURE_FPA, + SCREG, TFLOAT, + SCREG, TFLOAT, + NSPECIAL, RESCC, + " cmfs AL,AR" COM "float compare\n", }, + +{ OPLOG, FORCC | FEATURE_VFP, + SCREG, TFLOAT, + SCREG, TFLOAT, + 0, RESCC, + " fcmps AL,AR" COM "float compare\n", }, + +{ OPLOG, FORCC, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL, RESCC, + "ZF", }, + +{ OPLOG, FORCC | FEATURE_FPA, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NSPECIAL, RESCC, + " cmfd AL,AR" COM "double compare\n", }, + +{ OPLOG, FORCC | FEATURE_VFP, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + 0, RESCC, + " fcmpd AL,AR" COM "double compare\n", }, + +{ OPLOG, FORCC, + SBREG, TDOUBLE, + SBREG, TDOUBLE, + NSPECIAL, RESCC, + "ZF", }, + +{ OPLOG, FORCC | FEATURE_FPA, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + NSPECIAL, RESCC, + " cmfe AL,AR" COM "ldouble compare\n", }, + +{ OPLOG, FORCC | FEATURE_VFP, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + 0, RESCC, + " fcmpd AL,AR" COM "double compare\n", }, + +{ OPLOG, FORCC, + SBREG, TLDOUBLE, + SBREG, TLDOUBLE, + NSPECIAL, RESCC, + "ZF", }, + +/* AND/OR/ER */ +{ AND, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1|RESCC, + " and A1,AL,AR" COM "64-bit and\n" + " and U1,UL,UR\n", }, + +{ OR, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " orr A1,AL,AR" COM "64-bit or\n" + " orr U1,UL,UR\n" }, + +{ ER, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " eor A1,AL,AR" COM "64-bit xor\n" + " eor U1,UL,UR\n" }, + +{ OPSIMP, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1|RESCC, + " O A1,AL,AR\n", }, + +{ OPSIMP, INAREG|FORCC, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " Os A1,AL,AR\n", }, + + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " b LL\n", }, + +#if 0 +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " mov pc,AL\n", }, +#endif + +/* + * Convert LTYPE to reg. + */ + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TWORD|TPOINT, + NAREG, RESC1, + " ldr A1,AL" COM "load word from memory\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SOREG|SNAME, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " ldr A1,AL" COM "load long long from memory\n" + " ldr U1,UL\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TCHAR, + NAREG, RESC1, + " ldrsb A1,AL" COM "load char from memory\n" }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TUCHAR, + NAREG, RESC1, + " ldrb A1,AL" COM "load uchar from memory\n", }, + +{ OPLTYPE, INAREG | FEATURE_HALFWORDS, + SANY, TANY, + SOREG|SNAME, TSHORT, + NAREG, RESC1, + " ldrsh A1,AL" COM "load short from memory\n", }, + +{ OPLTYPE, INAREG | FEATURE_HALFWORDS, + SANY, TANY, + SOREG|SNAME, TUSHORT, + NAREG, RESC1, + " ldrh A1,AL" COM "load ushort from memory\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TSHORT|TUSHORT, + 2*NAREG, RESC1, + "ZH", }, + +#if 0 +{ OPLTYPE, INAREG, + SANY, TANY, + SCON, TPOINT, + NAREG, RESC1, + " ldr A1,AL" COM "load integer constant\n", }, +#endif + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON, TANY, + NAREG, RESC1, + "ZI", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SCON, TANY, + NBREG, RESC1, + "ZJ", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG, TANY, + NAREG, RESC1, + " mov A1,AL" COM "load AL into A1\n" }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " mov A1,AL" COM "load UL:AL into U1:A1\n" + " mov U1,UL\n", }, + +{ OPLTYPE, INCREG | FEATURE_FPA, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NCREG, RESC1, + " ldfs A1,AL" COM "load float\n", }, + +{ OPLTYPE, INCREG | FEATURE_VFP, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NCREG, RESC1, + COM "not implemented\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NAREG, RESC1, + " ldr A1,AL" COM "load float (soft-float)\n", }, + +{ OPLTYPE, INCREG | FEATURE_FPA, + SANY, TANY, + SOREG|SNAME, TDOUBLE, + NCREG, RESC1, + " ldfd A1,AL" COM "load double\n", }, + +{ OPLTYPE, INCREG | FEATURE_VFP, + SANY, TANY, + SOREG|SNAME, TDOUBLE, + NCREG, RESC1, + COM "not implemented\n" }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SOREG|SNAME, TDOUBLE, + NBREG, RESC1, + " ldr A1,AL" COM "load double (soft-float)\n" + " ldr U1,UL\n", }, + +{ OPLTYPE, INCREG | FEATURE_FPA, + SANY, TANY, + SOREG|SNAME, TLDOUBLE, + NCREG, RESC1, + " ldfe A1,AL" COM "load ldouble\n", }, + +{ OPLTYPE, INCREG | FEATURE_VFP, + SANY, TANY, + SOREG|SNAME, TLDOUBLE, + NCREG, RESC1, + COM "not implemented\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SOREG|SNAME, TLDOUBLE, + NBREG, RESC1, + " ldr A1,AL" COM "load ldouble (soft-float)\n" + " ldr U1,UL\n", }, + +/* + * Negate a word. + */ + +{ UMINUS, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " rsb A1,AL,#0" COM "negation\n", }, + +{ UMINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " rsbs A1,AL,#0" COM "64-bit negation\n" + " rsc U1,UL,#0\n", }, + +{ UMINUS, INCREG | FEATURE_FPA, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " mvfs A1,AL" COM "float negation\n", }, + +{ UMINUS, INCREG | FEATURE_VFP, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " negs A1,AL" COM "float negation\n", }, + +{ UMINUS, INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ UMINUS, INCREG | FEATURE_FPA, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESC1, + " mvfd A1,AL" COM "double negation\n", }, + +{ UMINUS, INCREG | FEATURE_VFP, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESC1, + " negd A1,AL" COM "double negation\n", }, + +{ UMINUS, INBREG, + SBREG, TDOUBLE, + SBREG, TDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ UMINUS, INCREG | FEATURE_FPA, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + NCREG, RESC1, + " mvfe A1,AL" COM "ldouble negation\n", }, + +{ UMINUS, INCREG | FEATURE_VFP, + SCREG, TLDOUBLE, + SCREG, TLDOUBLE, + NCREG, RESC1, + " negd A1,AL" COM "ldouble negation\n", }, + +{ UMINUS, INBREG, + SBREG, TLDOUBLE, + SBREG, TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ COMPL, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TANY, + NAREG|NASL, RESC1, + " mvn A1,AL" COM "complement\n", }, + +{ COMPL, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SANY, TANY, + NBREG|NBSL, RESC1, + " mvn A1,AL" COM "64-bit complement\n" + " mvn U1,UL\n", }, + +/* + * Arguments to functions. + */ + +{ FUNARG, FOREFF, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, 0, + " stmfd sp!,{AL}" COM "save function arg to stack\n", }, + +{ FUNARG, FOREFF, + SBREG, TLONGLONG|TULONGLONG, + SANY, TLONGLONG|TULONGLONG, + 0, 0, + " stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", }, + +{ FUNARG, FOREFF, + SCREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " stmfd sp!,{AL}" COM "save function arg to stack\n", }, + +{ FUNARG, FOREFF, + SCREG, TDOUBLE|TLDOUBLE, + SANY, TDOUBLE|TLDOUBLE, + 0, 0, + " stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", }, + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +/* { INIT, DF(INIT), }, */ + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/hppa/code.c b/lang/pcc/pcc/arch/hppa/code.c new file mode 100644 index 000000000..352eecdae --- /dev/null +++ b/lang/pcc/pcc/arch/hppa/code.c @@ -0,0 +1,258 @@ +/* $Id: code.c,v 1.28 2012/06/06 09:28:01 ragge Exp $ */ +/* $OpenBSD: code.c,v 1.2 2007/11/22 15:06:43 stefan Exp $ */ + +/* + * Copyright (c) 2007 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +NODE *funarg(NODE *, int *); +int argreg(TWORD, int *); + +static const char *const loctbl[] = { "text", "data", "section .rodata" }; + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + extern char *nextsect; + static int lastloc = -1; + TWORD t; + char *n; + int s; + + if (sp == NULL) { + lastloc = -1; + return; + } + t = sp->stype; + s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA; + if (nextsect) { + printf("\t.section %s\n", nextsect); + nextsect = NULL; + s = -1; + } else if (s != lastloc) + printf("\t.%s\n", loctbl[s]); + lastloc = s; + while (ISARY(t)) + t = DECREF(t); + s = ISFTN(t) ? ALINT : talign(t, sp->ssue); + if (s > ALCHAR) + printf("\t.align\t%d\n", s / ALCHAR); + n = sp->soname ? sp->soname : sp->sname; + if (sp->sclass == EXTDEF) + printf("\t.export %s, %s\n", n, + ISFTN(t)? "code" : "data"); + if (sp->slevel == 0) + printf("\t.type\t%s, @%s\n\t.label %s\n", + n, ISFTN(t)? "function" : "object", n); + else + printf("\t.type\t" LABFMT ", @%s\n\t.label\t" LABFMT "\n", + sp->soffset, ISFTN(t)? "function" : "object", sp->soffset); +} + +/* + * code for the end of a function + * deals with struct return here + */ +void +efcode(void) +{ + NODE *p, *q; + int sz; + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + /* address of return struct is in %ret0 */ + /* create a call to memcpy() */ + /* will get the result in %ret0 */ + p = block(REG, NIL, NIL, CHAR+PTR, 0, 0); + p->n_rval = RET0; + q = block(OREG, NIL, NIL, CHAR+PTR, 0, 0); + q->n_rval = FP; + q->n_lval = 8; /* return buffer offset */ + p = block(CM, q, p, INT, 0, 0); + sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR; + p = block(CM, p, bcon(sz), INT, 0, 0); + p->n_right->n_name = ""; + p = block(CALL, bcon(0), p, CHAR+PTR, 0, 0); + p->n_left->n_name = "memcpy"; + p = clocal(p); + send_passt(IP_NODE, p); +} + +int +argreg(TWORD t, int *n) +{ + switch (t) { + case FLOAT: + return FR7L - 2 * (*n)++; + case DOUBLE: + case LDOUBLE: + *n += 2; + return FR6 - *n - 2; + case LONGLONG: + case ULONGLONG: + *n += 2; + return AD1 - (*n - 2) / 2; + default: + return ARG0 - (*n)++; + } +} + +/* + * code for the beginning of a function; 'a' is an array of + * indices in symtab for the arguments; n is the number + */ +void +bfcode(struct symtab **a, int cnt) +{ + struct symtab *sp; + NODE *p, *q; + int i, n, sz; + + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + /* Function returns struct, adjust arg offset */ + for (i = 0; i < cnt; i++) + a[i]->soffset += SZPOINT(LONG); + } + + /* recalculate the arg offset and create TEMP moves */ + for (n = 0, i = 0; i < cnt; i++) { + sp = a[i]; + + sz = szty(sp->stype); + if (n % sz) + n++; /* XXX LDOUBLE */ + + if (n < 4) { + p = tempnode(0, sp->stype, sp->sdf, sp->ssue); + /* TODO p->n_left->n_lval = -(32 + n * 4); */ + q = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->ssue); + q->n_rval = argreg(sp->stype, &n); + p = buildtree(ASSIGN, p, q); + sp->soffset = regno(p->n_left); + sp->sflags |= STNODE; + ecomp(p); + } else { + sp->soffset += SZINT * n; + if (xtemps) { + /* put stack args in temps if optimizing */ + p = tempnode(0, sp->stype, sp->sdf, sp->ssue); + p = buildtree(ASSIGN, p, buildtree(NAME, 0, 0)); + sp->soffset = regno(p->n_left); + sp->sflags |= STNODE; + ecomp(p); + } + } + } +} + + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ + if (flag) + return; + + printf("\t.end\n"); +} + +void +bjobcode(void) +{ + printf("\t.level\t1.1\n" + "\t.import $global$, data\n" + "\t.import $$dyncall, millicode\n"); +} + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + +NODE * +funarg(NODE *p, int *n) +{ + NODE *r; + int sz; + + if (p->n_op == CM) { + p->n_left = funarg(p->n_left, n); + p->n_right = funarg(p->n_right, n); + return p; + } + + sz = szty(p->n_type); + if (*n % sz) + (*n)++; /* XXX LDOUBLE */ + + if (*n >= 4) { + *n += sz; + r = block(OREG, NIL, NIL, p->n_type|PTR, 0, 0); + r->n_rval = SP; + r->n_lval = -(32 + *n * 4); + } else { + r = block(REG, NIL, NIL, p->n_type, 0, 0); + r->n_lval = 0; + r->n_rval = argreg(p->n_type, n); + } + p = block(ASSIGN, r, p, p->n_type, 0, 0); + clocal(p); + + return p; +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + */ +NODE * +funcode(NODE *p) +{ + int n = 0; + + p->n_right = funarg(p->n_right, &n); + return p; +} diff --git a/lang/pcc/pcc/arch/hppa/local.c b/lang/pcc/pcc/arch/hppa/local.c new file mode 100644 index 000000000..2daf821bf --- /dev/null +++ b/lang/pcc/pcc/arch/hppa/local.c @@ -0,0 +1,823 @@ +/* $Id: local.c,v 1.41 2015/08/18 10:15:08 ragge Exp $ */ +/* $OpenBSD: local.c,v 1.2 2007/11/18 17:39:55 ragge Exp $ */ + +/* + * Copyright (c) 2007 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" +#include "pass2.h" + +/* this file contains code which is dependent on the target machine */ + +#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) + +struct symtab *makememcpy(void); + +/* clocal() is called to do local transformations on + * an expression tree preparitory to its being + * written out in intermediate code. + * + * the major essential job is rewriting the + * automatic variables and arguments in terms of + * REG and OREG nodes + * conversion ops which are not necessary are also clobbered here + * in addition, any special features (such as rewriting + * exclusive or) are easily handled here as well + */ +NODE * +clocal(NODE *p) +{ + register struct symtab *q, *sp; + register NODE *r, *l, *s; + register int o, m, rn; + char *ch, name[16], *n; + TWORD t; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + switch (o = p->n_op) { + + case NAME: + if ((q = p->n_sp) == NULL) + break; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + /* first four integral args are in regs */ + rn = (q->soffset >> 5) - 8; + if (rn < 4) { + r = block(REG, NIL, NIL, p->n_type, 0, 0); + r->n_lval = 0; + switch (p->n_type) { + case FLOAT: + r->n_rval = FR7L - rn; + break; + case DOUBLE: + case LDOUBLE: + r->n_rval = FR6 - rn; + break; + case LONGLONG: + case ULONGLONG: + r->n_rval = AD1 - rn / 2; + break; + default: + r->n_rval = ARG0 - rn; + } + r->n_sue = p->n_sue; + p->n_sue = NULL; + nfree(p); + p = r; + break; + } + /* FALLTHROUGH */ + + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + r->n_lval = 0; + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case REGISTER: + p->n_op = REG; + p->n_lval = 0; + p->n_rval = q->soffset; + break; + + case STATIC: + case EXTERN: + if (p->n_sp->sflags & SSTRING) + break; + + n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname; + if (strncmp(n, "__builtin", 9) == 0) + break; + + l = block(REG, NIL, NIL, INT, 0, 0); + l->n_lval = 0; + l->n_rval = R1; + l = block(ASSIGN, l, p, INT, 0, 0); + r = xbcon(0, p->n_sp, INT); + p = block(UMUL, + block(PLUS, l, r, INT, 0, 0), + NIL, p->n_type, p->n_df, p->n_sue); + break; + } + break; + + case ADDROF: + l = p->n_left; + if (!l->n_sp) + break; + + if (l->n_sp->sclass != EXTERN && + l->n_sp->sclass != STATIC && + l->n_sp->sclass != USTATIC && + l->n_sp->sclass != EXTDEF) + break; + + l = block(REG, NIL, NIL, INT, 0, 0); + l->n_lval = 0; + l->n_rval = R1; + l = block(ASSIGN, l, p->n_left, INT, 0, 0); + r = xbcon(0, p->n_left->n_sp, INT); + l = block(PLUS, l, r, p->n_type, p->n_df, p->n_sue); + nfree(p); + p = l; + break; + + case CBRANCH: + l = p->n_left; + + /* + * Remove unnecessary conversion ops. + */ + if (clogop(l->n_op) && l->n_left->n_op == SCONV) { + if (coptype(l->n_op) != BITYPE) + break; + if (l->n_right->n_op == ICON) { + r = l->n_left->n_left; + if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) + break; + /* Type must be correct */ + t = r->n_type; + nfree(l->n_left); + l->n_left = r; + l->n_type = t; + l->n_right->n_type = t; + } + } + break; + + case PCONV: + /* Remove redundant PCONV's. Be careful */ + l = p->n_left; + if (l->n_op == ICON) { + l->n_lval = (unsigned)l->n_lval; + goto delp; + } + if (l->n_type < INT || l->n_type == LONGLONG || + l->n_type == ULONGLONG) { + /* float etc? */ + p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); + break; + } + /* if left is SCONV, cannot remove */ + if (l->n_op == SCONV) + break; + + /* avoid ADDROF TEMP */ + if (l->n_op == ADDROF && l->n_left->n_op == TEMP) + break; + + /* if conversion to another pointer type, just remove */ + if (p->n_type > BTMASK && l->n_type > BTMASK) + goto delp; + break; + + delp: l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_sue = p->n_sue; + nfree(p); + p = l; + break; + + case SCONV: + l = p->n_left; + + if (p->n_type == l->n_type) { + nfree(p); + p = l; + break; + } + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + btdims[p->n_type].suesize == btdims[l->n_type].suesize) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == UMUL || l->n_op == TEMP || + l->n_op == NAME) { + l->n_type = p->n_type; + nfree(p); + p = l; + break; + } + } + } + + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && + coptype(l->n_op) == BITYPE) { + l->n_type = p->n_type; + nfree(p); + p = l; + break; + } + + o = l->n_op; + m = p->n_type; + + if (o == ICON) { + CONSZ val = l->n_lval; + + if (!ISPTR(m)) /* Pointers don't need to be conv'd */ + switch (m) { + case BOOL: + l->n_lval = l->n_lval != 0; + break; + case CHAR: + l->n_lval = (char)val; + break; + case UCHAR: + l->n_lval = val & 0377; + break; + case SHORT: + l->n_lval = (short)val; + break; + case USHORT: + l->n_lval = val & 0177777; + break; + case ULONG: + case UNSIGNED: + l->n_lval = val & 0xffffffff; + break; + case LONG: + case INT: + l->n_lval = (int)val; + break; + case LONGLONG: + l->n_lval = (long long)val; + break; + case ULONGLONG: + l->n_lval = val; + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = val; + break; + default: + cerror("unknown type %d", m); + } + l->n_type = m; + l->n_sue = 0; + nfree(p); + return l; + } else if (l->n_op == FCON) { + l->n_lval = l->n_dcon; + l->n_sp = NULL; + l->n_op = ICON; + l->n_type = m; + l->n_sue = 0; + nfree(p); + return clocal(l); + } + + if (DEUNSIGN(p->n_type) == SHORT && + DEUNSIGN(l->n_type) == SHORT) { + nfree(p); + p = l; + } + if ((p->n_type == CHAR || p->n_type == UCHAR || + p->n_type == SHORT || p->n_type == USHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue); + p->n_left->n_type = INT; + break; + } + break; + + case MOD: + case DIV: + if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) + break; + if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) + break; + /* make it an int division by inserting conversions */ + p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); + p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); + p = block(SCONV, p, NIL, p->n_type, 0, 0); + p->n_left->n_type = INT; + break; + + case LS: + case RS: + /* shift count must be in an int */ + if (p->n_right->n_op == ICON || p->n_right->n_lval <= 32) + break; /* do not do anything */ + if (p->n_right->n_type != INT || p->n_right->n_lval > 32) + p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); + break; + +#if 0 + case FLD: + /* already rewritten (in ASSIGN) */ + if (p->n_left->n_op == TEMP) + break; + + r = tempnode(0, p->n_type, p->n_df, p->n_sue); + l = block(ASSIGN, r, p->n_left, p->n_type, p->n_df, p->n_sue); + p->n_left = tcopy(r); + p = block(COMOP, l, p, p->n_type, p->n_df, p->n_sue); + break; +#endif + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue); + p->n_left->n_rval = p->n_left->n_type == BOOL ? + RETREG(CHAR) : RETREG(p->n_type); + if (p->n_right->n_op != FLD) + break; + break; + + case ASSIGN: + r = p->n_right; + l = p->n_left; + + /* rewrite ICON#0 into %r0 */ + if (r->n_op == ICON && r->n_lval == 0 && + (l->n_op == REG || l->n_op == OREG)) { + r->n_op = REG; + r->n_rval = R0; + } + + /* rewrite FCON#0 into %fr0 */ + if (r->n_op == FCON && r->n_lval == 0 && l->n_op == REG) { + r->n_op = REG; + r->n_rval = r->n_type == FLOAT? FR0L : FR0; + } + + if (p->n_left->n_op != FLD) + break; + + r = tempnode(0, l->n_type, l->n_df, l->n_sue); + p = block(COMOP, + block(ASSIGN, r, l->n_left, l->n_type, l->n_df, l->n_sue), + p, p->n_type, p->n_df, p->n_sue); + s = tcopy(l->n_left); + p = block(COMOP, p, + block(ASSIGN, s, tcopy(r), l->n_type, l->n_df, l->n_sue), + p->n_type, p->n_df, p->n_sue); + l->n_left = tcopy(r); + break; + + case STASG: + /* memcpy(left, right, size) */ + sp = makememcpy(); + l = p->n_left; + /* guess struct return */ + if (l->n_op == NAME && ISFTN(l->n_sp->stype)) { + l = block(REG, NIL, NIL, VOID|PTR, 0, 0); + l->n_lval = 0; + l->n_rval = RET0; + } else if (l->n_op == UMUL) + l = tcopy(l->n_left); + else if (l->n_op == NAME) + l = block(ADDROF,tcopy(l),NIL,PTR|STRTY,0,0); + l = block(CALL, block(ADDROF, + (s = block(NAME, NIL, NIL, FTN, 0, 0)), + NIL, PTR|FTN, 0, 0), + block(CM, block(CM, l, tcopy(p->n_right), + STRTY|PTR, 0, 0), + (r = block(ICON, NIL, NIL, INT, 0, 0)), 0, 0, 0), + INT, 0, 0); + r->n_lval = p->n_sue->suesize/SZCHAR; + s->n_sp = sp; + s->n_df = s->n_sp->sdf; + defid(s, EXTERN); + tfree(p); + p = l; + p->n_left = clocal(p->n_left); + p->n_right = clocal(p->n_right); + calldec(p->n_left, p->n_right); + funcode(p); + break; + + case STARG: + /* arg = memcpy(argN-size, src, size) */ + sp = makememcpy(); + l = block(CALL, block(ADDROF, + (s = block(NAME, NIL, NIL, FTN, 0, 0)),NIL,0,0,0), + block(CM, block(CM, tcopy(p), tcopy(p->n_left), 0, 0, 0), + (r = block(ICON, NIL, NIL, INT, 0, 0)), 0, 0, 0), + INT, 0, 0); + r->n_lval = p->n_sue->suesize/SZCHAR; + s->n_sp = sp; + s->n_df = s->n_sp->sdf; + defid(s, EXTERN); + tfree(p); + p = l; + p->n_left = clocal(p->n_left); + calldec(p->n_left, p->n_right); + funcode(p); + break; + + case STCALL: + case CALL: + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + if (r->n_right->n_op == ASSIGN && + r->n_right->n_right->n_op == CALL) { + s = r->n_right->n_right; + l = tempnode(0, s->n_type, s->n_df, s->n_sue); + ecode(buildtree(ASSIGN, l, s)); + r->n_right->n_right = tcopy(l); + } + if (r->n_left->n_op == ASSIGN && + r->n_left->n_right->n_op == CALL) { + s = r->n_left->n_right; + l = tempnode(0, s->n_type, s->n_df, s->n_sue); + ecode(buildtree(ASSIGN, l, s)); + r->n_left->n_right = tcopy(l); + } + } + break; + } + + /* second pass - rewrite long ops */ + switch (o) { + case DIV: + case MOD: + case MUL: + case RS: + case LS: + if (!(p->n_type == LONGLONG || p->n_type == ULONGLONG) || + !((o == DIV || o == MOD || o == MUL) && + p->n_type < FLOAT)) + break; + if (o == DIV && p->n_type == ULONGLONG) ch = "udiv"; + else if (o == DIV) ch = "div"; + else if (o == MUL) ch = "mul"; + else if (o == MOD && p->n_type == ULONGLONG) ch = "umod"; + else if (o == MOD) ch = "mod"; + else if (o == RS && p->n_type == ULONGLONG) ch = "lshr"; + else if (o == RS) ch = "ashr"; + else if (o == LS) ch = "ashl"; + else break; + snprintf(name, sizeof(name), "__%sdi3", ch); + p->n_right = block(CM, p->n_left, p->n_right, 0, 0, 0); + p->n_left = block(ADDROF, + block(NAME, NIL, NIL, FTN, 0, 0), NIL, PTR|FTN, 0, 0); + p->n_left->n_left->n_sp = lookup(addname(name), 0); + defid(p->n_left->n_left, EXTERN); + p->n_left = clocal(p->n_left); + calldec(p->n_left, p->n_right); + p->n_op = CALL; + funcode(p); + break; + } + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal end: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + return(p); +} + +struct symtab * +makememcpy(void) +{ + NODE *memcpy, *args, *t, *u; + struct symtab *sp; + + /* TODO check that it's a func proto */ + if ((sp = lookup(addname("memcpy"), SNORMAL))) + return sp; + + memcpy = block(NAME, NIL, NIL, 0, 0, 0); + memcpy->n_sp = sp = lookup(addname("memcpy"), SNORMAL); + defid(memcpy, EXTERN); + + args = block(CM, block(CM, + block(NAME, NIL, NIL, VOID|PTR, 0, 0), + block(NAME, NIL, NIL, VOID|PTR, 0, 0), 0, 0, 0), + block(NAME, NIL, NIL, LONG, 0, 0), 0, 0, 0); + + tymerge(t = block(TYPE, NIL, NIL, VOID|PTR, 0, 0), + (u = block(UMUL, block(CALL, memcpy, args, LONG, 0, 0), + NIL, LONG, 0, 0))); + tfree(t); + tfree(u); + + return sp; +} + +void +myp2tree(NODE *p) +{ + struct symtab *sp; + int o = p->n_op; + + if (o != FCON) + return; + + /* Write float constants to memory */ + /* Should be volontary per architecture */ + +#if 0 + setloc1(RDATA); + defalign(p->n_type == FLOAT ? ALFLOAT : p->n_type == DOUBLE ? + ALDOUBLE : ALLDOUBLE ); + deflab1(i = getlab()); +#endif + sp = tmpalloc(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->ssue = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + + defloc(sp); + ninval(0, btdims[p->n_type].suesize, p); + + p->n_op = NAME; + p->n_lval = 0; + p->n_sp = sp; + +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * Return 1 if a variable of type "t" is OK to put in register. + */ +int +cisreg(TWORD t) +{ + return 1; +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a storeable node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ + + /* sub the size from sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(PLUSEQ, sp, p)); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); + sp->n_lval = 0; + sp->n_rval = STKREG; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + +} + +/* + * print out a constant node, may be associated with a label. + * Do not free the node after use. + * off is bit offset from the beginning of the aggregate + * fsz is the number of bits this is referring to + * + * XXX this relies on the host fp numbers representation + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; long double l; int i[3]; } u; + struct symtab *q; + TWORD t; + int i; + + t = p->n_type; + if (t > BTMASK) + p->n_type = t = INT; /* pointer */ + + if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) + uerror("element not constant"); + + switch (t) { + case LONGLONG: + case ULONGLONG: + i = (p->n_lval >> 32); + p->n_lval &= 0xffffffff; + p->n_type = INT; + ninval(off, 32, p); + p->n_lval = i; + ninval(off+32, 32, p); + break; + case INT: + case UNSIGNED: + printf("\t.long 0x%x", (int)p->n_lval); + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0)) { + printf("+" LABFMT, q->soffset); + } else + printf("+%s", + q->soname ? q->soname : exname(q->sname)); + } + printf("\n"); + break; + case LDOUBLE: + case DOUBLE: + u.d = (double)p->n_dcon; + printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]); + break; + case FLOAT: + u.f = (float)p->n_dcon; + printf("\t.long\t0x%x\n", u.i[0]); + break; + default: + return 0; + } + return 1; +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ + if (p == NULL) + return ""; + return p; +} + +/* + * map types which are not defined on the local machine + */ +TWORD +ctype(TWORD type) +{ + switch (BTYPE(type)) { + case LONG: + MODTYPE(type,INT); + break; + + case ULONG: + MODTYPE(type,UNSIGNED); + } + + return (type); +} + +void +calldec(NODE *f, NODE *a) +{ + struct symtab *q; + if (f->n_op == UMUL && f->n_left->n_op == PLUS && + f->n_left->n_right->n_op == ICON) + q = f->n_left->n_right->n_sp; + else if (f->n_op == PLUS && f->n_right->n_op == ICON) + q = f->n_right->n_sp; + else { + fwalk(f, eprint, 0); + cerror("unknown function"); + return; + } + + printf("\t.import\t%s,code\n", q->soname ? q->soname : exname(q->sname)); +} + +void +extdec(struct symtab *q) +{ + printf("\t.import\t%s,data\n", q->soname ? q->soname : exname(q->sname)); +} + +/* make a common declaration for id, if reasonable */ +void +defzero(struct symtab *sp) +{ + int off; + + off = tsize(sp->stype, sp->sdf, sp->ssue); + off = (off + (SZCHAR - 1)) / SZCHAR; + printf("\t.%scomm\t", sp->sclass == STATIC ? "l" : ""); + if (sp->slevel == 0) + printf("%s,0%o\n", sp->soname ? sp->soname : exname(sp->sname), off); + else + printf(LABFMT ",0%o\n", sp->soffset, off); +} + +static char * +section2string(char *name) +{ + int len = strlen(name); + + if (strncmp(name, "link_set", 8) == 0) { + const char postfix[] = ",\"aw\",@progbits"; + char *s; + + s = IALLOC(len + sizeof(postfix)); + memcpy(s, name, len); + memcpy(s + len, postfix, sizeof(postfix)); + return s; + } + + return newstring(name, len); +} + +char *nextsect; +char *alias; +int constructor; +int destructor; + +#define SSECTION 010000 + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + char *a2 = pragtok(NULL); + + if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { + constructor = 1; + return 1; + } + if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { + destructor = 1; + return 1; + } + if (strcmp(str, "section") == 0 && a2 != NULL) { + nextsect = section2string(a2); + return 1; + } + if (strcmp(str, "alias") == 0 && a2 != NULL) { + alias = tmpstrdup(a2); + return 1; + } + return 0; +} + +/* + * Called when a identifier has been declared, to give target last word. + */ +void +fixdef(struct symtab *sp) +{ + if (alias != NULL && (sp->sclass != PARAM)) { + printf("\t.globl %s\n%s = %s\n", exname(sp->soname), + exname(sp->soname), exname(alias)); + alias = NULL; + } + if ((constructor || destructor) && (sp->sclass != PARAM)) { + printf("\t.section .%ctors,\"aw\",@progbits\n" + "\t.p2align 2\n\t.long %s\n\t.previous\n", + constructor ? 'c' : 'd', exname(sp->sname)); + constructor = destructor = 0; + } +} + +void +pass1_lastchance(struct interpass *ip) +{ +} diff --git a/lang/pcc/pcc/arch/hppa/local2.c b/lang/pcc/pcc/arch/hppa/local2.c new file mode 100644 index 000000000..346767ec9 --- /dev/null +++ b/lang/pcc/pcc/arch/hppa/local2.c @@ -0,0 +1,880 @@ +/* $Id: local2.c,v 1.31 2015/01/04 19:17:23 ragge Exp $ */ + +/* + * Copyright (c) 2007 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" +# include +# include + +void acon(NODE *p); +void prtprolog(struct interpass_prolog *, int); +int countargs(NODE *p, int *); +void fixcalls(NODE *p, void *); + +static int stkpos; +int p2calls; + +static const int rl[] = + { R0, R1, R1, R1, R1, R1, R31, R31, R31, R31, + R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, + T1, T4, T3, T2, ARG3, ARG1, RET1 }; +static const int rh[] = + { R0, R31, T4, T3, T2, T1, T4, T3, T2, T1, + R18, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, + T4, T3, T2, T1, ARG2, ARG0, RET0 }; + +void +deflab(int label) +{ + printf("\t.label\t" LABFMT "\n", label); +} + +static int regoff[MAXREGS]; +static TWORD ftype; + +/* + * Print out the prolog assembler. + * addto and regoff are already calculated. + */ +void +prtprolog(struct interpass_prolog *ipp, int addto) +{ + int i; + + /* if this functions calls nothing -- no frame is needed */ + if (p2calls || p2maxautooff > 4) { + printf("\tcopy\t%%r3,%%r1\n\tcopy\t%%sp,%%r3\n"); + if (addto < 0x2000) + printf("\tstw,ma\t%%r1,%d(%%sp)\n", addto); + else if (addto < 0x802000) + printf("\tstw,ma\t%%r1,8192(%%sp)\n" + "\taddil\t%d-8192,%%sp\n" + "\tcopy\t%%r1,%%sp\n", addto); + else + comperr("too much local allocation"); + if (p2calls) + printf("\tstw\t%%rp,-20(%%r3)\n"); + } + + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) { + if (i <= R31) + printf("\tstw\t%s,%d(%%r3)\n", + rnames[i], regoff[i]); + else if (i <= RETD0) + printf("\tstw\t%s,%d(%%r3)\n" + "\tstw\t%s,%d(%%r3)\n", + rnames[rl[i - RD0]], regoff[i] + 0, + rnames[rh[i - RD0]], regoff[i] + 4); + else if (i <= FR31) + printf("\tfstws\t%s,%d(%%r3)\n", + rnames[i], regoff[i]); + else + printf("\tfstds\t%s,%d(%%r3)\n", + rnames[i], regoff[i]); + } +} + +/* + * calculate stack size and offsets + */ +static int +offcalc(struct interpass_prolog *ipp) +{ + int i, addto, off; + + addto = 32; + if (p2calls) { + i = p2calls - 1; + /* round up to 4 args */ + if (i < 4) + i = 4; + addto += i * 4; + } + + for (off = 4, i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) { + regoff[i] = off; + off += szty(PERMTYPE(i)) * SZINT/SZCHAR; + } + addto += off + p2maxautooff; + return (addto + 63) & ~63; +} + +void +prologue(struct interpass_prolog *ipp) +{ + int addto; + + ftype = ipp->ipp_type; + + /* + * We here know what registers to save and how much to + * add to the stack. + */ + addto = offcalc(ipp); + printf("\t.proc\ncallinfo frame=%d, save_rp, save_sp\n\t.entry\n", + addto); + prtprolog(ipp, addto); +} + +void +eoftn(struct interpass_prolog *ipp) +{ + int i; + + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + /* return from function code */ + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) { + if (i <= R31) + printf("\tldw\t%d(%%r3),%s\n", + regoff[i], rnames[i]); + else if (i <= RETD0) + printf("\tldw\t%d(%%r3),%s\n" + "\tldw\t%d(%%r3),%s\n", + regoff[i] + 0, rnames[rl[i - RD0]], + regoff[i] + 4, rnames[rh[i - RD0]]); + else if (i <= FR31) + printf("\tfldws\t%d(%%r3),%s\n", + regoff[i], rnames[i]); + else + printf("\tfldds\t%d(%%r3),%s\n", + regoff[i], rnames[i]); + } + + if (p2calls || p2maxautooff > 4) { + if (p2calls) + printf("\tldw\t-20(%%r3),%%rp\n"); + printf("\tcopy\t%%r3,%%r1\n" + "\tldw\t0(%%r3),%%r3\n" + "\tbv\t%%r0(%%rp)\n" + "\tcopy\t%%r1,%%sp\n"); + } else + printf("\tbv\t%%r0(%%rp)\n\tnop\n"); + + printf("\t.exit\n\t.procend\n\t.size\t%s, .-%s\n", + ipp->ipp_name, ipp->ipp_name); +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "xor"; + break; + case EQ: + str = "="; + break; + case NE: + str = "<>"; + break; + case LE: + str = "<"; + break; + case LT: + str = "<="; + break; + case ULE: + str = "<<"; + break; + case ULT: + str = "<<="; + break; + case GE: + str = ">="; + break; + case GT: + str = ">"; + break; + case UGE: + str = ">>"; + break; + case UGT: + str = ">>="; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s%c", str, f); +} + +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(p) NODE *p; +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case FLOAT: + return(SZFLOAT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer", p->n_type); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +static int +argsiz(NODE *p) +{ + NODE *q; + TWORD t = p->n_type; + + if (t < LONGLONG || t == FLOAT || t > BTMASK) + return 4; + if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) + return 8; + if (t == LDOUBLE) + return 8; /* LDOUBLE is 16 */ + if ((t == STRTY || t == UNIONTY) && p->n_right->n_op == STARG) + return 4 + attr_find(p->n_right->n_ap, ATTR_P2STRUCT)->iarg(0); + /* perhaps it's down there somewhere -- let me take another look! */ + if ((t == STRTY || t == UNIONTY) && p->n_right->n_op == CALL) { + q = p->n_right->n_right->n_left->n_left->n_right; + if (q->n_op == STARG) + return 4 + attr_find(q->n_ap, ATTR_P2STRUCT)->iarg(0); + } + comperr("argsiz %p", p); + return 0; +} + +/* + * Emit code to compare two longlong numbers. + */ +static void +twollcomp(NODE *p) +{ + int o = p->n_op; + int s = getlab2(); + int e = p->n_label; + int cb1, cb2; + + if (o >= ULE) + o -= (ULE-LE); + switch (o) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 4, cb2 += 4; + if (cb1) { + p->n_op = cb1; + p->n_label = s; + expand(p, 0, "\tcomb,O\tUR,UL,LC\n\tnop\n"); + p->n_label = e; + p->n_op = o; + } + if (cb2) { + p->n_op = cb2; + expand(p, 0, "\tcomb,O\tUR,UL,LC\n\tnop\n"); + p->n_op = o; + } + expand(p, 0, "\tcomb,O\tAR,AL,LC\n\tnop\n"); + deflab(s); +} + +void +zzzcode(NODE *p, int c) +{ + int n; + + switch (c) { + + case 'C': /* after-call fixup */ + n = p->n_qual; /* args */ + break; + + case 'P': /* returning struct-call setup */ + n = p->n_qual; /* args */ + break; + + case 'D': /* Long long comparision */ + twollcomp(p); + break; + + case 'F': /* struct as an arg */ + + default: + comperr("zzzcode %c", c); + } +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o == NAME || o == REG || o == ICON || o == OREG || + (o == UMUL && shumul(p->n_left, SOREG))) + return(1); + return(0); +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + return 0; +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + if (isreg(p)) + return SRDIR; /* Direct match */ + + return SRREG; /* put it into a register */ +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + return 0; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +void +adrcon(CONSZ val) +{ + /* fix for L% and R% */ + printf(CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + CONSZ val = p->n_lval; + + switch (p->n_op) { + case ICON: + if (p->n_name[0] != '\0') { + fprintf(fp, "RR'%s-$global$", p->n_name); + if (val) + fprintf(fp, "+" CONFMT, val); + } else + fprintf(fp, CONFMT, val); + return; + + default: + comperr("illegal conput, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + + size /= SZCHAR; + switch (p->n_op) { + case REG: + printf("%s", rnames[rh[p->n_rval - RD0]]); + break; + + case OREG: + p->n_lval += size; + adrput(stdout, p); + p->n_lval -= size; + break; + + case ICON: + case NAME: + if (p->n_name[0] != '\0') { + printf("LR'%s-$global$", p->n_name); + if (p->n_lval != 0) + printf("+" CONFMT, p->n_lval); + } else + printf("L%%" CONFMT, p->n_lval >> 32); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *io, NODE *p) +{ + int r; + /* output an address, with offsets, from p */ + + if (p->n_op == FLD) + p = p->n_left; + + switch (p->n_op) { + + case ICON: + case NAME: + if (p->n_name[0] != '\0') { + fprintf(io, "RR'%s-$global$", p->n_name); + if (p->n_lval != 0) + fprintf(io, "+" CONFMT, p->n_lval); + } else + fprintf(io, "R%%" CONFMT, p->n_lval); + return; + + case OREG: + r = p->n_rval; + if (p->n_name[0] != '\0') { + fprintf(io, "RR'%s-$global$", p->n_name); + if (p->n_lval != 0) + fprintf(io, "+" CONFMT, p->n_lval); + } else + fprintf(io, "%d", (int)p->n_lval); + if (R2TEST(r)) { + fprintf(io, "%s(%s)", rnames[R2UPK1(r)], + rnames[R2UPK2(r)]); + } else + fprintf(io, "(%s)", rnames[p->n_rval]); + return; + case REG: + if (RD0 <= p->n_rval && p->n_rval <= RETD0) + fprintf(io, "%s", rnames[rl[p->n_rval - RD0]]); + else + fprintf(io, "%s", rnames[p->n_rval]); + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +/* not used */ +void +cbgen(int o, int lab) +{ +} + +int +countargs(NODE *p, int *n) +{ + int sz; + + if (p->n_op == CM) { + countargs(p->n_left, n); + countargs(p->n_right, n); + return *n; + } + + sz = argsiz(p) / 4; + if (*n % (sz > 4? 4 : sz)) + (*n)++; /* XXX */ + + return *n += sz; +} + +void +fixcalls(NODE *p, void *arg) +{ + int n, o; + + /* Prepare for struct return by allocating bounce space on stack */ + switch (o = p->n_op) { + case STCALL: + case USTCALL: + if (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) + + p2autooff > stkpos) + stkpos = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) + p2autooff; + /* FALLTHROGH */ + case CALL: + case UCALL: + n = 0; + n = 1 + countargs(p->n_right, &n); + if (n > p2calls) + p2calls = n; + break; + } +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + stkpos = p2autooff; + DLIST_FOREACH(ip, ipole, qelem) { + switch (ip->type) { + case IP_PROLOG: + p2calls = 0; + break; + + case IP_NODE: + walkf(ip->ip_node, fixcalls, 0); + break; + } + } + if (stkpos > p2autooff) + p2autooff = stkpos; + if (stkpos > p2maxautooff) + p2maxautooff = stkpos; + if (x2debug) + printip(ipole); +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE *p, void *arg) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2, 0); +} + +void +myoptim(struct interpass *ipole) +{ +} + +void +rmove(int s, int d, TWORD t) +{ + int sl, sh, dl, dh; + + switch (t) { + case LONGLONG: + case ULONGLONG: + sl = rl[s-RD0]; + sh = rh[s-RD0]; + dl = rl[d-RD0]; + dh = rh[d-RD0]; + +#define SW(x,y) { int i = x; x = y; y = i; } + if (sl == dh || sh == dl) { + /* Swap if moving to itself */ + SW(sl, sh); + SW(dl, dh); + } + if (sl != dl) + printf("\tcopy\t%s,%s\n", rnames[sl], rnames[dl]); + if (sh != dh) + printf("\tcopy\t%s,%s\n", rnames[sh], rnames[dh]); + break; + case FLOAT: + printf("\tfcpy,sgl\t%s,%s\n", rnames[s], rnames[d]); + break; + case DOUBLE: + case LDOUBLE: + printf("\tfcpy,dbl\t%s,%s\n", rnames[s], rnames[d]); + break; + default: + printf("\tcopy\t%s,%s\n", rnames[s], rnames[d]); + } +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int c, int *r) +{ + int num; + + switch (c) { + case CLASSA: + num = 2 * r[CLASSB]; + num += r[CLASSA]; + return num < 28; + case CLASSB: + num = r[CLASSA]; + num += r[CLASSB] * 2; + return num < 28; + case CLASSC: + num = (r[CLASSD] > 8? 8 : r[CLASSD]) * 2; + num += r[CLASSC]; + return num < 28; + case CLASSD: + num = (r[CLASSC] + 1) / 2; + num += r[CLASSD]; + return num < 28; + } + return 0; /* XXX gcc */ +} + +char * rnames[MAXREGS] = { + "%r0", "%r1", "%rp", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9", + "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%r16", "%r17", "%r18", + "%t4", "%t3", "%t2", "%t1", "%arg3", "%arg2", "%arg1", "%arg0", "%dp", + "%ret0", "%ret1", "%sp", "%r31", + "%rd0", "%rd1", "%rd2", "%rd3", "%rd4", "%rd5", "%rd6", "%rd7", + "%rd8", "%rd9", "%rd10", "%rd11", "%rd12", "%rd13", "%rd14", "%rd15", + "%rd16", "%rd17", "%rd18", "%rd19", "%rd20", "%rd21", "%rd22", "%rd23", + "%rd24", "%td4", "%td3", "%td2", "%td1", "%ad1", "%ad0", "%retd0", + "%fr0", "%fr4", "%fr5", "%fr6", "%fr7", "%fr8", "%fr9", "%fr10", + "%fr11", "%fr12", "%fr13", "%fr14", "%fr15", "%fr16", "%fr17", "%fr18", + "%fr19", "%fr20", "%fr21", "%fr22", "%fr23", "%fr24", "%fr25", "%fr26", + "%fr27", "%fr28", "%fr29", "%fr30", "%fr31", + "%fr0l", "%fr0r", "%fr4l", "%fr4r", "%fr5l", "%fr5r", "%fr6l", "%fr6r", + "%fr7l", "%fr7r", "%fr8l", "%fr8r", "%fr9l", "%fr9r", + "%fr10l", "%fr10r", "%fr11l", "%fr11r", "%fr12l", "%fr12r", + "%fr13l", "%fr13r", "%fr14l", "%fr14r", "%fr15l", "%fr15r", + "%fr16l", "%fr16r", "%fr17l", "%fr17r", "%fr18l", "%fr18r", +#ifdef __hppa64__ + "%fr19l", "%fr19r", + "%fr20l", "%fr20r", "%fr21l", "%fr21r", "%fr22l", "%fr22r", + "%fr23l", "%fr23r", "%fr24l", "%fr24r", "%fr25l", "%fr25r", + "%fr26l", "%fr26r", "%fr27l", "%fr27r", "%fr28l", "%fr28r", + "%fr29l", "%fr29r", "%fr30l", "%fr30r", "%fr31l", "%fr31r", +#endif +}; + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + switch (t) { + case LONGLONG: + case ULONGLONG: + return CLASSB; + case FLOAT: + return CLASSC; + case DOUBLE: + case LDOUBLE: + return CLASSD; + default: + return CLASSA; + } +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 64; + + p->n_qual = size; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + size += argsiz(p->n_right); + size += argsiz(p); + op->n_qual = size; /* XXX */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + int o = p->n_op; + + switch (shape) { + case SFUNCALL: + if (o == STCALL || o == USTCALL) + return SRREG; + break; + case SPIMM: + if (o != ICON || p->n_name[0] || + p->n_lval < -31 || p->n_lval >= 32) + break; + return SRDIR; + case SPICON: + if (o != ICON || p->n_name[0] || + p->n_lval < -1024 || p->n_lval >= 1024) + break; + return SRDIR; + case SPCNHW: + if (o != ICON || p->n_name[0] || (p->n_lval & 0xffffffffLL)) + break; + return SRDIR; + case SPCNLW: + if (o != ICON || p->n_name[0] || (p->n_lval & ~0xffffffffLL)) + break; + return SRDIR; + case SPCNHI: + if (o != ICON || p->n_name[0] || (p->n_lval & ~0xfffff800LL)) + break; + return SRDIR; + case SPCON: + if (o != ICON || p->n_name[0] || + p->n_lval < -8192 || p->n_lval >= 8192) + break; + return SRDIR; + case SPNAME: + if (o != ICON || !p->n_name[0]) + break; + return SRDIR; + } + return SRNOPE; +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ +} +/* + * Do something target-dependent for xasm arguments. + * Supposed to find target-specific constraints and rewrite them. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + return 0; +} diff --git a/lang/pcc/pcc/arch/hppa/macdefs.h b/lang/pcc/pcc/arch/hppa/macdefs.h new file mode 100644 index 000000000..cab29cab8 --- /dev/null +++ b/lang/pcc/pcc/arch/hppa/macdefs.h @@ -0,0 +1,472 @@ +/* $Id: macdefs.h,v 1.22 2016/03/05 15:53:04 ragge Exp $ */ + +/* + * Copyright (c) 2007 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) (lastcon = (lastcon<<8)|((val<<24)>>24)) + +#define ARGINIT (32*8) /* bits below fp where args start */ +#define AUTOINIT (4*8) /* bits above fp where locals start */ + +/* + * storage sizes + */ +#define SZCHAR 8 +#define SZBOOL 8 +#define SZINT 32 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 64 /* or later 128 */ +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 64 +#define SZPOINT(t) 32 + +/* + * alignment requirements + */ +#define ALCHAR 8 +#define ALBOOL 8 +#define ALINT 32 +#define ALFLOAT 32 +#define ALDOUBLE 64 +#define ALLDOUBLE 64 /* 128 later */ +#define ALLONG 32 +#define ALLONGLONG 32 +#define ALSHORT 16 +#define ALPOINT 32 +#define ALSTRUCT 32 +#define ALSTACK 64 + +/* + * type value limits + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT (-0x7fffffff-1) +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffff +#define MIN_LONG MIN_INT +#define MAX_LONG MAX_INT +#define MAX_ULONG MAX_UNSIGNED +#define MIN_LONGLONG (-0x7fffffffffffffffLL-1) +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +#undef CHAR_UNSIGNED +#define BOOL_TYPE CHAR + +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#define LABFMT ".L%d" /* format for printing labels */ +#define STABLBL ".LL%d" /* format for stab (debugging) labels */ + +#undef BACKAUTO /* stack grows upwards */ +#undef BACKTEMP /* stack grows upwards */ + +#define FIELDOPS /* have bit field ops */ +#define TARGET_ENDIAN TARGET_BE +#define TARGET_FLT_EVAL_METHOD 0 /* all as their type */ + +#define BYTEOFF(x) ((x)&03) +#define wdal(k) (BYTEOFF(k)==0) + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) + +#define szty(t) (((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : \ + (t) == LDOUBLE ? 2 : 1) + +#define R0 0 +#define R1 1 +#define RP 2 +#define FP 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 +#define R16 16 +#define R17 17 +#define R18 18 +#define T4 19 +#define T3 20 +#define T2 21 +#define T1 22 +#define ARG3 23 +#define ARG2 24 +#define ARG1 25 +#define ARG0 26 +#define DP 27 +#define RET0 28 +#define RET1 29 +#define SP 30 +#define R31 31 + +/* double regs overlay */ +#define RD0 32 /* r0:r0 */ +#define RD1 33 /* r1:r31 */ +#define RD2 34 /* r1:t4 */ +#define RD3 35 /* r1:t3 */ +#define RD4 36 /* r1:t2 */ +#define RD5 37 /* r1:t1 */ +#define RD6 38 /* r31:t4 */ +#define RD7 39 /* r31:t3 */ +#define RD8 40 /* r31:t2 */ +#define RD9 41 /* r31:t1 */ +#define RD10 42 /* r4:r18 */ +#define RD11 43 /* r5:r4 */ +#define RD12 44 /* r6:r5 */ +#define RD13 45 /* r7:r6 */ +#define RD14 46 /* r8:r7 */ +#define RD15 47 /* r9:r8 */ +#define RD16 48 /* r10:r9 */ +#define RD17 49 /* r11:r10 */ +#define RD18 50 /* r12:r11 */ +#define RD19 51 /* r13:r12 */ +#define RD20 52 /* r14:r13 */ +#define RD21 53 /* r15:r14 */ +#define RD22 54 /* r16:r15 */ +#define RD23 55 /* r17:r16 */ +#define RD24 56 /* r18:r17 */ +#define TD4 57 /* t1:t4 */ +#define TD3 58 /* t4:t3 */ +#define TD2 59 /* t3:t2 */ +#define TD1 60 /* t2:t1 */ +#define AD2 61 /* arg3:arg2 */ +#define AD1 62 /* arg1:arg0 */ +#define RETD0 63 /* ret1:ret0 */ + +/* FPU regs */ +#define FR0 64 +#define FR4 65 +#define FR5 66 +#define FR6 67 +#define FR7 68 +#define FR8 69 +#define FR9 70 +#define FR10 71 +#define FR11 72 +#define FR12 73 +#define FR13 74 +#define FR14 75 +#define FR15 76 +#define FR16 77 +#define FR17 78 +#define FR18 79 +#define FR19 80 +#define FR20 81 +#define FR21 82 +#define FR22 83 +#define FR23 84 +#define FR24 85 +#define FR25 86 +#define FR26 87 +#define FR27 88 +#define FR28 89 +#define FR29 90 +#define FR30 91 +#define FR31 92 + +#define FR0L 93 +#define FR0R 94 +#define FR4L 95 +#define FR4R 96 +#define FR5L 97 +#define FR5R 98 +#define FR6L 99 +#define FR6R 100 +#define FR7L 101 +#define FR7R 102 +#define FR8L 103 +#define FR8R 104 +#define FR9L 105 +#define FR9R 106 +#define FR10L 107 +#define FR10R 108 +#define FR11L 109 +#define FR11R 110 +#define FR12L 111 +#define FR12R 112 +#define FR13L 113 +#define FR13R 114 +#define FR14L 115 +#define FR14R 116 +#define FR15L 117 +#define FR15R 118 +#define FR16L 119 +#define FR16R 120 +#define FR17L 121 +#define FR17R 122 +#define FR18L 123 +#define FR18R 124 +#ifdef __hppa64__ +#define FR19L 125 +#define FR19R 126 +#define FR20L 127 +#define FR20R 128 +#define FR21L 129 +#define FR21R 130 +#define FR22L 131 +#define FR22R 132 +#define FR23L 133 +#define FR23R 134 +#define FR24L 135 +#define FR24R 136 +#define FR25L 137 +#define FR25R 138 +#define FR26L 139 +#define FR26R 140 +#define FR27L 141 +#define FR27R 142 +#define FR28L 143 +#define FR28R 144 +#define FR29L 145 +#define FR29R 146 +#define FR30L 147 +#define FR30R 148 +#define FR31L 149 +#define FR31R 150 + +#define MAXREGS 151 +#else +#define MAXREGS 125 +#endif + +#define RSTATUS \ + 0, SAREG|TEMPREG, 0, 0, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + 0, SAREG|TEMPREG, SAREG|TEMPREG, 0, SAREG|TEMPREG, \ + /* double overlays */ \ + 0, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + /* double-precision floats */ \ + 0, \ + SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, \ + SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, \ + SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, \ + SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, \ + SDREG|PERMREG, SDREG|PERMREG, \ + SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, \ + SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, \ + SDREG|TEMPREG, SDREG|TEMPREG, \ + /* single-precision floats */ \ + 0, 0, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, +#ifdef __hppa64__ + SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, +#endif + +#define ROVERLAP \ + { -1 }, \ + { RD1, RD2, RD3, RD4, RD5, -1 },\ + { -1 }, { -1 }, \ + { RD10, RD11, -1 }, \ + { RD11, RD12, -1 }, \ + { RD12, RD13, -1 }, \ + { RD13, RD14, -1 }, \ + { RD14, RD15, -1 }, \ + { RD15, RD16, -1 }, \ + { RD16, RD17, -1 }, \ + { RD17, RD18, -1 }, \ + { RD18, RD19, -1 }, \ + { RD19, RD20, -1 }, \ + { RD20, RD21, -1 }, \ + { RD21, RD22, -1 }, \ + { RD22, RD23, -1 }, \ + { RD23, RD24, -1 }, \ + { RD24, RD10, -1 }, \ + { TD1, TD4, -1 }, \ + { TD3, TD2, -1 }, \ + { TD1, TD2, -1 }, \ + { TD1, TD4, -1 }, \ + { AD2, -1 }, { AD2, -1 }, \ + { AD1, -1 }, { AD1, -1 }, \ + { -1 }, \ + { RETD0, -1 }, { RETD0, -1 }, \ + { -1 }, \ + { RD1, RD5, RD6, RD7, RD8, -1 },\ + { -1 }, \ + { R1, R31, -1 }, \ + { R1, T4, -1 }, \ + { R1, T3, -1 }, \ + { R1, T2, -1 }, \ + { R1, T1, -1 }, \ + { R31, T4, -1 }, \ + { R31, T3, -1 }, \ + { R31, T2, -1 }, \ + { R31, T1, -1 }, \ + { R4, R18, -1 }, \ + { R5, R4, -1 }, \ + { R6, R5, -1 }, \ + { R7, R6, -1 }, \ + { R8, R7, -1 }, \ + { R9, R8, -1 }, \ + { R10, R9, -1 }, \ + { R11, R10, -1 }, \ + { R12, R11, -1 }, \ + { R13, R12, -1 }, \ + { R14, R15, -1 }, \ + { R15, R14, -1 }, \ + { R16, R15, -1 }, \ + { R17, R16, -1 }, \ + { R18, R17, -1 }, \ + { T1, T4, -1 }, \ + { T4, T3, -1 }, \ + { T3, T2, -1 }, \ + { T2, T1, -1 }, \ + { ARG3, ARG2, -1 }, \ + { ARG1, ARG0, -1 }, \ + { RET1, RET0, -1 }, \ + { -1 }, \ + { FR4L, FR4R, -1 }, \ + { FR5L, FR5R, -1 }, \ + { FR6L, FR6R, -1 }, \ + { FR7L, FR7R, -1 }, \ + { FR8L, FR8R, -1 }, \ + { FR9L, FR9R, -1 }, \ + { FR10L, FR10R, -1 }, \ + { FR11L, FR11R, -1 }, \ + { FR12L, FR12R, -1 }, \ + { FR13L, FR13R, -1 }, \ + { FR14L, FR14R, -1 }, \ + { FR15L, FR15R, -1 }, \ + { FR16L, FR16R, -1 }, \ + { FR17L, FR17R, -1 }, \ + { FR18L, FR18R, -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, { -1 }, \ + { FR4, -1 }, { FR4, -1 }, \ + { FR5, -1 }, { FR5, -1 }, \ + { FR6, -1 }, { FR6, -1 }, \ + { FR7, -1 }, { FR7, -1 }, \ + { FR8, -1 }, { FR8, -1 }, \ + { FR9, -1 }, { FR9, -1 }, \ + { FR10, -1 }, { FR10, -1 }, \ + { FR11, -1 }, { FR11, -1 }, \ + { FR12, -1 }, { FR12, -1 }, \ + { FR13, -1 }, { FR13, -1 }, \ + { FR14, -1 }, { FR14, -1 }, \ + { FR15, -1 }, { FR15, -1 }, \ + { FR16, -1 }, { FR16, -1 }, \ + { FR17, -1 }, { FR17, -1 }, \ + { FR18, -1 }, { FR18, -1 }, +#ifdef __hppa64__ + { FR19, -1 }, { FR19, -1 }, \ + { FR20, -1 }, { FR20, -1 }, \ + { FR21, -1 }, { FR21, -1 }, \ + { FR22, -1 }, { FR22, -1 }, \ + { FR23, -1 }, { FR23, -1 }, \ + { FR24, -1 }, { FR24, -1 }, \ + { FR25, -1 }, { FR25, -1 }, \ + { FR26, -1 }, { FR26, -1 }, \ + { FR27, -1 }, { FR27, -1 }, \ + { FR28, -1 }, { FR28, -1 }, \ + { FR29, -1 }, { FR29, -1 }, \ + { FR30, -1 }, { FR30, -1 }, \ + { FR31, -1 }, { FR31, -1 }, +#endif + +#define PCLASS(p) \ + (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SBREG : \ + (p->n_type == FLOAT ? SCREG : \ + (p->n_type == DOUBLE || p->n_type == LDOUBLE ? SDREG : SAREG))) + +#define NUMCLASS 4 /* highest number of reg classes used */ + +int COLORMAP(int c, int *r); +#define PERMTYPE(x) ((x) < 32? INT : ((x) < 64? LONGLONG : ((x) < 93? LDOUBLE : FLOAT))) +#define GCLASS(x) ((x) < 32? CLASSA : ((x) < 64? CLASSB : ((x) < 93? CLASSD : CLASSC))) +#define DECRA(x,y) (((x) >> (y*8)) & 255) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 8) /* A1 */ +#define ENCRA2(x) ((x) << 16) /* A2 */ +#define ENCRA(x,y) ((x) << (8+y*8)) /* encode regs in int */ +#define RETREG(x) (x == LONGLONG || x == ULONGLONG ? RETD0 : \ + x == FLOAT? FR4L : \ + x == DOUBLE || x == LDOUBLE ? FR4 : RET0) + +#define FPREG FP /* frame pointer */ +#define STKREG SP /* stack pointer */ + +#define MYREADER(p) myreader(p) +#define MYCANON(p) mycanon(p) +#define MYOPTIM + +#define SFUNCALL (MAXSPECIAL+1) /* struct assign after function call */ +#define SPCNHI (MAXSPECIAL+2) /* high 21bits constant */ +#define SPCON (MAXSPECIAL+3) /* smaller constant */ +#define SPICON (MAXSPECIAL+4) /* even smaller constant */ +#define SPCNHW (MAXSPECIAL+5) /* LL const w/ 0 in low word */ +#define SPCNLW (MAXSPECIAL+6) /* LL const w/ 0 in high word */ +#define SPIMM (MAXSPECIAL+7) /* immidiate const for depi/comib */ +#define SPNAME (MAXSPECIAL+8) /* ext symbol reference load/store */ diff --git a/lang/pcc/pcc/arch/hppa/order.c b/lang/pcc/pcc/arch/hppa/order.c new file mode 100644 index 000000000..af8ed0f0c --- /dev/null +++ b/lang/pcc/pcc/arch/hppa/order.c @@ -0,0 +1,216 @@ +/* $Id: order.c,v 1.10 2011/06/05 08:54:42 plunky Exp $ */ + +/* + * Copyright (c) 2007 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +#include + +int canaddr(NODE *); + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + return(0); /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + * Be careful about register classes, this is a place where classes change. + */ +void +offstar(NODE *p, int shape) +{ + NODE *r; + + if (x2debug) + printf("offstar(%p)\n", p); + + if (isreg(p)) + return; /* Is already OREG */ + + r = p->n_right; + if (p->n_op == PLUS || p->n_op == MINUS) { + if (r->n_op == ICON) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + } + (void)geninsn(p, INAREG); +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + */ +void +myormake(NODE *q) +{ + NODE *p, *r; + + if (x2debug) + printf("myormake(%p)\n", q); + + p = q->n_left; + if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && + r->n_right->n_op == ICON && r->n_right->n_lval == 2 && + p->n_left->n_op == REG && r->n_left->n_op == REG) { + q->n_op = OREG; + q->n_lval = 0; + q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0); + tfree(p); + } +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Turns currently anything into OREG on hppa */ + if (shape & SOREG) + return SOREG; + return SRNOPE; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + if (x2debug) + printf("setbin(%p)\n", p); + + return 0; +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p,%s)\n", p, prcook(cookie)); + + if (p->n_left->n_op == FLD && !isreg(p->n_left->n_left)) { + NODE *l, *r; + int reg; + + geninsn(p->n_left->n_left, INAREG); + + reg = DECRA(p->n_left->n_left->n_reg, 0); + l = tcopy(p->n_left->n_left); + p->n_left->n_left->n_op = REG; + p->n_left->n_left->n_rval = reg; + p->n_left->n_left->n_lval = 0; + r = tcopy(p->n_left->n_left); + + geninsn(p->n_left, INAREG); + l = mkbinode(ASSIGN, l, r, l->n_type); + geninsn(l, INAREG); + return (1); + } + + return (0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + if (x2debug) + printf("setuni(%p,%s)\n", p, prcook(cookie)); + + return 0; +} + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; /* nothing differs on hppa */ +} + +/* + * Set registers "live" at function calls (like arguments in registers). + * This is for liveness analysis of registers. + */ +int * +livecall(NODE *p) +{ + static int r[5], *s = &r[4]; + + *s = -1; + if (p->n_op == UCALL || p->n_op == UFORTCALL || p->n_op == USTCALL || + p->n_op == FORTCALL) + return s; + + for (p = p->n_right; p->n_op == CM; p = p->n_left) + if (p->n_right->n_op == ASSIGN && + p->n_right->n_left->n_op == REG) + *--s = p->n_right->n_left->n_rval; + + if (p->n_op == ASSIGN && + p->n_left->n_op == REG) + *--s = p->n_left->n_rval; + + return s; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/hppa/table.c b/lang/pcc/pcc/arch/hppa/table.c new file mode 100644 index 000000000..4dc3947dc --- /dev/null +++ b/lang/pcc/pcc/arch/hppa/table.c @@ -0,0 +1,1015 @@ +/* $Id: table.c,v 1.16 2012/09/18 10:57:10 mickey Exp $ */ +/* $OpenBSD: table.c,v 1.2 2007/12/19 20:19:54 otto Exp $ */ + +/* + * Copyright (c) 2007 Michael Shalayeff + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +#define TLL TLONGLONG|TULONGLONG +#define ANYSIGNED TINT|TLONG|TSHORT|TCHAR +#define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR +#define ANYFIXED ANYSIGNED|ANYUSIGNED +#define TUWORD TUNSIGNED|TULONG +#define TSWORD TINT|TLONG +#define TWORD TUWORD|TSWORD +#define THWORD TUSHORT|TSHORT +#define TBYTE TUCHAR|TCHAR + +#define SHINT SAREG /* char, short and int */ +#define ININT INAREG +#define SHLL SBREG /* shape for long long */ +#define INLL INBREG +#define SHFL SCREG /* shape for float */ +#define INFL INCREG +#define SHDBL SDREG /* shape for double */ +#define INDBL INDREG + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are usually not necessary */ +{ PCONV, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + "", }, +/* + * A bunch conversions of integral<->integral types + * There are lots of them, first in table conversions to itself + * and then conversions from each type to the others. + */ + +/* itself to itself, including pointers */ + +/* convert int,short,char <-> int,short,char. */ +{ SCONV, ININT, + SHINT, TBYTE, + SHINT, TBYTE, + 0, RLEFT, + "", }, + +{ SCONV, ININT, + SHINT, THWORD, + SHINT, THWORD, + 0, RLEFT, + "", }, + +{ SCONV, ININT, + SHINT, TWORD, + SHINT, TWORD, + 0, RLEFT, + "", }, + +/* convert pointers to int. */ +{ SCONV, ININT, + SHINT, TWORD|TPOINT, + SANY, TWORD, + 0, RLEFT, + "", }, + +/* convert (u)longlong to (u)longlong. */ +{ SCONV, INLL, + SHLL, TLL, + SHLL, TLL, + 0, RLEFT, + "", }, + +/* convert pointers to pointers. */ +{ SCONV, ININT, + SHINT, TPOINT, + SANY, TPOINT, + 0, RLEFT, + "", }, + +/* convert double <-> ldouble. nothing to do here (or support quads later) */ +{ SCONV, INDBL, + SHDBL, TDOUBLE|TLDOUBLE, + SHDBL, TDOUBLE|TLDOUBLE, + 0, RLEFT, + "", }, + +/* convert float -> double */ +{ SCONV, INFL, + SHFL, TFLOAT, + SHDBL, TDOUBLE|TLDOUBLE, + 0, 0, + "\tfcnvff,sgl,dbl AL,AR\n", }, + +/* convert double -> float */ +{ SCONV, INDBL, + SHDBL, TDOUBLE|TLDOUBLE, + SHFL, TFLOAT, + 0, 0, + "\tfcnvff,dbl,sgl\tAL,AR\n", }, + +/* convert int,short,char to (u)long long */ +{ SCONV, INLL, + SHINT, ANYSIGNED, + SANY, TLL, + NBREG, RESC1, + "\tcopy\tAL,A1\n" + "\textrs\tAL,0,1,U1\n", }, + +/* convert unsigned int,short,char to (u)long long */ +{ SCONV, INLL, + SHINT, TWORD, + SANY, TLL, + NBREG, RESC1, + "\tcopy\tAL,A1\n" + "\tcopy\t%r0,U1\n", }, + +/* convert int,short,char (in memory) to float */ +{ SCONV, INFL, + SOREG, ANYSIGNED, + SHFL, TFLOAT, + NCREG, RESC1, + "\tfldws\tAL,A1\n" + "\tfcnvxf,sgl,sgl\tA1,A1\n", }, + +/* convert int,short,char (in memory) to double */ +{ SCONV, INDBL, + SOREG, TSWORD, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG, RESC1, + "\tfldws\tAL,A1\n" + "\tfcnvxf,sgl,dbl\tA1,A1\n", }, + +/* convert (u)long (in memory) to double */ +{ SCONV, INDBL, + SOREG, TLL, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG, RESC1, + "\tfldds\tAL,A1\n" + "\tfcnvxf,dbl,dbl\tA1,A1\n", }, + +/* convert int,short,char (in register) to float */ +{ SCONV, INFL, + SHINT, TSWORD, + SHFL, TFLOAT, + NCREG, RESC1, + "\tstw,ma\tAL,4(%sp)\n" + "\tfldws,ma\t-4(%sp),A1\n" + "\tfcnvxf,sgl,sgl\tA1,A1\n", }, + +/* convert int,short,char (in register) to double */ +{ SCONV, INDBL, + SHINT, TSWORD, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG, RESC1, + "\tstw,ma\tAL,4(%sp)\n" + "\tfldws,mb\t-4(%sp),AR\n" + "\tfcnvxf,sgl,dbl\tA1,A1\n", }, + +/* convert (u)long (in register) to double */ +{ SCONV, INDBL, + SHLL, TLL, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG, RESC1, + "\tldo\t8(%sp),%sp\n" + "\tstw\tAL,-8(%sp)\n" + "\tstw\tUL,-4(%sp)\n" + "\tfldds,mb\t-8(%sp),A1\n" + "\tfcnvxf,dbl,dbl\tA1,A1\n", }, + +/* convert char to (unsigned) short/int. */ +{ SCONV, ININT, + SAREG, TCHAR, + SAREG, THWORD|TWORD, + NASL|NAREG, RESC1, + "\textrs\tAL,31,8,A1\n", }, + +/* convert unsigned char to (unsigned) short/int. */ +{ SCONV, ININT, + SAREG, TUCHAR, + SAREG, THWORD|TWORD, + NASL|NAREG, RESC1, + "\textru\tAL,31,8,A1\n", }, + +/* convert char to (unsigned) long long. */ +{ SCONV, INLL, + SAREG, TCHAR, + SBREG, TLL, + NBSL|NBREG, RESC1, + "\textrs\tAL,31,8,A1\n\textrs\tA1,0,1,U1", }, + +/* convert unsigned char to (unsigned) long long. */ +{ SCONV, INLL, + SAREG, TUCHAR, + SBREG, TLL, + NBSL|NBREG, RESC1, + "\textru\tAL,31,8,A1\n\tcopy\t%r0,U1", }, + +/* convert short to (unsigned) int. */ +{ SCONV, ININT, + SAREG, TSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + "\textrs\tAL,31,16,A1\n", }, + +/* convert unsigned short to (unsigned) int. */ +{ SCONV, ININT, + SAREG, TUSHORT, + SAREG, THWORD, + NASL|NAREG, RESC1, + "\textru\tAL,31,16,A1\n", }, + +/* convert short to (unsigned) long long. */ +{ SCONV, INLL, + SAREG, TSHORT, + SBREG, TLL, + NBSL|NBREG, RESC1, + "\textrs\tAL,31,16,A1\n\textrs\tA1,0,1,U1", }, + +/* convert unsigned short to (unsigned) long long. */ +{ SCONV, INLL, + SAREG, TUSHORT, + SBREG, TLL, + NBSL|NBREG, RESC1, + "\textru\tAL,31,16,A1\n\tcopy\t%r0,U1", }, + +/* convert int,short,char (in memory) to int,short,char */ +{ SCONV, ININT, + SOREG, TBYTE, + SHINT, TBYTE|TPOINT, + NAREG|NASL, RESC1, + "\tldb\tAL,A1\n", }, + +{ SCONV, ININT, + SOREG, THWORD, + SHINT, THWORD|TPOINT, + NAREG|NASL, RESC1, + "\tldh\tAL,A1\n", }, + +{ SCONV, ININT, + SOREG, TWORD, + SHINT, TWORD|TPOINT, + NAREG|NASL, RESC1, + "\tldw\tAL,A1\n", }, + +/* convert (u)long long (in register) to int,short,char */ +{ SCONV, ININT, + SHLL, TLL, + SHINT, ANYFIXED, + NAREG|NASL, RESC1, + "\tcopy\tAL,A1\n", }, + +/* convert (u)long (in memory) to int,short,char */ +{ SCONV, ININT, + SOREG, TLL, + SHINT, ANYFIXED, + NAREG|NASL, RESC1, + "\tldw\tAL,A1\n", }, + +/* convert float (in register) to (u)int */ +{ SCONV, ININT, + SHFL, TFLOAT, + SHINT, TWORD, + NAREG, RESC1, + "\tfcnvfxt,sgl,sgl\tAL,AL\n" + "\tfstws,ma\tAL,4(%sp)\n" + "\tldw,mb\t-4(%sp),A1\n", }, + +/* convert double (in register) to (u)int */ +{ SCONV, ININT, + SHDBL, TDOUBLE|TLDOUBLE, + SHINT, TWORD, + NCREG|NCSL|NAREG, RESC1, + "\tfcnvfxt,dbl,sgl\tAL,A1\n" + "\tfstws,ma\tA1,4(%sp)\n" + "\tldw,mb\t-4(%sp),A2\n", }, + +/* convert float (in register) to (u)long */ +{ SCONV, INLL, + SHFL, TFLOAT, + SHLL, TLL, + NDREG|NDSL|NBREG, RESC1, + "\tfcnvfxt,sgl,dbl\tAL,A1\n" + "\tfstds,ma\tA1,8(%sp)\n" + "\tldw\t-8(%sp),A2\n" + "\tldw\t-4(%sp),U2\n" + "\tldo\t-8(%sp),%sp)\n", }, + +/* convert double (in register) to (u)long */ +{ SCONV, INLL, + SHDBL, TDOUBLE|TLDOUBLE, + SHLL, TLL, + NBREG, RESC1, + "\tfcnvfxt,dbl,dbl\tAL,AL\n" + "\tfstds,ma\tAL,8(%sp)\n" + "\tldw\t-8(%sp),A1\n" + "\tldw\t-4(%sp),U1\n" + "\tldo\t-8(%sp),%sp)\n", }, + +/* + * Subroutine calls. + */ + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + "ZP\tblr\t%r0, %rp\n" + "\tbv,n\t%r0(AL)\n" + "\tnop\nZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + "ZP\tblr\t%r0, %rp\n" + "\tbv,n\t%r0(AL)\n" + "\tnop\nZC", }, + +{ CALL, ININT, + SAREG, TANY, + SHINT, ANYFIXED|TPOINT, + NAREG|NASL, RESC1, + "ZP\tblr\t%r0, %rp\n" + "\tbv,n\t%r0(AL)\n" + "\tnop\nZC", }, + +{ UCALL, ININT, + SAREG, TANY, + SHINT, ANYFIXED|TPOINT, + NAREG|NASL, RESC1, + "ZP\tblr\t%r0, %rp\n" + "\tbv,n\t%r0(AL)\n" + "\tnop\nZC", }, + +{ CALL, INLL, + SAREG, TANY, + SHLL, TLL, + NBREG|NBSL, RESC1, + "ZP\tblr\t%r0, %rp\n" + "\tbv,n\t%r0(AL)\n" + "\tnop\nZC", }, + +{ UCALL, INLL, + SAREG, TANY, + SHLL, TLL, + NBREG|NBSL, RESC1, + "ZP\tblr\t%r0, %rp\n" + "\tbv,n\t%r0(AL)\n" + "\tnop\nZC", }, + +{ CALL, INFL, + SAREG, TANY, + SHFL, TFLOAT, + NCREG|NCSL, RESC1, + "ZP\tblr\t%r0, %rp\n" + "\tbv,n\t%r0(AL)\n" + "\tnop\nZC", }, + +{ UCALL, INFL, + SAREG, TANY, + SHFL, TFLOAT, + NCREG|NCSL, RESC1, + "ZP\tblr\t%r0, %rp\n" + "\tbv,n\t%r0(AL)\n" + "\tnop\nZC", }, + +{ CALL, INDBL, + SAREG, TANY, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG|NDSL, RESC1, + "ZP\tblr\t%r0, %rp\n" + "\tbv,n\t%r0(AL)\n" + "\tnop\nZC", }, + +{ UCALL, INDBL, + SAREG, TANY, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG|NDSL, RESC1, + "ZP\tblr\t%r0, %rp\n" + "\tbv,n\t%r0(AL)\n" + "\tnop\nZC", }, + +/* + * The next rules handle all binop-style operators. + */ +/* TODO fix char/short overflows */ + +{ PLUS, INLL, + SHLL, TLL, + SPICON, TANY, + NBREG|NBSL, RESC1, + "\taddi\tAL,AR,A1\n" + "\taddc\tUL,%r0,U1\n", }, + +{ PLUS, INLL, + SHLL, TLL, + SHLL, TLL, + NBREG|NBSL|NBSR, RESC1, + "\tadd\tAL,AR,A1\n" + "\taddc\tUL,UR,U1\n", }, + +{ PLUS, INFL, + SHFL, TFLOAT, + SHFL, TFLOAT, + NCREG|NCSL|NCSR, RESC1, + "\tfadd,sgl\tAL,AR,A1\n", }, + +{ PLUS, INDBL, + SHDBL, TDOUBLE|TLDOUBLE, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG|NDSL|NDSR, RESC1, + "\tfadd,dbl\tAL,AR,A1\n", }, + +{ PLUS, ININT, + SHINT, ANYFIXED|TPOINT, + SONE, TANY, + NAREG|NASL, RESC1, + "\tldo\t1(AL),A1\n", }, + +{ PLUS, ININT, + SHINT, ANYFIXED|TPOINT, + SPCON, TANY, + NAREG|NASL, RESC1, + "\tldo\tCR(AL),A1\n", }, + +{ MINUS, INLL, + SHLL, TLL, + SPICON, TANY, + NBREG|NBSL|NBSR, RESC1, + "\tsubi\tAL,AR,A1\n" + "\tsubb\tUL,%r0,U1\n", }, + +{ PLUS, ININT, + SHINT, TANY|TPOINT, + SPNAME, TANY, + NAREG|NASL, RESC1, + "\tldo\tAR(AL),A1\n", }, + +{ MINUS, INLL, + SHLL, TLL, + SHLL, TLL, + NBREG|NBSL|NBSR, RESC1, + "\tsub\tAL,AR,A1\n" + "\tsubb\tUL,UR,U1\n", }, + +{ MINUS, INFL, + SHFL, TFLOAT, + SHFL, TFLOAT, + NCREG|NCSL|NCSR, RESC1, + "\tfsub,sgl\tAL,AR,A1\n", }, + +{ MINUS, INDBL, + SHDBL, TDOUBLE|TLDOUBLE, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG|NDSL|NDSR, RESC1, + "\tfsub,dbl\tAL,AR,A1\n", }, + +{ MINUS, ININT, + SHINT, ANYFIXED|TPOINT, + SONE, TANY, + NAREG|NASL, RESC1, + "\tldo\t-1(AL),A1\n", }, + +{ MINUS, ININT, + SHINT, ANYFIXED|TPOINT, + SPCON, TANY, + NAREG|NASL, RESC1, + "\tldo\t-CR(AL),A1\n", }, + +/* Simple reg->reg ops */ +{ OPSIMP, ININT, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + "\tO\tAL,AR,A1\n", }, + +{ OPSIMP, INLL, + SHLL, TLL, + SHLL, TLL, + NBREG|NBSL|NBSR, RESC1, + "\tO\tAL,AR,A1\n" + "\tO\tUL,UR,U1\n", }, + +/* + * The next rules handle all shift operators. + */ +{ LS, ININT, + SHINT, ANYFIXED, + SCON, ANYFIXED, + NAREG|NASL, RESC1, + "\tzdep\tAL,31-AR,32-AR,A1\n", }, + +{ LS, ININT, + SHINT, ANYFIXED, + SHINT, ANYFIXED, + NAREG|NASR, RESC1, + "\tsubi\t31,AR,A1\n" + "\tmtsar\tA1\n" + "\tzvdep\tAL,32,A1\n", }, + +{ RS, INLL, + SHLL, TLONGLONG, + SCON, ANYFIXED, + NBREG|NBSL, RESC1, + "\tshd\tUL,AL,31-AR,A1\n" + "\textrs\tUL,31-AR,32,U1\n", }, + +{ RS, INLL, + SHLL, TULONGLONG, + SCON, ANYFIXED, + NBREG|NBSL, RESC1, + "\tshd\tUL,AL,AR,A1\n" + "\textru\tUL,31-AR,32,U1\n", }, + +{ RS, ININT, + SHINT, ANYSIGNED, + SCON, ANYFIXED, + NAREG|NASL, RESC1, + "\textrs\tAL,31-AR,32,A1\n", }, + +{ RS, ININT, + SHINT, ANYUSIGNED, + SCON, ANYFIXED, + NAREG|NASL, RESC1, + "\textru\tAL,31-AR,32,A1\n", }, + +/* TODO the following should be split into mtsar and actual shift parts */ +{ RS, ININT, + SHINT, ANYSIGNED, + SHINT, ANYFIXED, + NAREG|NASR, RESC1, + "\tsubi\t31,AR,A1\n" + "\tmtsar\tA1\n" + "\tvextrs\tAL,32,A1\n", }, + +{ RS, ININT, + SHINT, ANYUSIGNED, + SHINT, ANYFIXED, + NAREG|NASR, RESC1, + "\tsubi\t31,AR,A1\n" + "\tmtsar\tA1\n" + "\tvextru\tAL,32,A1\n", }, + +/* + * The next rules takes care of assignments. "=". + */ + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SPCON, TANY, + 0, RDEST, + "\tldi\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, TBYTE, + SHINT, TBYTE, + 0, RDEST, + "\tstb\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, THWORD, + SHINT, THWORD, + 0, RDEST, + "\tsth\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, TWORD|TPOINT, + SHINT, TWORD|TPOINT, + 0, RDEST, + "\tstw\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INLL, + SOREG, TLL, + SHLL, TLL, + 0, RDEST, + "\tstw\tAR,AL\n" + "\tstw\tUR,UL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SHINT, TBYTE, + SOREG, TBYTE, + 0, RDEST, + "\tldb\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SHINT, THWORD, + SOREG, THWORD, + 0, RDEST, + "\tldh\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SHINT, TWORD|TPOINT, + SOREG, TWORD|TPOINT, + 0, RDEST, + "\tldw\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INLL, + SHLL, TLL, + SOREG, TLL, + 0, RDEST, + "\tldw\tAR,AL\n" + "\tldw\tUR,UL\n", }, + +{ ASSIGN, FOREFF|ININT, + SHINT, TWORD|TPOINT, + SHINT, TWORD|TPOINT, + 0, RDEST, + "\tcopy\tAR,AL\n", }, + +{ ASSIGN, FOREFF|ININT, + SHINT, ANYFIXED, + SHINT, ANYFIXED, + 0, RDEST, + "\tcopy\tAR,AL\n", }, + +{ ASSIGN, FOREFF|ININT, + SFLD, TANY, + SPIMM, TANY, + 0, RDEST, + "\tdepi\tAR,31-H,S,AL\n", }, + +{ ASSIGN, FOREFF|ININT, + SFLD, TANY, + SHINT, TANY, + 0, RDEST, + "\tdep\tAR,31-H,S,AL\n", }, + +{ ASSIGN, FOREFF|INLL, + SHLL, TLL, + SHLL, TLL, + 0, RDEST, + "\tcopy\tAR,AL\n" + "\tcopy\tUR,UL\n", }, + +{ ASSIGN, FOREFF|INFL, + SHFL, TFLOAT, + SHFL, TFLOAT, + 0, RDEST, + "\tfcpy,sgl\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INDBL, + SHDBL, TDOUBLE|TLDOUBLE, + SHDBL, TDOUBLE|TLDOUBLE, + 0, RDEST, + "\tfcpy,dbl\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INFL, + SHFL, TFLOAT, + SOREG, TFLOAT, + 0, RDEST, + "\tfldws\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INDBL, + SHDBL, TDOUBLE|TLDOUBLE, + SOREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + "\tfldds\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INFL, + SOREG, TFLOAT, + SHFL, TFLOAT, + 0, RDEST, + "\tfstws\tAR,AL\n", }, + +{ ASSIGN, FOREFF|INDBL, + SOREG, TDOUBLE|TLDOUBLE, + SHDBL, TDOUBLE|TLDOUBLE, + 0, RDEST, + "\tfstds\tAR,AL\n", }, + +/* + * DIV/MOD/MUL + */ +{ DIV, INFL, + SHFL, TFLOAT, + SHFL, TFLOAT, + NCREG|NCSL|NCSR, RESC1, + "\tfdiv,sgl\tAL,AR,A1\n", }, + +{ DIV, INDBL, + SHDBL, TDOUBLE|TLDOUBLE, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG|NDSL|NDSR, RESC1, + "\tfdiv,dbl\tAL,AR,A1\n", }, + +{ MUL, INFL, + SHFL, TFLOAT, + SHFL, TFLOAT, + NCREG|NCSL|NCSR, RESC1, + "\tfmul,sgl\tAL,AR,A1\n", }, + +{ MUL, INDBL, + SHDBL, TDOUBLE|TLDOUBLE, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG|NDSL|NDSR, RESC1, + "\tfmul,dbl\tAL,AR,A1\n", }, + +/* + * Indirection operators. + */ +{ UMUL, INLL, + SANY, TANY, + SOREG, TLL, + NBREG, RESC1, + "\tldw\tAL,A1\n" + "\tldw\tUL,U1\n", }, + +{ UMUL, ININT, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG|NASL, RESC1, + "\tldw\tAL,A1\n", }, + +{ UMUL, ININT, + SANY, TANY, + SOREG, THWORD, + NAREG|NASL, RESC1, + "\tldh\tAL,A1\n", }, + +{ UMUL, ININT, + SANY, TANY, + SOREG, TBYTE, + NAREG|NASL, RESC1, + "\tldb\tAL,A1\n", }, + +{ UMUL, INDBL, + SANY, TANY, + SOREG, TDOUBLE|TLDOUBLE, + NDREG|NDSL, RESC1, + "\tfldds\tAL,A1\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TFLOAT, + NCREG|NCSL, RESC1, + "\tfldws\tAL,A1\n", }, + +/* + * Logical/branching operators + */ +{ OPLOG, FORCC, + SHLL, TLL, + SHLL, TLL, + 0, 0, + "ZD", }, + +{ OPLOG, FORCC, + SHINT, ANYFIXED|TPOINT, + SPIMM, ANYFIXED|TPOINT, + 0, 0, + "\tcomib,O\tAR,AL,LC\n\tnop\n", }, + +{ OPLOG, FORCC, + SHINT, ANYFIXED|TPOINT, + SHINT, ANYFIXED|TPOINT, + 0, 0, + "\tcomb,O\tAR,AL,LC\n\tnop\n", }, + +{ OPLOG, FORCC, + SHFL, TFLOAT, + SHFL, TFLOAT, + 0, RESCC, + "\tfcmp,sgl,!O\tAR,AL\n" + "\tftest\n" + "\tb\tLC\n" + "\tnop", }, + +{ OPLOG, FORCC, + SHDBL, TDOUBLE|TLDOUBLE, + SHDBL, TDOUBLE|TLDOUBLE, + 0, RESCC, + "\tfcmp,dbl,!O\tAR,AL\n" + "\tftest\n" + "\tb\tLC\n" + "\tnop", }, + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + "\tb\tLL\n\tnop\n", }, + +#ifdef GCC_COMPAT +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + "\tbv\t%r0(AL)\n\tnop\n", }, +#endif + + +/* + * Convert LTYPE to reg. + */ + +{ OPLTYPE, INAREG, + SAREG, TANY, + SNAME, TANY, + 0, RDEST, + "\taddil\tUR,%r27\n", }, + +{ OPLTYPE, INAREG, + SAREG, TANY, + SCON, TPOINT, + 0, RDEST, + "\taddil\tUR,%r27\n", }, + +{ OPLTYPE, INLL, + SANY, TANY, + SOREG, TLL, + NBREG|NBSL, RESC1, + "\tldw\tAL,A1\n" + "\tldw\tUL,U1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + "\tldw\tAL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + "\tcopy\tAL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SPCNHI, ANYFIXED, + NAREG, RESC1, + "\tldil\tUR,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SPCON, ANYFIXED, + NAREG, RESC1, + "\tldi\tAR,A1\n", }, + +{ OPLTYPE, INLL, + SANY, TANY, + SPCON, TLL, + NBREG, RESC1, + "\tldi\tAR,A1\n" + "\tcopy\t%r0,U1\n", }, + +{ OPLTYPE, ININT, + SANY, TANY, + SCON, TWORD, + NAREG, RESC1, + "\tldil\tUR,A1\n" + "\tldo\tAR(A1),A1\n", }, + +{ OPLTYPE, INLL, + SHLL, TLL, + SPCNHW, TLL, + NBREG, RESC1, + "\tldil\tUR>>32,U1\n" + "\tldo\tAR>>32(U1),U1\n" + "\tcopy\t%r0,A1\n", }, + +{ OPLTYPE, INLL, + SHLL, TLL, + SPCNLW, TLL, + NBREG, RESC1, + "\tcopy\t%r0,U1\n" + "\tldil\tUR,A1\n" + "\tldo\tAR(A1),A1\n", }, + +{ OPLTYPE, INLL, + SHLL, TLL, + SCON, TLL, + NBREG, RESC1, + "\tldil\tUR,A1\n" + "\tldo\tAR(A1),A1\n" + "\tldil\tUR>>32,U1\n" + "\tldo\tAR>>32(U1),U1\n", }, + +{ OPLTYPE, INCREG, + SANY, TFLOAT, + SHFL, TFLOAT, + NCREG, RESC1, + "\tfldws\tAL,A1\n", }, + +{ OPLTYPE, INDREG, + SANY, TDOUBLE|TLDOUBLE, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG, RESC1, + "\tfldds\tAL,A1\n", }, + +/* + * Negate a word. + */ +{ UMINUS, INLL, + SHLL, TLL, + SHLL, TLL, + NBREG|NBSL, RESC1, + "\tsub\t%r0,AL,A1\n" + "\tsubb\t%r0,UL,A1\n", }, + +{ UMINUS, ININT, + SHINT, TWORD, + SHINT, TWORD, + NAREG|NASL, RESC1, + "\tsub\t%r0,AL,A1\n", }, + +{ UMINUS, INFL, + SHFL, TFLOAT, + SHFL, TFLOAT, + NCREG|NCSL, RESC1, + "\tfsub,sgl\t%fr0,AL,A1\n", }, + +{ UMINUS, INDBL, + SHDBL, TDOUBLE|TLDOUBLE, + SHDBL, TDOUBLE|TLDOUBLE, + NDREG|NDSL, RESC1, + "\tfsub,dbl\t%fr0,AL,A1\n", }, + +{ COMPL, INLL, + SHLL, TLL, + SANY, TANY, + NBREG|NBSL, RESC1, + "\tuaddcm\t%r0,AL,A1\n" + "\tuaddcm\t%r0,UL,U1\n", }, + +{ COMPL, ININT, + SHINT, ANYFIXED, + SANY, TANY, + NAREG|NASL, RESC1, + "\tuaddcm\t%r0,AL,A1\n", }, + +/* + * Arguments to functions. + */ + +{ STARG, FOREFF, + SAREG|SOREG|SNAME|SCON, TANY, + SANY, TSTRUCT, + NAREG | RNULL, 0, + "ZS", }, + +/* + * struct field ops + */ +{ FLD, ININT, + SHINT, TANY, + SFLD, ANYSIGNED, + NAREG|NASL, RESC1, + "\textrs\tAL,31-H,S,A1\n", }, + +{ FLD, ININT, + SHINT, TANY, + SFLD, ANYUSIGNED, + NAREG|NASL, RESC1, + "\textru\tAL,31-H,S,A1\n", }, + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +/* { INIT, DF(INIT), }, */ + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, + FREE, FREE, + FREE, FREE, + FREE, FREE, + "HELP; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/i386/code.c b/lang/pcc/pcc/arch/i386/code.c new file mode 100644 index 000000000..05118fb9a --- /dev/null +++ b/lang/pcc/pcc/arch/i386/code.c @@ -0,0 +1,669 @@ +/* $Id: code.c,v 1.96 2015/11/17 19:19:40 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#ifdef LANG_CXX +#define p1listf listf +#define p1tfree tfree +#else +#define NODE P1ND +#define talloc p1alloc +#endif + +/* + * Print out assembler segment name. + */ +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + case DATA: + case LDATA: name = ".data"; break; + case UDATA: break; +#ifdef MACHOABI + case PICLDATA: + case PICDATA: name = ".section .data.rel.rw,\"aw\""; break; + case PICRDATA: name = ".section .data.rel.ro,\"aw\""; break; + case STRNG: name = ".cstring"; break; + case RDATA: name = ".const_data"; break; +#else + case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break; + case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; + case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; + case STRNG: +#ifdef AOUTABI + case RDATA: name = ".data"; break; +#else + case RDATA: name = ".section .rodata"; break; +#endif +#endif + case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; + case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; +#ifdef MACHOABI + case CTORS: name = ".mod_init_func\n\t.align 2"; break; + case DTORS: name = ".mod_term_func\n\t.align 2"; break; +#else + case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; + case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; +#endif + case NMSEG: + printf(PRTPREF "\t.section %s,\"a%c\",@progbits\n", name, + cftnsp ? 'x' : 'w'); + return; + } + printf(PRTPREF "\t%s\n", name); +} + +#ifdef MACHOABI +void +defalign(int al) +{ + printf(PRTPREF "\t.align %d\n", ispow2(al/ALCHAR)); +} +#endif + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + char *name; + + name = getexname(sp); + if (sp->sclass == EXTDEF) { + printf(PRTPREF " .globl %s\n", name); +#if defined(ELFABI) + printf(PRTPREF "\t.type %s,@%s\n", name, + ISFTN(sp->stype)? "function" : "object"); +#endif + } +#if defined(ELFABI) + if (!ISFTN(sp->stype)) { + if (sp->slevel == 0) + printf(PRTPREF "\t.size %s,%d\n", name, + (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR); + else + printf(PRTPREF "\t.size " LABFMT ",%d\n", sp->soffset, + (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR); + } +#endif + if (sp->slevel == 0) + printf(PRTPREF "%s:\n", name); + else + printf(PRTPREF LABFMT ":\n", sp->soffset); +} + +int structrettemp; + +/* + * code for the end of a function + * deals with struct return here + */ +void +efcode(void) +{ + extern int gotnr; + NODE *p, *q; + int sz; + + gotnr = 0; /* new number for next fun */ + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + + /* struct return for small structs */ + sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap); +#if defined(os_openbsd) + if (sz == SZCHAR || sz == SZSHORT || sz == SZINT || sz == SZLONGLONG) { +#else + if (sz == SZLONGLONG && attr_find(cftnsp->sap, ATTR_COMPLEX)) { +#endif + /* Pointer to struct in eax */ + if (sz == SZLONGLONG) { + q = block(OREG, NIL, NIL, INT, 0, 0); + slval(q, 4); + p = block(REG, NIL, NIL, INT, 0, 0); + p->n_rval = EDX; + ecomp(buildtree(ASSIGN, p, q)); + } + if (sz < SZSHORT) sz = CHAR; + else if (sz > SZSHORT) sz = INT; + else sz = SHORT; + q = block(OREG, NIL, NIL, sz, 0, 0); + p = block(REG, NIL, NIL, sz, 0, 0); + ecomp(buildtree(ASSIGN, p, q)); + return; + } + + /* Create struct assignment */ + q = tempnode(structrettemp, PTR+STRTY, 0, cftnsp->sap); + q = buildtree(UMUL, q, NIL); + p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); + p = buildtree(UMUL, p, NIL); + p = buildtree(ASSIGN, q, p); + ecomp(p); + + /* put hidden arg in eax on return */ + q = tempnode(structrettemp, INT, 0, 0); + p = block(REG, NIL, NIL, INT, 0, 0); + regno(p) = EAX; + ecomp(buildtree(ASSIGN, p, q)); +} + +#ifdef GCC_COMPAT +static TWORD reparegs[] = { EAX, EDX, ECX }; +static TWORD fastregs[] = { ECX, EDX }; +#endif +static TWORD longregs[] = { EAXEDX, EDXECX }; +static TWORD charregs[] = { AL, DL, CL }; +static TWORD *regpregs; + +/* + * code for the beginning of a function; a is an array of + * indices in symtab for the arguments; n is the number + * + * Classifying args on i386; not simple: + * - Args may be on stack or in registers (regparm) + * - There may be a hidden first arg, unless OpenBSD struct return. + * - Regparm syntax is not well documented. + * - There may be stdcall functions, where the called function pops stack + * - ...probably more + */ +void +bfcode(struct symtab **sp, int cnt) +{ + extern int argstacksize; +#ifdef GCC_COMPAT + struct attr *ap; +#endif + struct symtab *sp2; + extern int gotnr; + NODE *n, *p; + int i, regparmarg; + int argbase, nrarg, sz; + + /* Take care of PIC stuff first */ + if (kflag) { +#define STL 200 + char *str = xmalloc(STL); +#if !defined(MACHOABI) + int l = getlab(); +#else + char *name; +#endif + + /* Generate extended assembler for PIC prolog */ + p = tempnode(0, INT, 0, 0); + gotnr = regno(p); + p = block(XARG, p, NIL, INT, 0, 0); + p->n_name = "=g"; + p = block(XASM, p, bcon(0), INT, 0, 0); + +#if defined(MACHOABI) + if ((name = cftnsp->soname) == NULL) + name = cftnsp->sname; + if (snprintf(str, STL, "call L%s$pb\nL%s$pb:\n\tpopl %%0\n", + name, name) >= STL) + cerror("bfcode"); +#else + if (snprintf(str, STL, + "call " LABFMT ";" LABFMT ":;\tpopl %%0;" + "\taddl $_GLOBAL_OFFSET_TABLE_+[.-" LABFMT "], %%0;", + l, l, l) >= STL) + cerror("bfcode"); +#endif + p->n_name = addstring(str); + p->n_right->n_type = STRTY; + free(str); + ecomp(p); + } + + argbase = ARGINIT; + nrarg = regparmarg = 0; + argstacksize = 0; + +#ifdef GCC_COMPAT + regpregs = reparegs; + if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL) + cftnsp->sflags |= SSTDCALL; + if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM))) + regparmarg = ap->iarg(0); + if ((ap = attr_find(cftnsp->sap, GCC_ATYP_FASTCALL))) + regparmarg = 2, regpregs = fastregs; +#endif + + /* Function returns struct, create return arg node */ + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap); +#if defined(os_openbsd) + /* OpenBSD uses non-standard return for small structs */ + if (sz > SZLONGLONG) +#else + if (sz != SZLONGLONG || + attr_find(cftnsp->sap, ATTR_COMPLEX) == 0) +#endif + { + if (regparmarg) { + n = block(REG, 0, 0, INT, 0, 0); + regno(n) = regpregs[nrarg++]; + } else { + n = block(OREG, 0, 0, INT, 0, 0); + slval(n, argbase/SZCHAR); + argbase += SZINT; + regno(n) = FPREG; + argstacksize += 4; /* popped by callee */ + } + p = tempnode(0, INT, 0, 0); + structrettemp = regno(p); + p = buildtree(ASSIGN, p, n); + ecomp(p); + } + } + + /* + * Find where all params are so that they end up at the right place. + * At the same time recalculate their arg offset on stack. + * We also get the "pop size" for stdcall. + */ + for (i = 0; i < cnt; i++) { + sp2 = sp[i]; + sz = tsize(sp2->stype, sp2->sdf, sp2->sap); + + SETOFF(sz, SZINT); + + if (cisreg(sp2->stype) == 0 || + ((regparmarg - nrarg) * SZINT < sz)) { /* not in reg */ + sp2->soffset = argbase; + argbase += sz; + nrarg = regparmarg; /* no more in reg either */ + } else { /* in reg */ + sp2->soffset = regpregs[nrarg]; + nrarg += sz/SZINT; + sp2->sclass = REGISTER; + } + } + + /* + * Now (argbase - ARGINIT) is used space on stack. + * Move (if necessary) the args to something new. + */ + for (i = 0; i < cnt; i++) { + int reg, j; + + sp2 = sp[i]; + + if ((ISSOU(sp2->stype) && sp2->sclass == REGISTER) || + (sp2->sclass == REGISTER && xtemps == 0)) { + /* must move to stack */ + sz = tsize(sp2->stype, sp2->sdf, sp2->sap); + SETOFF(sz, SZINT); + SETOFF(autooff, SZINT); + reg = sp2->soffset; + sp2->sclass = AUTO; + sp2->soffset = NOOFFSET; + oalloc(sp2, &autooff); + for (j = 0; j < sz/SZCHAR; j += 4) { + p = block(OREG, 0, 0, INT, 0, 0); + slval(p, sp2->soffset/SZCHAR + j); + regno(p) = FPREG; + n = block(REG, 0, 0, INT, 0, 0); + regno(n) = regpregs[reg++]; + p = block(ASSIGN, p, n, INT, 0, 0); + ecomp(p); + } + } else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) && + ((cqual(sp2->stype, sp2->squal) & VOL) == 0) && xtemps) { + /* just put rest in temps */ + if (sp2->sclass == REGISTER) { + n = block(REG, 0, 0, sp2->stype, + sp2->sdf, sp2->sap); + if (ISLONGLONG(sp2->stype)) + regno(n) = longregs[sp2->soffset]; + else if (DEUNSIGN(sp2->stype) == CHAR || + sp2->stype == BOOL) + regno(n) = charregs[sp2->soffset]; + else + regno(n) = regpregs[sp2->soffset]; + } else { + n = block(OREG, 0, 0, sp2->stype, + sp2->sdf, sp2->sap); + slval(n, sp2->soffset/SZCHAR); + regno(n) = FPREG; + } + p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap); + sp2->soffset = regno(p); + sp2->sflags |= STNODE; + n = buildtree(ASSIGN, p, n); + ecomp(n); + } + } + + if (cftnsp->sflags & SSTDCALL) { +#ifdef PECOFFABI + char buf[256]; + char *name; +#endif + /* XXX interaction STDCALL and struct return? */ + argstacksize += (argbase - ARGINIT)/SZCHAR; +#ifdef PECOFFABI + /* + * mangle name in symbol table as a callee. + */ + if ((name = cftnsp->soname) == NULL) + name = exname(cftnsp->sname); + snprintf(buf, 256, "%s@%d", name, argstacksize); + cftnsp->soname = addname(buf); +#endif + } + +} + +#if defined(MACHOABI) +struct stub stublist; +struct stub nlplist; +#endif + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ +#if defined(MACHOABI) + /* + * iterate over the stublist and output the PIC stubs +` */ + if (kflag) { + struct stub *p; + + DLIST_FOREACH(p, &stublist, link) { + printf(PRTPREF "\t.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5\n"); + printf(PRTPREF "L%s$stub:\n", p->name); + printf(PRTPREF "\t.indirect_symbol %s\n", p->name); + printf(PRTPREF "\thlt ; hlt ; hlt ; hlt ; hlt\n"); + printf(PRTPREF "\t.subsections_via_symbols\n"); + } + + printf(PRTPREF "\t.section __IMPORT,__pointers,non_lazy_symbol_pointers\n"); + DLIST_FOREACH(p, &nlplist, link) { + printf(PRTPREF "L%s$non_lazy_ptr:\n", p->name); + printf(PRTPREF "\t.indirect_symbol %s\n", p->name); + printf(PRTPREF "\t.long 0\n"); + } + + } +#endif + + printf(PRTPREF "\t.ident \"PCC: %s\"\n", VERSSTR); +} + +void +bjobcode(void) +{ +#ifdef os_sunos + astypnames[SHORT] = astypnames[USHORT] = "\t.2byte"; +#endif + astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; +#if defined(MACHOABI) + DLIST_INIT(&stublist, link); + DLIST_INIT(&nlplist, link); +#endif +#if defined(__GNUC__) || defined(__PCC__) + /* Be sure that the compiler uses full x87 */ + /* XXX cross-compiling will fail here */ + int fcw; + __asm("fstcw (%0)" : : "r"(&fcw)); + fcw |= 0x300; + __asm("fldcw (%0)" : : "r"(&fcw)); +#endif +} + +/* + * Convert FUNARG to assign in case of regparm. + */ +static int regcvt, rparg, fcall; +static void +addreg(NODE *p) +{ + TWORD t; + NODE *q; + int sz, r; + + sz = tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR; + sz = (sz + 3) >> 2; /* sz in regs */ + if ((regcvt+sz) > rparg) { + regcvt = rparg; + return; + } + if (sz > 2) + uerror("cannot put struct in 3 regs (yet)"); + + if (sz == 2) + r = regcvt == 0 ? EAXEDX : EDXECX; + else if (fcall) + r = regcvt == 0 ? ECX : EDX; + else + r = regcvt == 0 ? EAX : regcvt == 1 ? EDX : ECX; + + if (p->n_op == FUNARG) { + /* at most 2 regs */ + if (p->n_type < INT) { + p->n_left = ccast(p->n_left, INT, 0, 0, 0); + p->n_type = INT; + } + + p->n_op = ASSIGN; + p->n_right = p->n_left; + } else if (p->n_op == STARG) { + /* convert to ptr, put in reg */ + q = p->n_left; + t = sz == 2 ? LONGLONG : INT; + q = cast(q, INCREF(t), 0); + q = buildtree(UMUL, q, NIL); + p->n_op = ASSIGN; + p->n_type = t; + p->n_right = q; + } else + cerror("addreg"); + p->n_left = block(REG, 0, 0, p->n_type, 0, 0); + regno(p->n_left) = r; + regcvt += sz; +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + * Returns p. + */ +NODE * +funcode(NODE *p) +{ + extern int gotnr; + struct attr *ap; + NODE *r, *l; + TWORD t = DECREF(DECREF(p->n_left->n_type)); + int stcall; + + stcall = ISSOU(t); + /* + * We may have to prepend: + * - Hidden arg0 for struct return (in reg or on stack). + * - ebx in case of PIC code. + */ + + /* Fix function call arguments. On x86, just add funarg */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + if (r->n_right->n_op != STARG) + r->n_right = block(FUNARG, r->n_right, NIL, + r->n_right->n_type, r->n_right->n_df, + r->n_right->n_ap); + } + if (r->n_op != STARG) { + l = talloc(); + *l = *r; + r->n_op = FUNARG; + r->n_left = l; + r->n_type = l->n_type; + } +#ifdef os_openbsd + if (stcall && (ap = strattr(p->n_left->n_ap)) && + ap->amsize != SZCHAR && ap->amsize != SZSHORT && + ap->amsize != SZINT && ap->amsize != SZLONGLONG) +#else + if (stcall && + (attr_find(p->n_left->n_ap, ATTR_COMPLEX) == 0 || + ((ap = strattr(p->n_left->n_ap)) && ap->amsize > SZLONGLONG))) +#endif + { + /* Prepend a placeholder for struct address. */ + /* Use EBP, can never show up under normal circumstances */ + l = talloc(); + *l = *r; + r->n_op = CM; + r->n_right = l; + r->n_type = INT; + l = block(REG, 0, 0, INCREF(VOID), 0, 0); + regno(l) = EBP; + l = block(FUNARG, l, 0, INCREF(VOID), 0, 0); + r->n_left = l; + } + +#ifdef GCC_COMPAT + fcall = 0; + if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM))) + rparg = ap->iarg(0); + else if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_FASTCALL))) + fcall = rparg = 2; + else +#endif + rparg = 0; + + regcvt = 0; + if (rparg) + p1listf(p->n_right, addreg); + + if (kflag == 0) + return p; + +#if defined(ELFABI) + /* Create an ASSIGN node for ebx */ + l = block(REG, NIL, NIL, INT, 0, 0); + l->n_rval = EBX; + l = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); + if (p->n_right->n_op != CM) { + p->n_right = block(CM, l, p->n_right, INT, 0, 0); + } else { + for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left) + ; + r->n_left = block(CM, l, r->n_left, INT, 0, 0); + } +#endif + return p; +} + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + +NODE * +builtin_return_address(const struct bitable *bt, NODE *a) +{ + int nframes; + NODE *f; + + if (a->n_op != ICON) + goto bad; + + nframes = (int)glval(a); + + p1tfree(a); + + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + + while (nframes--) + f = block(UMUL, f, NIL, PTR+VOID, 0, 0); + + f = block(PLUS, f, bcon(4), INCREF(PTR+VOID), 0, 0); + f = buildtree(UMUL, f, NIL); + + return f; +bad: + uerror("bad argument to __builtin_return_address"); + return bcon(0); +} + +NODE * +builtin_frame_address(const struct bitable *bt, NODE *a) +{ + int nframes; + NODE *f; + + if (a->n_op != ICON) + goto bad; + + nframes = (int)glval(a); + + p1tfree(a); + + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + + while (nframes--) + f = block(UMUL, f, NIL, PTR+VOID, 0, 0); + + return f; +bad: + uerror("bad argument to __builtin_frame_address"); + return bcon(0); +} + +/* + * Return "canonical frame address". + */ +NODE * +builtin_cfa(const struct bitable *bt, NODE *a) +{ + uerror("missing builtin_cfa"); + return bcon(0); +} + diff --git a/lang/pcc/pcc/arch/i386/flocal.c b/lang/pcc/pcc/arch/i386/flocal.c new file mode 100644 index 000000000..91f08e236 --- /dev/null +++ b/lang/pcc/pcc/arch/i386/flocal.c @@ -0,0 +1,231 @@ +/* $Id: flocal.c,v 1.17 2012/04/22 21:07:40 plunky Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 + +#include "defines.h" +#include "defs.h" + +void +prchars(int *s) +{ + printf("\t.byte 0%o,0%o\n", s[0], s[1]); +} + +void +setloc(int l) +{ + static int lastloc = -1; + static char *loctbl[] = + { "text", "data", "section .rodata", "section .rodata", "bss" }; + if (l == lastloc) + return; + printf("\t.%s\n", loctbl[l]); + lastloc = l; +} + +#ifdef FCOM + + +/* + PDP11-780/VAX - SPECIFIC PRINTING ROUTINES +*/ + +/* + * Called just before return from a subroutine. + */ +void +goret(int type) +{ +} + +/* + * Print out a label. + */ +void +prlabel(int k) +{ + printf(LABFMT ":\n", k); +} + +/* + * Print naming for location. + * name[0] is location type. + */ +void +prnloc(char *name) +{ + if (*name == '0') + setloc(DATA); + else + fatal("unhandled prnloc %c", *name); + printf("%s:\n", name+1); +} + +/* + * Print integer constant. + */ +void +prconi(FILE *fp, int type, ftnint n) +{ + fprintf(fp, "\t%s\t%ld\n", (type==TYSHORT ? ".word" : ".long"), n); +} + +/* + * Print address constant, given as a label number. + */ +void +prcona(ftnint a) +{ + printf("\t.long\t" LABFMT "\n", (int)a); +} + +/* + * Print out a floating constant. + */ +void +prconr(FILE *fp, int type, double x) +{ + fprintf(fp, "\t%s\t0f%e\n", (type==TYREAL ? ".float" : ".double"), x); +} + +void +preven(int k) +{ + if (k > 1) + printf("\t.align\t%d\n", k); +} + +/* + * Convert a tag and offset into the symtab table to a string. + * An external string is never longer than XL bytes. + */ +char * +memname(int stg, int mem) +{ +#define MLEN (XL + 10) + char *s = malloc(MLEN); + + switch(stg) { + case STGCOMMON: + case STGEXT: + snprintf(s, MLEN, "%s", varstr(XL, extsymtab[mem].extname)); + break; + + case STGBSS: + case STGINIT: + snprintf(s, MLEN, "v.%d", mem); + break; + + case STGCONST: + snprintf(s, MLEN, ".L%d", mem); + break; + + case STGEQUIV: + snprintf(s, MLEN, "q.%d", mem); + break; + + default: + fatal1("memname: invalid vstg %d", stg); + } + return(s); +} + +void +prlocvar(char *s, ftnint len) +{ + printf("\t.lcomm\t%s,%ld\n", s, len); +} + + +void +prext(char *name, ftnint leng, int init) +{ + if(leng == 0) + printf("\t.globl\t%s\n", name); + else + printf("\t.comm\t%s,%ld\n", name, leng); +} + +void +prendproc(void) +{ +} + +void +prtail(void) +{ +} + +void +prolog(struct entrypoint *ep, struct bigblock *argvec) +{ + /* Ignore for now. ENTRY is not supported */ +} + +void +prdbginfo(void) +{ +} + +static void +fcheck(NODE *p, void *arg) +{ + NODE *r, *l; + + switch (p->n_op) { + case CALL: /* fix arguments */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + r->n_right = mkunode(FUNARG, r->n_right, 0, + r->n_right->n_type); + } + l = talloc(); + *l = *r; + r->n_op = FUNARG; + r->n_left = l; + r->n_type = l->n_type; + break; + } +} + +/* + * Called just before the tree is written out to pass2. + */ +void p2tree(NODE *p); +void +p2tree(NODE *p) +{ + walkf(p, fcheck, 0); +} +#endif /* FCOM */ diff --git a/lang/pcc/pcc/arch/i386/local.c b/lang/pcc/pcc/arch/i386/local.c new file mode 100644 index 000000000..b276cb0b5 --- /dev/null +++ b/lang/pcc/pcc/arch/i386/local.c @@ -0,0 +1,1319 @@ +/* $Id: local.c,v 1.200 2016/03/05 15:31:24 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#undef NIL +#define NIL NULL + +#ifdef LANG_CXX +#define P1ND NODE +#define p1nfree nfree +#define p1fwalk fwalk +#define p1tcopy tcopy +#endif + +/* this file contains code which is dependent on the target machine */ + +#ifdef notyet +/* + * Check if a constant is too large for a type. + */ +static int +toolarge(TWORD t, CONSZ con) +{ + U_CONSZ ucon = con; + + switch (t) { + case ULONGLONG: + case LONGLONG: + break; /* cannot be too large */ +#define SCHK(i) case i: if (con > MAX_##i || con < MIN_##i) return 1; break +#define UCHK(i) case i: if (ucon > MAX_##i) return 1; break + SCHK(INT); + SCHK(SHORT); + case BOOL: + SCHK(CHAR); + UCHK(UNSIGNED); + UCHK(USHORT); + UCHK(UCHAR); + default: + cerror("toolarge"); + } + return 0; +} +#endif + +static char * +getsoname(struct symtab *sp) +{ + struct attr *ap; + return (ap = attr_find(sp->sap, ATTR_SONAME)) ? + ap->sarg(0) : sp->sname; + +} + +#if defined(MACHOABI) + +/* + * Keep track of PIC stubs. + */ + +void +addstub(struct stub *list, char *name) +{ + struct stub *s; + + DLIST_FOREACH(s, list, link) { + if (strcmp(s->name, name) == 0) + return; + } + + s = permalloc(sizeof(struct stub)); + s->name = newstring(name, strlen(name)); + DLIST_INSERT_BEFORE(list, s, link); +} + +#endif + +#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) + +/* + * Make a symtab entry for PIC use. + */ +static struct symtab * +picsymtab(char *p, char *s, char *s2) +{ + struct symtab *sp = IALLOC(sizeof(struct symtab)); + size_t len = strlen(p) + strlen(s) + strlen(s2) + 1; + + sp->sname = IALLOC(len); + strlcpy(sp->sname, p, len); + strlcat(sp->sname, s, len); + strlcat(sp->sname, s2, len); + sp->sap = attr_new(ATTR_SONAME, 1); + sp->sap->sarg(0) = sp->sname; + sp->sclass = EXTERN; + sp->sflags = sp->slevel = 0; + sp->stype = 0xdeadbeef; + return sp; +} + +#ifdef PECOFFABI +static P1ND * +import(P1ND *p) +{ + struct attr *ap; + P1ND *q; + char *name; + struct symtab *sp; + + name = getexname(p->n_sp); + + sp = picsymtab("__imp_", name, ""); + q = xbcon(0, sp, PTR+VOID); + q = block(UMUL, q, 0, PTR|VOID, 0, 0); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + p1nfree(p); + + return q; +} +#endif + +int gotnr; /* tempnum for GOT register */ +int argstacksize; + +/* + * Create a reference for an extern variable. + */ +static P1ND * +picext(P1ND *p) +{ + struct attr *ap; + +#if defined(ELFABI) + P1ND *q, *r; + struct symtab *sp; + char *name; + + q = tempnode(gotnr, PTR|VOID, 0, 0); + name = getexname(p->n_sp); + +#ifdef GCC_COMPAT + if ((ap = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) && + strcmp(ap->sarg(0), "hidden") == 0) { + /* For hidden vars use GOTOFF */ + sp = picsymtab("", name, "@GOTOFF"); + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + p1nfree(p); + return q; + } +#endif + + sp = picsymtab("", name, "@GOT"); +#ifdef GCC_COMPAT + if (attr_find(p->n_sp->sap, GCC_ATYP_STDCALL) != NULL) + p->n_sp->sflags |= SSTDCALL; +#endif + sp->sflags = p->n_sp->sflags & SSTDCALL; + sp->sap = attr_add(p->n_sp->sap, sp->sap); + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + q = block(UMUL, q, 0, PTR|VOID, 0, 0); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + p1nfree(p); + return q; + +#elif defined(MACHOABI) + + P1ND *q, *r; + struct symtab *sp; + char buf2[256], *name, *pspn; + + name = getsoname(cftnsp); + pspn = getexname(p->n_sp); + + if (p->n_sp->sclass == EXTDEF) { + snprintf(buf2, 256, "-L%s$pb", name); + sp = picsymtab("", pspn, buf2); + } else { + snprintf(buf2, 256, "$non_lazy_ptr-L%s$pb", name); + sp = picsymtab("L", pspn, buf2); + addstub(&nlplist, pspn); + } + + sp->stype = p->n_sp->stype; + + q = tempnode(gotnr, PTR+VOID, 0, 0); + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + + if (p->n_sp->sclass != EXTDEF) + q = block(UMUL, q, 0, PTR+VOID, 0, 0); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + p1nfree(p); + return q; + +#else /* defined(PECOFFABI) || defined(AOUTABI) */ + + return p; + +#endif + +} + +/* + * Create a reference for a static variable. + */ +static P1ND * +picstatic(P1ND *p) +{ +#if defined(ELFABI) + + P1ND *q, *r; + struct symtab *sp; + + q = tempnode(gotnr, PTR|VOID, 0, 0); + if (p->n_sp->slevel > 0) { + char buf[32]; + if ((p->n_sp->sflags & SMASK) == SSTRING) + p->n_sp->sflags |= SASG; + snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset); + sp = picsymtab("", buf, "@GOTOFF"); + } else + sp = picsymtab("", getsoname(p->n_sp), "@GOTOFF"); + + sp->sclass = STATIC; + sp->stype = p->n_sp->stype; + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + p1nfree(p); + return q; + +#elif defined(MACHOABI) + + P1ND *q, *r; + struct symtab *sp; + char buf2[256]; + + snprintf(buf2, 256, "-L%s$pb", + cftnsp->soname ? cftnsp->soname : cftnsp->sname); + + if (p->n_sp->slevel > 0) { + char buf1[32]; + snprintf(buf1, 32, LABFMT, (int)p->n_sp->soffset); + sp = picsymtab("", buf1, buf2); + } else { + char *name = getexname(p->n_sp); + sp = picsymtab("", name, buf2); + } + sp->sclass = STATIC; + sp->stype = p->n_sp->stype; + q = tempnode(gotnr, PTR+VOID, 0, 0); + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; + p1nfree(p); + return q; + +#else /* defined(PECOFFABI) || defined(AOUTABI) */ + + return p; + +#endif + +} + +#ifdef TLS +/* + * Create a reference for a TLS variable. + */ +static P1ND * +tlspic(P1ND *p) +{ + P1ND *q, *r; + struct symtab *sp, *sp2; + char *name; + + /* + * creates: + * leal var@TLSGD(%ebx),%eax + * call ___tls_get_addr@PLT + */ + + /* calc address of var@TLSGD */ + q = tempnode(gotnr, PTR|VOID, 0, 0); + name = getsoname(p->n_sp); + sp = picsymtab("", name, "@TLSGD"); + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + + /* assign to %eax */ + r = block(REG, NIL, NIL, PTR|VOID, 0, 0); + r->n_rval = EAX; + q = buildtree(ASSIGN, r, q); + + /* call ___tls_get_addr */ + sp2 = lookup("___tls_get_addr@PLT", 0); + sp2->stype = EXTERN|INT|FTN; + r = nametree(sp2); + r = buildtree(ADDROF, r, NIL); + r = block(UCALL, r, NIL, INT, 0, 0); + + /* fusion both parts together */ + q = buildtree(COMOP, q, r); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + + p1nfree(p); + return q; +} + +static P1ND * +tlsnonpic(P1ND *p) +{ + P1ND *q, *r; + struct symtab *sp, *sp2; + int ext = p->n_sp->sclass; + char *name; + + name = getsoname(p->n_sp); + sp = picsymtab("", name, + ext == EXTERN ? "@INDNTPOFF" : "@NTPOFF"); + q = xbcon(0, sp, INT); + if (ext == EXTERN) + q = block(UMUL, q, NIL, PTR|VOID, 0, 0); + + sp2 = lookup("%gs:0", 0); + sp2->stype = EXTERN|INT; + r = nametree(sp2); + + q = buildtree(PLUS, q, r); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + + p1nfree(p); + return q; +} + +static P1ND * +tlsref(P1ND *p) +{ + if (kflag) + return (tlspic(p)); + else + return (tlsnonpic(p)); +} +#endif + +/* clocal() is called to do local transformations on + * an expression tree preparitory to its being + * written out in intermediate code. + * + * the major essential job is rewriting the + * automatic variables and arguments in terms of + * REG and OREG nodes + * conversion ops which are not necessary are also clobbered here + * in addition, any special features (such as rewriting + * exclusive or) are easily handled here as well + */ +P1ND * +clocal(P1ND *p) +{ + + struct attr *ap; + register struct symtab *q; + register P1ND *r, *l, *n, *s; + register int o; + register int m; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal: %p\n", p); + p1fwalk(p, eprint, 0); + } +#endif + switch( o = p->n_op ){ + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + slval(r, 0); + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case USTATIC: + if (kflag == 0) + break; + /* FALLTHROUGH */ + case STATIC: +#ifdef TLS + if (q->sflags & STLS) { + p = tlsref(p); + break; + } +#endif + if (kflag == 0) { + if (q->slevel == 0) + break; + } else if (kflag && !statinit && blevel > 0 && +#ifdef GCC_COMPAT + attr_find(q->sap, GCC_ATYP_WEAKREF)) { +#else + 0) { +#endif + /* extern call */ + p = picext(p); + } else if (blevel > 0 && !statinit) + p = picstatic(p); + break; + + case REGISTER: + p->n_op = REG; + slval(p, 0); + p->n_rval = q->soffset; + break; + + case EXTERN: + case EXTDEF: +#ifdef TLS + if (q->sflags & STLS) { + p = tlsref(p); + break; + } +#endif + +#ifdef PECOFFABI + if (q->sflags & SDLLINDIRECT) + p = import(p); +#endif +#ifdef GCC_COMPAT + if ((ap = attr_find(q->sap, + GCC_ATYP_VISIBILITY)) != NULL && + strcmp(ap->sarg(0), "hidden") == 0) + printf(PRTPREF "\t.hidden %s\n", getsoname(q)); +#endif + if (kflag == 0) + break; + if (blevel > 0 && !statinit) + p = picext(p); + break; + } + break; + + case ADDROF: + if (kflag == 0 || blevel == 0 || statinit) + break; + /* char arrays may end up here */ + l = p->n_left; + if (l->n_op != NAME || + (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE)) + break; + l = p; + p = picstatic(p->n_left); + p1nfree(l); + if (p->n_op != UMUL) + cerror("ADDROF error"); + l = p; + p = p->n_left; + p1nfree(l); + break; + + case UCALL: + if (kflag == 0) + break; + l = block(REG, NIL, NIL, INT, 0, 0); + l->n_rval = EBX; + p->n_right = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); + p->n_op -= (UCALL-CALL); + break; + + case USTCALL: +#if defined(os_openbsd) + ap = strattr(p->n_left->n_ap); + if (ap->amsize == SZCHAR || ap->amsize == SZSHORT || + ap->amsize == SZINT || ap->amsize == SZLONGLONG) +#else + if (attr_find(p->n_left->n_ap, ATTR_COMPLEX) && + (ap = strattr(p->n_left->n_ap)) && + ap->amsize == SZLONGLONG) +#endif + { + /* float complex */ + /* fake one arg to make pass2 happy */ + p->n_right = block(FUNARG, bcon(0), NIL, INT, 0, 0); + p->n_op -= (UCALL-CALL); + break; + } + + /* Add hidden arg0 */ + r = block(REG, NIL, NIL, INCREF(VOID), 0, 0); + regno(r) = EBP; +#ifdef GCC_COMPAT + if ((ap = attr_find(p->n_ap, GCC_ATYP_REGPARM)) != NULL && + ap->iarg(0) > 0) { + l = block(REG, NIL, NIL, INCREF(VOID), 0, 0); + regno(l) = EAX; + p->n_right = buildtree(ASSIGN, l, r); + } else +#endif + p->n_right = block(FUNARG, r, NIL, INCREF(VOID), 0, 0); + p->n_op -= (UCALL-CALL); + + if (kflag == 0) + break; + l = block(REG, NIL, NIL, INT, 0, 0); + regno(l) = EBX; + r = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); + p->n_right = block(CM, r, p->n_right, INT, 0, 0); + break; + + /* FALLTHROUGH */ +#if defined(MACHOABI) + case CALL: + case STCALL: + if (p->n_type == VOID) + break; + + r = tempnode(0, p->n_type, p->n_df, p->n_ap); + l = tcopy(r); + p = buildtree(COMOP, buildtree(ASSIGN, r, p), l); +#endif + + break; + +#ifdef notyet + /* XXX breaks sometimes */ + case CBRANCH: + l = p->n_left; + + /* + * Remove unnecessary conversion ops. + */ + if (!clogop(l->n_op) || l->n_left->n_op != SCONV) + break; + if (coptype(l->n_op) != BITYPE) + break; + if (l->n_right->n_op != ICON) + break; + r = l->n_left->n_left; + if (r->n_type >= FLOAT) + break; + if (toolarge(r->n_type, l->n_right->n_lval)) + break; + l->n_right->n_type = r->n_type; + if (l->n_op >= ULE && l->n_op <= UGT) + l->n_op -= (UGT-ULE); + p->n_left = buildtree(l->n_op, r, l->n_right); + p1nfree(l->n_left); + p1nfree(l); + break; +#endif + + case PCONV: + l = p->n_left; + + /* Make int type before pointer */ + if (l->n_type < INT || l->n_type == LONGLONG || + l->n_type == ULONGLONG || l->n_type == BOOL) { + /* float etc? */ + p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); + } + break; + + case SCONV: + if (p->n_left->n_op == COMOP) + break; /* may propagate wrong type later */ + l = p->n_left; + + if (p->n_type == l->n_type) { + p1nfree(p); + return l; + } + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + tsize(p->n_type, p->n_df, p->n_ap) == + tsize(l->n_type, l->n_df, l->n_ap)) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + p1nfree(p); + return l; + } + } + } + + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && + coptype(l->n_op) == BITYPE && l->n_op != COMOP && + l->n_op != QUEST && l->n_op != ASSIGN) { + l->n_type = p->n_type; + p1nfree(p); + return l; + } + + o = l->n_op; + m = p->n_type; + + if (o == ICON) { + /* + * Can only end up here if o is an address, + * and in that case the only compile-time conversion + * possible is to int. + */ + if ((TMASK & l->n_type) == 0 && l->n_sp == NULL) + cerror("SCONV ICON"); + if (l->n_sp == 0) { + p->n_type = UNSIGNED; + concast(l, m); + } else if (m != INT && m != UNSIGNED) + break; + l->n_type = m; + l->n_ap = 0; + p1nfree(p); + return l; + } else if (l->n_op == FCON) + cerror("SCONV FCON"); + if ((p->n_type == CHAR || p->n_type == UCHAR || + p->n_type == SHORT || p->n_type == USHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left->n_type = INT; + return p; + } + break; + + case MOD: + case DIV: + if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) + break; + if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) + break; + /* make it an int division by inserting conversions */ + p->n_left = makety(p->n_left, INT, 0, 0, 0); + p->n_right = makety(p->n_right, INT, 0, 0, 0); + o = p->n_type; + p->n_type = INT; + p = makety(p, o, 0, 0, 0); + break; + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + p->n_left->n_rval = p->n_left->n_type == BOOL ? + RETREG(CHAR) : RETREG(p->n_type); + break; + + case LS: + case RS: + /* shift count must be in a char */ + if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR) + break; + p->n_right = block(SCONV, p->n_right, NIL, CHAR, 0, 0); + break; + + /* If not using pcc struct return */ + case STASG: + r = p->n_right; + if (r->n_op != STCALL && r->n_op != USTCALL) + break; + m = tsize(BTYPE(r->n_type), r->n_df, r->n_ap); + if (m == SZCHAR) + m = CHAR; + else if (m == SZSHORT) + m = SHORT; + else if (m == SZINT) + m = INT; + else if (m == SZLONGLONG) + m = LONGLONG; + else + break; +#if !defined(os_openbsd) + if (attr_find(r->n_ap, ATTR_COMPLEX) == 0) + break; /* float _Complex always in regs */ +#endif + l = buildtree(ADDROF, p->n_left, NIL); + p1nfree(p); + + r->n_op -= (STCALL-CALL); + r->n_type = m; + + /* r = long, l = &struct */ + + n = tempnode(0, m, r->n_df, r->n_ap); + r = buildtree(ASSIGN, p1tcopy(n), r); + + s = tempnode(0, l->n_type, l->n_df, l->n_ap); + l = buildtree(ASSIGN, p1tcopy(s), l); + + p = buildtree(COMOP, r, l); + + l = buildtree(CAST, + block(NAME, NIL, NIL, m|PTR, 0, 0), p1tcopy(s)); + r = l->n_right; + p1nfree(l->n_left); + p1nfree(l); + + r = buildtree(ASSIGN, buildtree(UMUL, r, NIL), n); + p = buildtree(COMOP, p, r); + p = buildtree(COMOP, p, s); + break; + } +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal end: %p\n", p); + p1fwalk(p, eprint, 0); + } +#endif + return(p); +} + +/* + * Change CALL references to either direct (static) or PLT. + */ +static void +fixnames(P1ND *p, void *arg) +{ +#if defined(ELFABI) || defined(MACHOABI) + + struct symtab *sp; + struct attr *ap, *ap2; + P1ND *q; + char *c; + int isu; + + if ((cdope(p->n_op) & CALLFLG) == 0) + return; + isu = 0; + q = p->n_left; + ap = q->n_ap; + if (q->n_op == UMUL) + q = q->n_left, isu = 1; + + if (q->n_op == PLUS && q->n_left->n_op == TEMP && + q->n_right->n_op == ICON) { + sp = q->n_right->n_sp; + + if (sp == NULL) + return; /* nothing to do */ + if (sp->sclass == STATIC && !ISFTN(sp->stype)) + return; /* function pointer */ + + if (sp->sclass != STATIC && sp->sclass != EXTERN && + sp->sclass != EXTDEF) + cerror("fixnames"); + c = NULL; +#if defined(ELFABI) + + if ((ap2 = attr_find(sp->sap, ATTR_SONAME)) == NULL || + (c = strstr(ap2->sarg(0), "@GOT")) == NULL) + cerror("fixnames2: %p %s", ap2, c); + if (isu) { + memcpy(c, "@PLT", sizeof("@PLT")); + } else + *c = 0; + +#elif defined(MACHOABI) + + if (sp->soname == NULL || + ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL && + (c = strstr(sp->soname, "-L")) == NULL)) + cerror("fixnames2"); + + if (!ISFTN(sp->stype)) + return; /* function pointer */ + + if (isu) { + *c = 0; + addstub(&stublist, sp->soname+1); + memcpy(c, "$stub", sizeof("$stub")); + } else + *c = 0; + +#endif + + p1nfree(q->n_left); + q = q->n_right; + if (isu) + p1nfree(p->n_left->n_left); + p1nfree(p->n_left); + p->n_left = q; + q->n_ap = ap; + } +#endif +} + +static void mangle(P1ND *p); + +void +myp2tree(P1ND *p) +{ + struct symtab *sp; + + if (kflag) + fixnames(p, 0); + + mangle(p); + + if ((p->n_op == STCALL || p->n_op == USTCALL) && + attr_find(p->n_ap, ATTR_COMPLEX) && + strmemb(p->n_ap)->stype == FLOAT) + p->n_ap = attr_add(p->n_ap, attr_new(ATTR_I386_FCMPLRET, 1)); + + if (p->n_op != FCON) + return; + + sp = IALLOC(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->sap = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + sp->sname = NULL; + + locctr(DATA, sp); + defloc(sp); + ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + + p->n_op = NAME; + slval(p, 0); + p->n_sp = sp; + + if (kflag) { + P1ND *q = optim(picstatic(p1tcopy(p))); + *p = *q; + p1nfree(q); + } +} + +/*ARGSUSED*/ +int +andable(P1ND *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * Return 1 if a variable of type type is OK to put in register. + */ +int +cisreg(TWORD t) +{ + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return 0; /* not yet */ + return 1; +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a storeable node where to write + * the allocated address. + */ +void +spalloc(P1ND *t, P1ND *p, OFFSZ off) +{ + P1ND *sp; + + p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ + + /* sub the size from sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + slval(sp, 0); + sp->n_rval = STKREG; + ecomp(buildtree(MINUSEQ, sp, p)); + +#ifdef MACHOABI + /* align to 16 bytes */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(PLUSEQ, sp, bcon(15))); + + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(RSEQ, sp, bcon(4))); + + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(LSEQ, sp, bcon(4))); +#endif + + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); + slval(sp, 0); + sp->n_rval = STKREG; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + +} + +/* + * print out a constant node, may be associated with a label. + * Do not free the node after use. + * off is bit offset from the beginning of the aggregate + * fsz is the number of bits this is referring to + */ +int +ninval(CONSZ off, int fsz, P1ND *p) +{ + union { float f; double d; long double l; int i[3]; } u; + int i; + + switch (p->n_type) { + case LONGLONG: + case ULONGLONG: + i = (int)(glval(p) >> 32); + slval(p, glval(p) & 0xffffffff); + p->n_type = INT; + inval(off, 32, p); + slval(p, i); + inval(off+32, 32, p); + break; + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)((FLT *)p->n_dcon)->fp; +#if defined(HOST_BIG_ENDIAN) + printf(PRTPREF "\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]); +#else + printf(PRTPREF "\t.long\t%d,%d,%d\n", u.i[0], u.i[1], u.i[2] & 0177777); +#endif + break; + case DOUBLE: + u.d = (double)((FLT *)p->n_dcon)->fp; +#if defined(HOST_BIG_ENDIAN) + printf(PRTPREF "\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]); +#else + printf(PRTPREF "\t.long\t%d,%d\n", u.i[0], u.i[1]); +#endif + break; + case FLOAT: + u.f = (float)((FLT *)p->n_dcon)->fp; + printf(PRTPREF "\t.long\t%d\n", u.i[0]); + break; + default: + return 0; + } + return 1; +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ +#if !defined(ELFABI) + +#define NCHNAM 256 + static char text[NCHNAM+1]; + int i; + + if (p == NULL) + return ""; + + text[0] = '_'; + for (i=1; *p && istype, sp->sap)/SZCHAR; + off = (int)tsize(sp->stype, sp->sdf, sp->sap); + SETOFF(off,SZCHAR); + off /= SZCHAR; +#if defined(MACHOABI) || defined(PECOFFABI)/* && binutils>2.20 */ + al = ispow2(al); + if (sp->sclass == STATIC) { + if (sp->slevel == 0) + printf(PRTPREF "\t.lcomm %s,0%o,%d\n", name, off, al); + else + printf(PRTPREF "\t.lcomm " LABFMT ",0%o,%d\n", sp->soffset, off, al); + } else { + if (sp->slevel == 0) + printf(PRTPREF "\t.comm %s,0%o,%d\n", name, off, al); + else + printf(PRTPREF "\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); + } +#elif defined(ELFABI) +#ifdef GCC_COMPAT + if (attr_find(sp->sap, GCC_ATYP_WEAKREF) != NULL) + return; +#endif + if (sp->sclass == STATIC) { + if (sp->slevel == 0) { + printf(PRTPREF "\t.local %s\n", name); + } else + printf(PRTPREF "\t.local " LABFMT "\n", sp->soffset); + } + if (sp->slevel == 0) + printf(PRTPREF "\t.comm %s,0%o,%d\n", name, off, al); + else + printf(PRTPREF "\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); +#else + if (attr_find(sp->sap, GCC_ATYP_WEAKREF) != NULL) + return; + if (sp->slevel == 0) + printf(PRTPREF "\t.%scomm %s,0%o\n", + sp->sclass == STATIC ? "l" : "", name, off); + else + printf(PRTPREF "\t.%scomm " LABFMT ",0%o\n", + sp->sclass == STATIC ? "l" : "", sp->soffset, off); +#endif +} + +#ifdef TLS +static int gottls; +#endif +#ifdef PECOFFABI +static int dllindirect; +#endif +static char *alias; +static int constructor; +static int destructor; + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + char *a2 = pragtok(NULL); + +#ifdef TLS + if (strcmp(str, "tls") == 0 && a2 == NULL) { + gottls = 1; + return 1; + } +#endif +#ifdef PECOFFABI + if (strcmp(str, "dllimport") == 0) { + dllindirect = 1; + return 1; + } + if (strcmp(str, "dllexport") == 0) { + dllindirect = 1; + return 1; + } +#endif +#ifndef AOUTABI + if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { + constructor = 1; + return 1; + } + if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { + destructor = 1; + return 1; + } +#endif + if (strcmp(str, "alias") == 0 && a2 != NULL) { + alias = tmpstrdup(a2); + return 1; + } + + return 0; +} + +/* + * Called when a identifier has been declared. + */ +void +fixdef(struct symtab *sp) +{ +#ifdef GCC_COMPAT + struct attr *ap; +#endif + +#ifdef TLS + /* may have sanity checks here */ + if (gottls) + sp->sflags |= STLS; + gottls = 0; +#endif +#ifdef GCC_COMPAT +#ifdef HAVE_WEAKREF + /* not many as'es have this directive */ + if ((ap = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) { + char *wr = ap->sarg(0); + char *sn = getsoname(sp); + if (sp->sclass != STATIC && sp->sclass != USTATIC) + uerror("weakref %s must be static", sp->sname); + if (wr == NULL) { + if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS))) { + wr = ap->sarg(0); + } + } + if (wr == NULL) + printf(PRTPREF "\t.weak %s\n", sn); + else + printf(PRTPREF "\t.weakref %s,%s\n", sn, wr); + } else +#endif + if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) { + char *an = ap->sarg(0); + char *v; + char *sn = getsoname(sp); + + v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl"; + printf(PRTPREF "\t.%s %s\n", v, sn); + printf(PRTPREF "\t.set %s,%s\n", sn, an); + } +#endif + if (alias != NULL && (sp->sclass != PARAM)) { + char *name = getexname(sp); + printf(PRTPREF "\t.globl %s\n", name); + printf(PRTPREF "%s = ", name); + printf("%s\n", exname(alias)); + alias = NULL; + } + if ((constructor || destructor) && (sp->sclass != PARAM)) { +#if defined(ELFABI) + printf(PRTPREF "\t.section .%ctors,\"aw\",@progbits\n", + constructor ? 'c' : 'd'); +#elif defined(PECOFFABI) + printf(PRTPREF "\t.section .%ctors,\"w\"\n", + constructor ? 'c' : 'd'); +#elif defined(MACHOABI) + if (kflag) { + if (constructor) + printf(PRTPREF "\t.mod_init_func\n"); + else + printf(PRTPREF "\t.mod_term_func\n"); + } else { + if (constructor) + printf(PRTPREF "\t.constructor\n"); + else + printf(PRTPREF "\t.destructor\n"); + } +#elif defined(AOUTABI) + uerror("constructor/destructor are not supported for this target"); +#endif + printf(PRTPREF "\t.p2align 2\n"); + printf(PRTPREF "\t.long %s\n", exname(sp->sname)); +#if defined(ELFABI) + printf(PRTPREF "\t.previous\n"); +#else + printf(PRTPREF "\t.text\n"); +#endif + constructor = destructor = 0; + } +#ifdef PECOFFABI + if (dllindirect && (sp->sclass != PARAM)) { + sp->sflags |= SDLLINDIRECT; + dllindirect = 0; + } +#endif +} + +/* + * Postfix external functions with the arguments size. + */ +static void +mangle(P1ND *p) +{ + P1ND *l; + + if (p->n_op != CALL && p->n_op != STCALL && + p->n_op != UCALL && p->n_op != USTCALL) + return; + + l = p->n_left; + while (cdope(l->n_op) & CALLFLG) + l = l->n_left; + if (l->n_op == TEMP) + return; + if (l->n_op == ADDROF) + l = l->n_left; + if (l->n_sp == NULL) + return; +#ifdef GCC_COMPAT + if (attr_find(l->n_sp->sap, GCC_ATYP_STDCALL) != NULL) + l->n_sp->sflags |= SSTDCALL; +#endif +#ifdef PECOFFABI + if (l->n_sp->sflags & SSTDCALL) { + if (strchr(l->n_name, '@') == NULL) { + int size = 0; + char buf[256]; + P1ND *r; + TWORD t; + + if (p->n_op == CALL || p->n_op == STCALL) { + for (r = p->n_right; + r->n_op == CM; r = r->n_left) { + t = r->n_type; + if (t == STRTY || t == UNIONTY) + size += tsize(t, r->n_df, r->n_ap); + else + size += szty(t) * SZINT / SZCHAR; + } + t = r->n_type; + if (t == STRTY || t == UNIONTY) + size += tsize(t, r->n_df, r->n_ap); + else + size += szty(t) * SZINT / SZCHAR; + } + size = snprintf(buf, 256, "%s@%d", l->n_name, size) + 1; + l->n_name = IALLOC(size); + memcpy(l->n_name, buf, size); + } + } +#endif +} + +void +pass1_lastchance(struct interpass *ip) +{ + if (ip->type == IP_NODE && + (ip->ip_node->n_op == CALL || ip->ip_node->n_op == UCALL) && + ISFTY(ip->ip_node->n_type)) + ip->ip_node->n_ap = attr_add(ip->ip_node->n_ap, + attr_new(ATTR_I386_FPPOP, 1)); + + if (ip->type == IP_EPILOG) { + struct interpass_prolog *ipp = (struct interpass_prolog *)ip; + ipp->ipp_argstacksize = argstacksize; + } +} + +#ifdef PASS1 +void +mflags(char *s) +{ +} +#endif diff --git a/lang/pcc/pcc/arch/i386/local2.c b/lang/pcc/pcc/arch/i386/local2.c new file mode 100644 index 000000000..4957ff7c4 --- /dev/null +++ b/lang/pcc/pcc/arch/i386/local2.c @@ -0,0 +1,1555 @@ +/* $Id: local2.c,v 1.187 2016/03/13 10:14:25 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" +# include +# include + +#if defined(PECOFFABI) || defined(MACHOABI) || defined(AOUTABI) +#define EXPREFIX "_" +#else +#define EXPREFIX "" +#endif + +int msettings = MI686; +static int stkpos; + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static int regoff[7]; +static TWORD ftype; + +/* + * Print out the prolog assembler. + * addto and regoff are already calculated. + */ +static void +prtprolog(struct interpass_prolog *ipp, int addto) +{ + int i; + +#if 1 +#if defined(MACHOABI) + addto += 8; +#endif + if (addto == 0 || addto > 65535) { + printf(" pushl %%ebp\n\tmovl %%esp,%%ebp\n"); + if (addto) + printf(" subl $%d,%%esp\n", addto); + } else + printf(" enter $%d,$0\n", addto); +#endif + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) + printf(" movl %s,-%d(%s)\n", + rnames[i], regoff[i], rnames[FPREG]); +} + +/* + * calculate stack size and offsets + */ +static int +offcalc(struct interpass_prolog *ipp) +{ + int i, addto; + + addto = p2maxautooff; + if (addto >= AUTOINIT/SZCHAR) + addto -= AUTOINIT/SZCHAR; + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) { + addto += SZINT/SZCHAR; + regoff[i] = addto; + } + return addto; +} + +void +prologue(struct interpass_prolog *ipp) +{ + int addto; + + ftype = ipp->ipp_type; + +#ifdef LANG_F77 + if (ipp->ipp_vis) + printf(" .globl %s\n", ipp->ipp_name); + printf(" .align 4\n"); + printf("%s:\n", ipp->ipp_name); +#endif + /* + * We here know what register to save and how much to + * add to the stack. + */ + addto = offcalc(ipp); +#if defined(MACHOABI) + addto = (addto + 15) & ~15; /* stack alignment */ +#endif + prtprolog(ipp, addto); +} + +void +eoftn(struct interpass_prolog *ipp) +{ + int i; + + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + /* return from function code */ + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) + printf(" movl -%d(%s),%s\n", + regoff[i], rnames[FPREG], rnames[i]); + + /* struct return needs special treatment */ + if (ftype == STRTY || ftype == UNIONTY) { + printf(" movl 8(%%ebp),%%eax\n"); + printf(" leave\n"); + printf(" ret $%d\n", 4 + ipp->ipp_argstacksize); + } else { + printf(" leave\n"); + if (ipp->ipp_argstacksize) + printf(" ret $%d\n", ipp->ipp_argstacksize); + else + printf(" ret\n"); + } + +#if defined(ELFABI) + printf("\t.size " EXPREFIX "%s,.-" EXPREFIX "%s\n", ipp->ipp_name, + ipp->ipp_name); +#endif +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s%c", str, f); +} + +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(NODE *p) +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +/* + * Emit code to compare two longlong numbers. + */ +static void +twollcomp(NODE *p) +{ + int u; + int s = getlab2(); + int e = p->n_label; + int cb1, cb2; + + u = p->n_op; + switch (p->n_op) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + u += (ULE-LE); + /* FALLTHROUGH */ + case ULE: + case ULT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + u += (ULE-LE); + /* FALLTHROUGH */ + case UGE: + case UGT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 4, cb2 += 4; + expand(p, 0, " cmpl UR,UL\n"); + if (cb1) cbgen(cb1, s); + if (cb2) cbgen(cb2, e); + expand(p, 0, " cmpl AR,AL\n"); + cbgen(u, e); + deflab(s); +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + comperr("fldexpand"); + return 0; +} + +/* + * Push a structure on stack as argument. + * the scratch registers are already free here + */ +static void +starg(NODE *p) +{ + struct attr *ap; + NODE *q = p->n_left; + + ap = attr_find(p->n_ap, ATTR_P2STRUCT); + printf(" subl $%d,%%esp\n", (ap->iarg(0) + 3) & ~3); + p->n_left = mklnode(OREG, 0, ESP, INT); + zzzcode(p, 'Q'); + tfree(p->n_left); + p->n_left = q; +} + +/* + * Compare two floating point numbers. + */ +static void +fcomp(NODE *p) +{ + static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" }; + + if (msettings & MI686) { + if ((p->n_su & DORIGHT) == 0) + expand(p, 0, "\tfxch\n"); + expand(p, 0, "\tfucomip %st(1),%st\n"); /* emit compare insn */ + expand(p, 0, "\tfstp %st(0)\n"); /* pop fromstack */ + + if (p->n_op == NE || p->n_op == GT || p->n_op == GE) + expand(p, 0, "\tjp LC\n"); + else if (p->n_op == EQ) + printf("\tjp 1f\n"); + printf(" %s ", fpcb[p->n_op - EQ]); + expand(p, 0, "LC\n"); + if (p->n_op == EQ) + printf("1:\n"); + } else { + int swap = ((p->n_su & DORIGHT) == 0); + + if (p->n_op == GT || p->n_op == GE) + swap ^= 1; + if (swap) + expand(p, 0, "\tfxch\n"); + + /* + * Flags for x87: + * C3 C2 C0 + * 0 0 0 st0 > st1 + * 0 0 1 st0 < st1 + * 1 0 0 st0 = st1 + * 1 1 1 unordered + */ + + /* ax avoided in nspecial() */ + printf("\tfucompp\n\tfnstsw %%ax\n"); + if (p->n_op == GE || p->n_op == LE) { + printf("\ttestb $0x45,%%ah\n"); + } else if (p->n_op == GT || p->n_op == LT) { + printf("\ttestb $0x05,%%ah\n"); + } else if (p->n_op == NE) { + printf("\tandb $0x45,%%ah\n"); + printf("\txorb $0x40,%%ah\n"); + } else if (p->n_op == EQ) { + printf("\tandb $0x45,%%ah\n"); + printf("\tcmpb $0x40,%%ah\n"); + } + if (p->n_op == EQ) { + expand(p, 0, "\tje LC\n"); + } else + expand(p, 0, "\tjne LC\n"); + } +} + +/* + * Convert an unsigned long long to floating point number. + */ +static void +ulltofp(NODE *p) +{ + int jmplab; + +#if defined(ELFABI) || defined(PECOFFABI) || defined(AOUTABI) + static int loadlab; + + if (loadlab == 0) { + loadlab = getlab2(); + expand(p, 0, " .data\n"); + printf(LABFMT ": .long 0,0x80000000,0x403f\n", loadlab); + expand(p, 0, " .text\n"); + } +#endif + + jmplab = getlab2(); + expand(p, 0, " pushl UL\n pushl AL\n"); + expand(p, 0, " fildq (%esp)\n"); + expand(p, 0, " addl $8,%esp\n"); + expand(p, 0, " cmpl $0,UL\n"); + printf(" jge " LABFMT "\n", jmplab); + +#if defined(ELFABI) || defined(AOUTABI) + printf(" fldt " LABFMT "%s\n", loadlab, kflag ? "@GOTOFF" : ""); +#elif defined(MACHOABI) + printf("\tpushl 0x5f800000\n"); + printf("\tfadds (%%esp)\n"); + printf("\taddl $4,%%esp\n"); +#else +#error incomplete implementation +#endif + + printf(" faddp %%st,%%st(1)\n"); + printf(LABFMT ":\n", jmplab); +} + +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (t < LONGLONG || t == FLOAT || t > BTMASK) + return 4; + if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) + return 8; + if (t == LDOUBLE) + return 12; + if (t == STRTY || t == UNIONTY) + return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) & ~3; + comperr("argsiz"); + return 0; +} + +static void +fcast(NODE *p) +{ + TWORD t = p->n_type; + int sz, c; + + if (t >= p->n_left->n_type) + return; /* cast to more precision */ + if (t == FLOAT) + sz = 4, c = 's'; + else + sz = 8, c = 'l'; + + printf(" sub $%d,%%esp\n", sz); + printf(" fstp%c (%%esp)\n", c); + printf(" fld%c (%%esp)\n", c); + printf(" add $%d,%%esp\n", sz); +} + +static void +llshft(NODE *p) +{ + char *d[3]; + + if (p->n_op == LS) { + d[0] = "l", d[1] = "%eax", d[2] = "%edx"; + } else + d[0] = "r", d[1] = "%edx", d[2] = "%eax"; + + printf("\tsh%sdl %s,%s\n",d[0], d[1], d[2]); + printf("\ts%s%sl %%cl,%s\n", p->n_op == RS && + p->n_left->n_type == ULONGLONG ? "h" : "a", d[0], d[1]); + printf("\ttestb $32,%%cl\n"); + printf("\tje 1f\n"); + printf("\tmovl %s,%s\n", d[1], d[2]); + if (p->n_op == RS && p->n_left->n_type == LONGLONG) + printf("\tsarl $31,%%edx\n"); + else + printf("\txorl %s,%s\n",d[1],d[1]); + printf("1:\n"); +} + +void +zzzcode(NODE *p, int c) +{ + struct attr *ap; + NODE *l; + int pr, lr; + char *ch; + + switch (c) { + case 'A': /* swap st0 and st1 if right is evaluated second */ + if ((p->n_su & DORIGHT) == 0) { + if (logop(p->n_op)) + printf(" fxch\n"); + else + printf("r"); + } + break; + + case 'C': /* remove from stack after subroutine call */ +#ifdef GCC_COMPAT + if (attr_find(p->n_left->n_ap, GCC_ATYP_STDCALL)) + break; +#endif + pr = p->n_qual; + if (attr_find(p->n_ap, ATTR_I386_FPPOP)) + printf(" fstp %%st(0)\n"); + if (p->n_op == UCALL) + return; /* XXX remove ZC from UCALL */ + if (pr) + printf(" addl $%d, %s\n", pr, rnames[ESP]); +#if defined(os_openbsd) + ap = attr_find(p->n_ap, ATTR_P2STRUCT); + if (p->n_op == STCALL && (ap->iarg(0) == 1 || + ap->iarg(0) == 2 || ap->iarg(0) == 4 || + ap->iarg(0) == 8)) { + /* save on stack */ + printf("\tmovl %%eax,-%d(%%ebp)\n", stkpos); + printf("\tmovl %%edx,-%d(%%ebp)\n", stkpos+4); + printf("\tleal -%d(%%ebp),%%eax\n", stkpos); + } +#endif + break; + + case 'D': /* Long long comparision */ + twollcomp(p); + break; + + case 'F': /* Structure argument */ + starg(p); + break; + + case 'G': /* Floating point compare */ + fcomp(p); + break; + + case 'H': /* assign of longlong between regs */ + rmove(DECRA(p->n_right->n_reg, 0), + DECRA(p->n_left->n_reg, 0), LONGLONG); + break; + + case 'I': /* float casts */ + fcast(p); + break; + + case 'J': /* convert unsigned long long to floating point */ + ulltofp(p); + break; + + case 'K': /* Load longlong reg into another reg */ + rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG); + break; + + case 'M': /* Output sconv move, if needed */ + l = getlr(p, 'L'); + /* XXX fixneed: regnum */ + pr = DECRA(p->n_reg, 0); + lr = DECRA(l->n_reg, 0); + if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) || + (pr == CL && lr == ECX) || (pr == DL && lr == EDX)) + ; + else + printf(" movb %%%cl,%s\n", + rnames[lr][2], rnames[pr]); + l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */ + break; + + case 'N': /* output extended reg name */ + printf("%s", rnames[getlr(p, '1')->n_rval]); + break; + + case 'O': /* print out emulated ops */ + pr = 16; + if (p->n_op == RS || p->n_op == LS) { + llshft(p); + break; + } else if (p->n_op == MUL) { + printf("\timull %%ecx, %%edx\n"); + printf("\timull %%eax, %%esi\n"); + printf("\taddl %%edx, %%esi\n"); + printf("\tmull %%ecx\n"); + printf("\taddl %%esi, %%edx\n"); + break; + } + expand(p, INCREG, "\tpushl UR\n\tpushl AR\n"); + expand(p, INCREG, "\tpushl UL\n\tpushl AL\n"); + if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv"; + else if (p->n_op == DIV) ch = "div"; + else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod"; + else if (p->n_op == MOD) ch = "mod"; + else ch = 0, comperr("ZO"); +#ifdef ELFABI + printf("\tcall " EXPREFIX "__%sdi3%s\n\taddl $%d,%s\n", + ch, (kflag ? "@PLT" : ""), pr, rnames[ESP]); +#else + printf("\tcall " EXPREFIX "__%sdi3\n\taddl $%d,%s\n", + ch, pr, rnames[ESP]); +#endif + break; + + case 'Q': /* emit struct assign */ + /* + * Put out some combination of movs{b,w,l} + * esi/edi/ecx are available. + */ + expand(p, INAREG, " leal AL,%edi\n"); + ap = attr_find(p->n_ap, ATTR_P2STRUCT); + if (ap->iarg(0) < 32) { + int i = ap->iarg(0) >> 2; + while (i) { + expand(p, INAREG, " movsl\n"); + i--; + } + } else { + printf("\tmovl $%d,%%ecx\n", ap->iarg(0) >> 2); + printf(" rep movsl\n"); + } + if (ap->iarg(0) & 2) + printf(" movsw\n"); + if (ap->iarg(0) & 1) + printf(" movsb\n"); + break; + + case 'S': /* emit eventual move after cast from longlong */ + pr = DECRA(p->n_reg, 0); + lr = p->n_left->n_rval; + switch (p->n_type) { + case CHAR: + case UCHAR: + if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' && + rnames[pr][1] == rnames[lr][1]) + break; + if (rnames[lr][2] == 'x') { + printf("\tmovb %%%cl,%s\n", + rnames[lr][1], rnames[pr]); + break; + } + /* Must go via stack */ + expand(p, INAREG, "\tmovl AL,A2\n"); + expand(p, INBREG, "\tmovb A2,A1\n"); +#ifdef notdef + /* cannot use freetemp() in instruction emission */ + s = freetemp(1); + printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s); + printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]); +#endif + break; + + case SHORT: + case USHORT: + if (rnames[lr][1] == rnames[pr][2] && + rnames[lr][2] == rnames[pr][3]) + break; + printf("\tmovw %%%c%c,%%%s\n", + rnames[lr][1], rnames[lr][2], rnames[pr]+2); + break; + case INT: + case UNSIGNED: + if (rnames[lr][1] == rnames[pr][2] && + rnames[lr][2] == rnames[pr][3]) + break; + printf("\tmovl %%e%c%c,%s\n", + rnames[lr][1], rnames[lr][2], rnames[pr]); + break; + + default: + if (rnames[lr][1] == rnames[pr][2] && + rnames[lr][2] == rnames[pr][3]) + break; + comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]); + break; + } + break; + + default: + comperr("zzzcode %c", c); + } +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left, SOREG))) + return(1); + return(0); +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + comperr("flshape"); + return 0; +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + return 0; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +void +adrcon(CONSZ val) +{ + printf("$" CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + int val = (int)getlval(p); + + switch (p->n_op) { + case ICON: + if (p->n_name[0] != '\0') { + fprintf(fp, "%s", p->n_name); + if (val) + fprintf(fp, "+%d", val); + } else + fprintf(fp, "%d", val); + return; + + default: + comperr("illegal conput, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + + size /= SZCHAR; + switch (p->n_op) { + case REG: + printf("%%%s", &rnames[p->n_rval][3]); + break; + + case NAME: + case OREG: + setlval(p, getlval(p) + size); + adrput(stdout, p); + setlval(p, getlval(p) - size); + break; + case ICON: + printf("$" CONFMT, getlval(p) >> 32); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *io, NODE *p) +{ + int r; + /* output an address, with offsets, from p */ + + switch (p->n_op) { + + case NAME: + if (p->n_name[0] != '\0') { + fputs(p->n_name, io); + if (getlval(p) != 0) + fprintf(io, "+" CONFMT, getlval(p)); + } else + fprintf(io, CONFMT, getlval(p)); + return; + + case OREG: + r = p->n_rval; + if (p->n_name[0]) + printf("%s%s", p->n_name, getlval(p) ? "+" : ""); + if (getlval(p)) + fprintf(io, "%d", (int)getlval(p)); + if (R2TEST(r)) { + fprintf(io, "(%s,%s,4)", rnames[R2UPK1(r)], + rnames[R2UPK2(r)]); + } else + fprintf(io, "(%s)", rnames[p->n_rval]); + return; + case ICON: +#ifdef PCC_DEBUG + /* Sanitycheck for PIC, to catch adressable constants */ + if (kflag && p->n_name[0] && 0) { + static int foo; + + if (foo++ == 0) { + printf("\nfailing...\n"); + fwalk(p, e2print, 0); + comperr("pass2 conput"); + } + } +#endif + /* addressable value of the constant */ + fputc('$', io); + conput(io, p); + return; + + case REG: + switch (p->n_type) { + case LONGLONG: + case ULONGLONG: + fprintf(io, "%%%c%c%c", rnames[p->n_rval][0], + rnames[p->n_rval][1], rnames[p->n_rval][2]); + break; + case SHORT: + case USHORT: + fprintf(io, "%%%s", &rnames[p->n_rval][2]); + break; + default: + fprintf(io, "%s", rnames[p->n_rval]); + } + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +static char * +ccbranches[] = { + "je", /* jumpe */ + "jne", /* jumpn */ + "jle", /* jumple */ + "jl", /* jumpl */ + "jge", /* jumpge */ + "jg", /* jumpg */ + "jbe", /* jumple (jlequ) */ + "jb", /* jumpl (jlssu) */ + "jae", /* jumpge (jgequ) */ + "ja", /* jumpg (jgtru) */ +}; + + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + if (o < EQ || o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); +} + +static void +fixcalls(NODE *p, void *arg) +{ + struct attr *ap; + + /* Prepare for struct return by allocating bounce space on stack */ + switch (p->n_op) { + case STCALL: + case USTCALL: + ap = attr_find(p->n_ap, ATTR_P2STRUCT); + if (ap->iarg(0)+p2autooff > stkpos) + stkpos = ap->iarg(0)+p2autooff; + if (8+p2autooff > stkpos) + stkpos = ap->iarg(0)+p2autooff; + break; + case LS: + case RS: + if (p->n_type != LONGLONG && p->n_type != ULONGLONG) + break; + if (p->n_right->n_op == ICON) /* constants must be char */ + p->n_right->n_type = CHAR; + break; + } +} + +/* + * Must store floats in memory if there are two function calls involved. + */ +static int +storefloat(struct interpass *ip, NODE *p) +{ + int l, r; + + switch (optype(p->n_op)) { + case BITYPE: + l = storefloat(ip, p->n_left); + r = storefloat(ip, p->n_right); + if (p->n_op == CM) + return 0; /* arguments, don't care */ + if (callop(p->n_op)) + return 1; /* found one */ +#define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \ + (p)->n_type == LDOUBLE) + if (ISF(p->n_left) && ISF(p->n_right) && l && r) { + /* must store one. store left */ + struct interpass *nip; + TWORD t = p->n_left->n_type; + NODE *ll; + int off; + + off = freetemp(szty(t)); + ll = mklnode(OREG, off, FPREG, t); + nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t)); + p->n_left = mklnode(OREG, off, FPREG, t); + DLIST_INSERT_BEFORE(ip, nip, qelem); + } + return l|r; + + case UTYPE: + l = storefloat(ip, p->n_left); + if (callop(p->n_op)) + l = 1; + return l; + default: + return 0; + } +} + +static void +outfargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c) +{ + struct interpass *ip2; + NODE *q, *r; + int i; + + for (i = 0; i < num; i++) + if (XASMVAL(cwp[i]) == c && (cwp[i] & (XASMASG|XASMINOUT))) + break; + if (i == num) + return; + q = ary[i]->n_left; + r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type); + ary[i]->n_left = tcopy(r); + ip2 = ipnode(mkbinode(ASSIGN, q, r, q->n_type)); + DLIST_INSERT_AFTER(ip, ip2, qelem); +} + +static void +infargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c) +{ + struct interpass *ip2; + NODE *q, *r; + int i; + + for (i = 0; i < num; i++) + if (XASMVAL(cwp[i]) == c && (cwp[i] & XASMASG) == 0) + break; + if (i == num) + return; + q = ary[i]->n_left; + q = (cwp[i] & XASMINOUT) ? tcopy(q) : q; + r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type); + if ((cwp[i] & XASMINOUT) == 0) + ary[i]->n_left = tcopy(r); + ip2 = ipnode(mkbinode(ASSIGN, r, q, q->n_type)); + DLIST_INSERT_BEFORE(ip, ip2, qelem); +} + +/* + * Extract float args to XASM and ensure that they are put on the stack + * in correct order. + * This should be done sow other way. + */ +static void +fixxfloat(struct interpass *ip, NODE *p) +{ + NODE *w, **ary; + int nn, i, c, *cwp; + + nn = 1; + w = p->n_left; + if (w->n_op == ICON && w->n_type == STRTY) + return; + /* index all xasm args first */ + for (; w->n_op == CM; w = w->n_left) + nn++; + ary = tmpcalloc(nn * sizeof(NODE *)); + cwp = tmpcalloc(nn * sizeof(int)); + for (i = 0, w = p->n_left; w->n_op == CM; w = w->n_left) { + ary[i] = w->n_right; + cwp[i] = xasmcode(ary[i]->n_name); + i++; + } + ary[i] = w; + cwp[i] = xasmcode(ary[i]->n_name); + for (i = 0; i < nn; i++) + if (XASMVAL(cwp[i]) == 't' || XASMVAL(cwp[i]) == 'u') + break; + if (i == nn) + return; + + for (i = 0; i < nn; i++) { + c = XASMVAL(cwp[i]); + if (c >= '0' && c <= '9') + cwp[i] = (cwp[i] & ~0377) | XASMVAL(cwp[c-'0']); + } + infargs(ip, ary, nn, cwp, 'u'); + infargs(ip, ary, nn, cwp, 't'); + outfargs(ip, ary, nn, cwp, 't'); + outfargs(ip, ary, nn, cwp, 'u'); +} + +static NODE * +lptr(NODE *p) +{ + if (p->n_op == ASSIGN && p->n_right->n_op == REG && + regno(p->n_right) == EBP) + return p->n_right; + if (p->n_op == FUNARG && p->n_left->n_op == REG && + regno(p->n_left) == EBP) + return p->n_left; + return NIL; +} + +/* + * Find arg reg that should be struct reference instead. + */ +static void +updatereg(NODE *p, void *arg) +{ + NODE *q; + + if (p->n_op != STCALL) + return; +#if defined(os_openbsd) + struct attr *ap = attr_find(p->n_ap, ATTR_P2STRUCT); + if (ap->iarg(0) == 1 || ap->iarg(0) == 2 || ap->iarg(0) == 4 || + ap->iarg(0) == 8) + return; +#endif + if (attr_find(p->n_ap, ATTR_I386_FCMPLRET)) + return; + + if (p->n_right->n_op != CM) + p = p->n_right; + else for (p = p->n_right; + p->n_op == CM && p->n_left->n_op == CM; p = p->n_left) + ; + if (p->n_op == CM) { + if ((q = lptr(p->n_left))) + ; + else + q = lptr(p->n_right); + } else + q = lptr(p); + if (q == NIL) + comperr("bad STCALL hidden reg"); + + /* q is now the hidden arg */ + q->n_op = MINUS; + q->n_type = INCREF(CHAR); + q->n_left = mklnode(REG, 0, EBP, INCREF(CHAR)); + q->n_right = mklnode(ICON, stkpos, 0, INT); +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + stkpos = p2autooff; + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, fixcalls, 0); + storefloat(ip, ip->ip_node); + if (ip->ip_node->n_op == XASM) + fixxfloat(ip, ip->ip_node); + } + if (stkpos != p2autooff) { + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, updatereg, 0); + } + } + if (stkpos > p2autooff) + p2autooff = stkpos; + if (stkpos > p2maxautooff) + p2maxautooff = stkpos; + if (x2debug) + printip(ipole); +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE *p, void *arg) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2, 0); +} + +void +myoptim(struct interpass *ip) +{ +} + +static char rl[] = + { EAX, EAX, EAX, EAX, EAX, EDX, EDX, EDX, EDX, ECX, ECX, ECX, EBX, EBX, ESI }; +static char rh[] = + { EDX, ECX, EBX, ESI, EDI, ECX, EBX, ESI, EDI, EBX, ESI, EDI, ESI, EDI, EDI }; + +void +rmove(int s, int d, TWORD t) +{ + int sl, sh, dl, dh; + + switch (t) { + case LONGLONG: + case ULONGLONG: +#if 1 + sl = rl[s-EAXEDX]; + sh = rh[s-EAXEDX]; + dl = rl[d-EAXEDX]; + dh = rh[d-EAXEDX]; + + /* sanity checks, remove when satisfied */ + if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 || + memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0) + comperr("rmove source error"); + if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 || + memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0) + comperr("rmove dest error"); +#define SW(x,y) { int i = x; x = y; y = i; } + if (sh == dl) { + /* Swap if overwriting */ + SW(sl, sh); + SW(dl, dh); + } + if (sl != dl) + printf(" movl %s,%s\n", rnames[sl], rnames[dl]); + if (sh != dh) + printf(" movl %s,%s\n", rnames[sh], rnames[dh]); +#else + if (memcmp(rnames[s], rnames[d], 3) != 0) + printf(" movl %%%c%c%c,%%%c%c%c\n", + rnames[s][0],rnames[s][1],rnames[s][2], + rnames[d][0],rnames[d][1],rnames[d][2]); + if (memcmp(&rnames[s][3], &rnames[d][3], 3) != 0) + printf(" movl %%%c%c%c,%%%c%c%c\n", + rnames[s][3],rnames[s][4],rnames[s][5], + rnames[d][3],rnames[d][4],rnames[d][5]); +#endif + break; + case CHAR: + case UCHAR: + printf(" movb %s,%s\n", rnames[s], rnames[d]); + break; + case FLOAT: + case DOUBLE: + case LDOUBLE: +#ifdef notdef + /* a=b()*c(); will generate this */ + comperr("bad float rmove: %d %d", s, d); +#endif + break; + default: + printf(" movl %s,%s\n", rnames[s], rnames[d]); + } +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int c, int *r) +{ + int num; + + switch (c) { + case CLASSA: + num = r[CLASSB] > 4 ? 4 : r[CLASSB]; + num += 2*r[CLASSC]; + num += r[CLASSA]; + return num < 6; + case CLASSB: + num = r[CLASSA]; + num += 2*r[CLASSC]; + num += r[CLASSB]; + return num < 4; + case CLASSC: + num = r[CLASSA]; + num += r[CLASSB] > 4 ? 4 : r[CLASSB]; + num += 2*r[CLASSC]; + return num < 5; + case CLASSD: + return r[CLASSD] < DREGCNT; + } + return 0; /* XXX gcc */ +} + +char *rnames[] = { + "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp", + "%al", "%ah", "%dl", "%dh", "%cl", "%ch", "%bl", "%bh", + "eaxedx", "eaxecx", "eaxebx", "eaxesi", "eaxedi", "edxecx", + "edxebx", "edxesi", "edxedi", "ecxebx", "ecxesi", "ecxedi", + "ebxesi", "ebxedi", "esiedi", + "%st0", "%st1", "%st2", "%st3", "%st4", "%st5", "%st6", "%st7", +}; + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t == CHAR || t == UCHAR) + return CLASSB; + if (t == LONGLONG || t == ULONGLONG) + return CLASSC; + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return CLASSD; + return CLASSA; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int nr = 0, size = 0; + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) { + if (p->n_right->n_op != ASSIGN) + size += argsiz(p->n_right); + else + nr = 1; + } + if (p->n_op != ASSIGN) + size += argsiz(p); + else + nr++; + if (op->n_op == STCALL) { + if (kflag) + nr--; + if (nr == 0) + size -= 4; /* XXX OpenBSD? */ + } + +#if defined(MACHOABI) + int newsize = (size + 15) & ~15; /* stack alignment */ + int align = newsize-size; + + if (align != 0) + printf(" subl $%d,%%esp\n", align); + + size=newsize; +#endif + + op->n_qual = size; /* XXX */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + int o = p->n_op; + + switch (shape) { + case SFUNCALL: + if (o == STCALL || o == USTCALL) + return SRREG; + break; + case SPCON: + if (o != ICON || p->n_name[0] || + getlval(p) < 0 || getlval(p) > 0x7fffffff) + break; + return SRDIR; + case SMIXOR: + return tshape(p, SZERO); + case SMILWXOR: + if (o != ICON || p->n_name[0] || + getlval(p) == 0 || getlval(p) & 0xffffffff) + break; + return SRDIR; + case SMIHWXOR: + if (o != ICON || p->n_name[0] || + getlval(p) == 0 || (getlval(p) >> 32) != 0) + break; + return SRDIR; + } + return SRNOPE; +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ +#define MSET(s,a) if (strcmp(str, s) == 0) \ + msettings = (msettings & ~MCPUMSK) | a + + MSET("arch=i386",MI386); + MSET("arch=i486",MI486); + MSET("arch=i586",MI586); + MSET("arch=i686",MI686); +} + +/* + * Do something target-dependent for xasm arguments. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + struct interpass *ip2; + int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 }; + NODE *in = 0, *ut = 0; + TWORD t; + char *w; + int reg; + int c, cw; + CONSZ v; + + cw = xasmcode(p->n_name); + if (cw & (XASMASG|XASMINOUT)) + ut = p->n_left; + if ((cw & XASMASG) == 0) + in = p->n_left; + + c = XASMVAL(cw); + switch (c) { + case 'D': reg = EDI; break; + case 'S': reg = ESI; break; + case 'a': reg = EAX; break; + case 'b': reg = EBX; break; + case 'c': reg = ECX; break; + case 'd': reg = EDX; break; + + case 't': + case 'u': + p->n_name = tmpstrdup(p->n_name); + w = strchr(p->n_name, XASMVAL(cw)); + *w = 'r'; /* now reg */ + return 1; + + case 'A': reg = EAXEDX; break; + case 'q': { + /* Set edges in MYSETXARG */ + if (p->n_left->n_op == REG || p->n_left->n_op == TEMP) + return 1; + t = p->n_left->n_type; + if (in && ut) + in = tcopy(in); + p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t); + if (ut) { + ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t)); + DLIST_INSERT_AFTER(ip, ip2, qelem); + } + if (in) { + ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t)); + DLIST_INSERT_BEFORE(ip, ip2, qelem); + } + return 1; + } + + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + if (p->n_left->n_op != ICON) { + if ((c = XASMVAL1(cw)) != 0) { + p->n_name++; + return 0; /* Try again */ + } + uerror("xasm arg not constant"); + } + v = getlval(p->n_left); + if ((c == 'K' && v < -128) || + (c == 'L' && v != 0xff && v != 0xffff) || + (c != 'K' && v < 0) || + (v > Cmax[c-'I'])) + uerror("xasm val out of range"); + p->n_name = "i"; + return 1; + + default: + return 0; + } + /* If there are requested either memory or register, delete memory */ + w = p->n_name = tmpstrdup(p->n_name); + if (*w == '=') + w++; + *w++ = 'r'; + *w = 0; + + t = p->n_left->n_type; + if (reg == EAXEDX) { + ; + } else { + if (t == CHAR || t == UCHAR) { + reg = reg * 2 + 8; + } + } + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) { + reg += 037; + } + + if (in && ut) + in = tcopy(in); + p->n_left = mklnode(REG, 0, reg, t); + if (ut) { + ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t)); + DLIST_INSERT_AFTER(ip, ip2, qelem); + } + if (in) { + ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t)); + DLIST_INSERT_BEFORE(ip, ip2, qelem); + } + return 1; +} + +void +targarg(char *w, void *arg) +{ + NODE **ary = arg; + NODE *p, *q; + + if (ary[(int)w[1]-'0'] == 0) + p = ary[(int)w[1]-'0'-1]->n_left; /* XXX */ + else + p = ary[(int)w[1]-'0']->n_left; + if (optype(p->n_op) != LTYPE) + comperr("bad xarg op %d", p->n_op); + q = tcopy(p); + if (q->n_op == REG) { + if (*w == 'k') { + q->n_type = INT; + } else if (*w != 'w') { + if (q->n_type > UCHAR) { + regno(q) = regno(q)*2+8; + if (*w == 'h') + regno(q)++; + } + q->n_type = INT; + } else + q->n_type = SHORT; + } + adrput(stdout, q); + tfree(q); +} + +/* + * target-specific conversion of numeric arguments. + */ +int +numconv(void *ip, void *p1, void *q1) +{ + NODE *p = p1, *q = q1; + int cw = xasmcode(q->n_name); + + switch (XASMVAL(cw)) { + case 'a': + case 'b': + case 'c': + case 'd': + p->n_name = tmpcalloc(2); + p->n_name[0] = (char)XASMVAL(cw); + return 1; + default: + return 0; + } +} + +static struct { + char *name; int num; +} xcr[] = { + { "eax", EAX }, + { "ebx", EBX }, + { "ecx", ECX }, + { "edx", EDX }, + { "esi", ESI }, + { "edi", EDI }, + { "ax", EAX }, + { "bx", EBX }, + { "cx", ECX }, + { "dx", EDX }, + { NULL, 0 }, +}; + +/* + * Check for other names of the xasm constraints registers. + */ + +/* + * Check for other names of the xasm constraints registers. + */ +int xasmconstregs(char *s) +{ + int i; + + if (strncmp(s, "st", 2) == 0) { + int off =0; + if (s[2] == '(' && s[4] == ')') + off = s[3] - '0'; + return ESIEDI + 1 + off; + } + + for (i = 0; xcr[i].name; i++) + if (strcmp(xcr[i].name, s) == 0) + return xcr[i].num; + return -1; +} + diff --git a/lang/pcc/pcc/arch/i386/macdefs.h b/lang/pcc/pcc/arch/i386/macdefs.h new file mode 100644 index 000000000..fb2e5339c --- /dev/null +++ b/lang/pcc/pcc/arch/i386/macdefs.h @@ -0,0 +1,371 @@ +/* $Id: macdefs.h,v 1.94 2016/03/05 15:31:24 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +#define ARGINIT 64 /* # bits above fp where arguments start */ +#define AUTOINIT 0 /* # bits below fp where automatics start */ + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZBOOL 8 +#define SZINT 32 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#ifdef MACHOABI +#define SZLDOUBLE 128 +#else +#define SZLDOUBLE 96 +#endif +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 64 +#define SZPOINT(t) 32 + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALBOOL 8 +#define ALINT 32 +#define ALFLOAT 32 +#define ALDOUBLE 32 +#ifdef MACHOABI +#define ALLDOUBLE 128 +#else +#define ALLDOUBLE 32 +#endif +#define ALLONG 32 +#define ALLONGLONG 32 +#define ALSHORT 16 +#define ALPOINT 32 +#undef ALSTRUCT /* Not defined if ELF ABI */ +#define ALSTACK 32 +#define ALMAX 128 /* not yet supported type */ + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT (-0x7fffffff-1) +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffff +#define MIN_LONG MIN_INT +#define MAX_LONG MAX_INT +#define MAX_ULONG MAX_UNSIGNED +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +/* Default char is signed */ +#undef CHAR_UNSIGNED +#define BOOL_TYPE UCHAR /* what used to store _Bool */ +#undef UNALIGNED_ACCESS +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#if defined(ELFABI) +#define LABFMT ".L%d" /* format for printing labels */ +#define STABLBL ".LL%d" /* format for stab (debugging) labels */ +#else +#define LABFMT "L%d" /* format for printing labels */ +#define STABLBL "LL%d" /* format for stab (debugging) labels */ +#endif +#ifdef LANG_F77 +#define BLANKCOMMON "_BLNK_" +#define MSKIREG (M(TYSHORT)|M(TYLONG)) +#define TYIREG TYLONG +#define FSZLENG FSZLONG +#define AUTOREG EBP +#define ARGREG EBP +#define ARGOFFSET 8 +#endif + +#ifdef MACHOABI +#define STAB_LINE_ABSOLUTE /* S_LINE fields use absolute addresses */ +#define MYALIGN /* user power-of-2 alignment */ +#endif + +#define BACKAUTO /* stack grows negatively for automatics */ +#define BACKTEMP /* stack grows negatively for temporaries */ + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_LE + +#define FINDMOPS /* i386 has instructions that modifies memory */ +#define CC_DIV_0 /* division by zero is safe in the compiler */ + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&03) +#define wdal(k) (BYTEOFF(k)==0) + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) +#define genfcall(a,b) gencall(a,b) + +#define szty(t) (((t) == DOUBLE || (t) == FLOAT || \ + (t) == LONGLONG || (t) == ULONGLONG) ? 2 : (t) == LDOUBLE ? 3 : 1) + +/* + * The x86 has a bunch of register classes, most of them interfering + * with each other. All registers are given a sequential number to + * identify it which must match rnames[] in local2.c. + * Class membership and overlaps are defined in the macros RSTATUS + * and ROVERLAP below. + * + * The classes used on x86 are: + * A - short and int regs + * B - char regs + * C - long long regs + * D - floating point + */ +#define EAX 000 /* Scratch and return register */ +#define EDX 001 /* Scratch and secondary return register */ +#define ECX 002 /* Scratch (and shift count) register */ +#define EBX 003 /* GDT pointer or callee-saved temporary register */ +#define ESI 004 /* Callee-saved temporary register */ +#define EDI 005 /* Callee-saved temporary register */ +#define EBP 006 /* Frame pointer */ +#define ESP 007 /* Stack pointer */ + +#define AL 010 +#define AH 011 +#define DL 012 +#define DH 013 +#define CL 014 +#define CH 015 +#define BL 016 +#define BH 017 + +#define EAXEDX 020 +#define EAXECX 021 +#define EAXEBX 022 +#define EAXESI 023 +#define EAXEDI 024 +#define EDXECX 025 +#define EDXEBX 026 +#define EDXESI 027 +#define EDXEDI 030 +#define ECXEBX 031 +#define ECXESI 032 +#define ECXEDI 033 +#define EBXESI 034 +#define EBXEDI 035 +#define ESIEDI 036 + +/* The 8 math registers in class D lacks names */ + +#define MAXREGS 047 /* 39 registers */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, 0, 0, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, + +#define ROVERLAP \ + /* 8 basic registers */\ + { AL, AH, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ + { DL, DH, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ + { CL, CH, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ + { BL, BH, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ + { EAXESI, EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\ + { EAXEDI, EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ + { -1 },\ + { -1 },\ +\ + /* 8 char registers */\ + { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ + { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ + { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ + { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ + { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ + { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ + { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ + { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ +\ + /* 15 long-long-emulating registers */\ + { EAX, AL, AH, EDX, DL, DH, EAXECX, EAXEBX, EAXESI, /* eaxedx */\ + EAXEDI, EDXECX, EDXEBX, EDXESI, EDXEDI, -1, },\ + { EAX, AL, AH, ECX, CL, CH, EAXEDX, EAXEBX, EAXESI, /* eaxecx */\ + EAXEDI, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ + { EAX, AL, AH, EBX, BL, BH, EAXEDX, EAXECX, EAXESI, /* eaxebx */\ + EAXEDI, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ + { EAX, AL, AH, ESI, EAXEDX, EAXECX, EAXEBX, EAXEDI, /* eaxesi */\ + EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\ + { EAX, AL, AH, EDI, EAXEDX, EAXECX, EAXEBX, EAXESI, /* eaxedi */\ + EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ + { EDX, DL, DH, ECX, CL, CH, EAXEDX, EAXECX, EDXEBX, /* edxecx */\ + EDXESI, EDXEDI, ECXEBX, ECXESI, ECXEDI, -1 },\ + { EDX, DL, DH, EBX, BL, BH, EAXEDX, EDXECX, EDXESI, /* edxebx */\ + EDXEDI, EAXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ + { EDX, DL, DH, ESI, EAXEDX, EDXECX, EDXEBX, EDXEDI, /* edxesi */\ + EAXESI, ECXESI, EBXESI, ESIEDI, -1 },\ + { EDX, DL, DH, EDI, EAXEDX, EDXECX, EDXEBX, EDXESI, /* edxedi */\ + EAXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ + { ECX, CL, CH, EBX, BL, BH, EAXECX, EDXECX, ECXESI, /* ecxebx */\ + ECXEDI, EAXEBX, EDXEBX, EBXESI, EBXEDI, -1 },\ + { ECX, CL, CH, ESI, EAXECX, EDXECX, ECXEBX, ECXEDI, /* ecxesi */\ + EAXESI, EDXESI, EBXESI, ESIEDI, -1 },\ + { ECX, CL, CH, EDI, EAXECX, EDXECX, ECXEBX, ECXESI, /* ecxedi */\ + EAXEDI, EDXEDI, EBXEDI, ESIEDI, -1 },\ + { EBX, BL, BH, ESI, EAXEBX, EDXEBX, ECXEBX, EBXEDI, /* ebxesi */\ + EAXESI, EDXESI, ECXESI, ESIEDI, -1 },\ + { EBX, BL, BH, EDI, EAXEBX, EDXEBX, ECXEBX, EBXESI, /* ebxedi */\ + EAXEDI, EDXEDI, ECXEDI, ESIEDI, -1 },\ + { ESI, EDI, EAXESI, EDXESI, ECXESI, EBXESI, /* esiedi */\ + EAXEDI, EDXEDI, ECXEDI, EBXEDI, -1 },\ +\ + /* The fp registers do not overlap with anything */\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 }, + + +/* Return a register class based on the type of the node */ +#define PCLASS(p) (p->n_type <= UCHAR ? SBREG : \ + (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SCREG : \ + (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SDREG : SAREG))) + +#define NUMCLASS 4 /* highest number of reg classes used */ + +int COLORMAP(int c, int *r); +#define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 31 ? CLASSC : CLASSD) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ +/* XXX - return char in al? */ +#define RETREG(x) (x == CHAR || x == UCHAR ? AL : \ + x == LONGLONG || x == ULONGLONG ? EAXEDX : \ + x == FLOAT || x == DOUBLE || x == LDOUBLE ? 31 : EAX) + +#if 0 +#define R2REGS 1 /* permit double indexing */ +#endif + +/* XXX - to die */ +#define FPREG EBP /* frame pointer */ +#define STKREG ESP /* stack pointer */ + +#define SHSTR (MAXSPECIAL+1) /* short struct */ +#define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */ +#define SPCON (MAXSPECIAL+3) /* positive nonnamed constant */ + +/* + * Specials that indicate the applicability of machine idioms. + */ +#define SMIXOR (MAXSPECIAL+4) +#define SMILWXOR (MAXSPECIAL+5) +#define SMIHWXOR (MAXSPECIAL+6) + +/* + * i386-specific symbol table flags. + */ +#define SSECTION SLOCAL1 +#define SSTDCALL SLOCAL2 +#define SDLLINDIRECT SLOCAL3 + +/* + * i386-specific interpass stuff. + */ + +#define TARGET_IPP_MEMBERS \ + int ipp_argstacksize; + +#define target_members_print_prolog(ipp) printf("%d", ipp->ipp_argstacksize) +#define target_members_print_epilog(ipp) printf("%d", ipp->ipp_argstacksize) +#define target_members_read_prolog(ipp) ipp->ipp_argstacksize = rdint(&p) +#define target_members_read_epilog(ipp) ipp->ipp_argstacksize = rdint(&p) + +#define HAVE_WEAKREF +#define TARGET_FLT_EVAL_METHOD 2 /* all as long double */ + +/* + * Extended assembler macros. + */ +void targarg(char *w, void *arg); +#define XASM_TARGARG(w, ary) \ + (w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' ? \ + w++, targarg(w, ary), 1 : 0) +int numconv(void *ip, void *p, void *q); +#define XASM_NUMCONV(ip, p, q) numconv(ip, p, q) +int xasmconstregs(char *); +#define XASMCONSTREGS(x) xasmconstregs(x) +#define MYSETXARG if (XASMVAL(cw) == 'q') { \ + c = 'r'; addalledges(&ablock[ESI]); addalledges(&ablock[EDI]); } + +#if defined(MACHOABI) +struct stub { + struct { struct stub *q_forw, *q_back; } link; + char *name; +}; +extern struct stub stublist; +extern struct stub nlplist; +void addstub(struct stub *list, char *name); +#endif + +/* -m flags */ +extern int msettings; +#define MI386 0x001 +#define MI486 0x002 +#define MI586 0x004 +#define MI686 0x008 +#define MCPUMSK 0x00f + +/* target specific attributes */ +#define ATTR_MI_TARGET ATTR_I386_FCMPLRET, ATTR_I386_FPPOP diff --git a/lang/pcc/pcc/arch/i386/order.c b/lang/pcc/pcc/arch/i386/order.c new file mode 100644 index 000000000..6f2c83494 --- /dev/null +++ b/lang/pcc/pcc/arch/i386/order.c @@ -0,0 +1,313 @@ +/* $Id: order.c,v 1.63 2015/11/17 19:19:40 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +#include + +int canaddr(NODE *); + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + return(0); /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + * Be careful about register classes, this is a place where classes change. + */ +void +offstar(NODE *p, int shape) +{ + NODE *r; + + if (x2debug) + printf("offstar(%p)\n", p); + + if (isreg(p)) + return; /* Is already OREG */ + + r = p->n_right; + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( r->n_op == ICON ){ + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + if (r->n_op == LS && r->n_right->n_op == ICON && + getlval(r->n_right) == 2 && p->n_op == PLUS) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + if (isreg(r->n_left) == 0) + (void)geninsn(r->n_left, INAREG); + return; + } + } + (void)geninsn(p, INAREG); +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + */ +void +myormake(NODE *q) +{ + NODE *p, *r; + + if (x2debug) + printf("myormake(%p)\n", q); + + p = q->n_left; + if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && + r->n_right->n_op == ICON && getlval(r->n_right) == 2 && + p->n_left->n_op == REG && r->n_left->n_op == REG) { + q->n_op = OREG; + setlval(q, 0); + q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0); + tfree(p); + } +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Turns currently anything into OREG on x86 */ + if (shape & SOREG) + return SROREG; + return SRNOPE; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + case OPLOG: + { + static struct rspecial s[] = { { NEVER, EAX }, { 0 } }; + return s; + } + + case STASG: + { + static struct rspecial s[] = { + { NEVER, EDI }, { NEVER, ESI }, + { NRIGHT, ESI }, { NOLEFT, ESI }, + { NOLEFT, ECX }, { NORIGHT, ECX }, + { NEVER, ECX }, { 0 } }; + return s; + } + + case STARG: + { + static struct rspecial s[] = { + { NEVER, EDI }, { NEVER, ECX }, + { NLEFT, ESI }, { 0 } }; + return s; + } + + case SCONV: + if ((q->ltype & (TINT|TUNSIGNED|TSHORT|TUSHORT)) && + q->rtype == (TCHAR|TUCHAR)) { + static struct rspecial s[] = { + { NOLEFT, ESI }, { NOLEFT, EDI }, { 0 } }; + return s; + } else if ((q->ltype & TINT) && + q->rtype == (TLONGLONG|TULONGLONG)) { + static struct rspecial s[] = { + { NLEFT, EAX }, { NRES, EAXEDX }, + { NEVER, EAX }, { NEVER, EDX }, { 0 } }; + return s; + } else if (q->ltype == TSHORT && + q->rtype == (TLONGLONG|TULONGLONG)) { + static struct rspecial s[] = { + { NRES, EAXEDX }, + { NEVER, EAX }, { NEVER, EDX }, { 0 } }; + return s; + } else if (q->ltype == TCHAR && + q->rtype == (TLONGLONG|TULONGLONG)) { + static struct rspecial s[] = { + { NRES, EAXEDX }, + { NEVER, EAX }, { NEVER, EDX }, { 0 } }; + return s; + } + break; + case DIV: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NEVER, AL }, { NEVER, AH }, + { NLEFT, AL }, { NRES, AL }, + { NORIGHT, AH }, { NORIGHT, AL }, { 0 } }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NLEFT, EAX }, { NRES, EAX }, + { NORIGHT, EDX }, { NORIGHT, EAX }, { 0 } }; + return s; + } else if (q->lshape & SCREG) { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NEVER, ECX }, { NRES, EAXEDX }, { 0 } }; + return s; + } + break; + case MOD: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NEVER, AL }, { NEVER, AH }, + { NLEFT, AL }, { NRES, AH }, + { NORIGHT, AH }, { NORIGHT, AL }, { 0 } }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NLEFT, EAX }, { NRES, EDX }, + { NORIGHT, EDX }, { NORIGHT, EAX }, { 0 } }; + return s; + } else if (q->lshape & SCREG) { + static struct rspecial s[] = { + { NEVER, EAX }, { NEVER, EDX }, + { NEVER, ECX }, { NRES, EAXEDX }, { 0 } }; + return s; + } + break; + case MUL: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NEVER, AL }, { NEVER, AH }, + { NLEFT, AL }, { NRES, AL }, { 0 } }; + return s; + } else if (q->lshape & SCREG) { + static struct rspecial s[] = { + { NLEFT, EAXEDX }, { NRIGHT, ECXESI }, + { NEVER, ESI }, { NRES, EAXEDX }, { 0 } }; + return s; + } + break; + case LS: + case RS: + if (q->visit & (INAREG|INBREG)) { + static struct rspecial s[] = { + { NRIGHT, CL }, { NOLEFT, ECX }, { 0 } }; + return s; + } else if (q->visit & INCREG) { + static struct rspecial s[] = { + { NLEFT, EAXEDX }, { NRIGHT, CL }, + { NRES, EAXEDX }, { 0 } }; + return s; + } + break; + + default: + break; + } + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; /* nothing differs on x86 */ +} + +/* + * set registers in calling conventions live. + */ +int * +livecall(NODE *p) +{ + static int r[] = { EAX, EBX, -1 }; + int off = 1; + +#ifdef TLS + if (p->n_left->n_op == ICON && + strcmp(p->n_left->n_name, "___tls_get_addr@PLT") == 0) + off--; +#endif + + return kflag ? &r[off] : &r[2]; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/i386/table.c b/lang/pcc/pcc/arch/i386/table.c new file mode 100644 index 000000000..7f2c28761 --- /dev/null +++ b/lang/pcc/pcc/arch/i386/table.c @@ -0,0 +1,1622 @@ +/* $Id: table.c,v 1.144 2015/10/07 11:30:21 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +# define TLL TLONGLONG|TULONGLONG +# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR +# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR +# define ANYFIXED ANYSIGNED|ANYUSIGNED +# define TUWORD TUNSIGNED|TULONG +# define TSWORD TINT|TLONG +# define TWORD TUWORD|TSWORD +#define SHINT SAREG /* short and int */ +#define ININT INAREG +#define SHCH SBREG /* shape for char */ +#define INCH INBREG +#define SHLL SCREG /* shape for long long */ +#define INLL INCREG +#define SHFL SDREG /* shape for float/double */ +#define INFL INDREG /* shape for float/double */ + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are usually not necessary */ +{ PCONV, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + "", }, + +/* + * A bunch conversions of integral<->integral types + * There are lots of them, first in table conversions to itself + * and then conversions from each type to the others. + */ + +/* itself to itself, including pointers */ + +/* convert (u)char to (u)char. */ +{ SCONV, INCH, + SHCH, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR, + 0, RLEFT, + "", }, + +/* convert pointers to int. */ +{ SCONV, ININT, + SHINT, TPOINT|TWORD, + SANY, TWORD, + 0, RLEFT, + "", }, + +/* convert (u)longlong to (u)longlong. */ +{ SCONV, INLL, + SHLL, TLL, + SHLL, TLL, + 0, RLEFT, + "", }, + +/* convert between float/double/long double. */ +{ SCONV, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + "ZI", }, + +/* convert pointers to pointers. */ +{ SCONV, ININT, + SHINT, TPOINT, + SANY, TPOINT, + 0, RLEFT, + "", }, + +/* char to something */ + +/* convert char to (unsigned) short. */ +{ SCONV, ININT, + SBREG|SOREG|SNAME, TCHAR, + SAREG, TSHORT|TUSHORT, + NASL|NAREG, RESC1, + " movsbw AL,A1\n", }, + +/* convert unsigned char to (u)short. */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TUCHAR, + SAREG, TSHORT|TUSHORT, + NASL|NAREG, RESC1, + " movzbw AL,A1\n", }, + +/* convert signed char to int (or pointer). */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TCHAR, + SAREG, TWORD|TPOINT, + NASL|NAREG, RESC1, + " movsbl AL,A1\n", }, + +/* convert unsigned char to (u)int. */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TUCHAR, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movzbl AL,A1\n", }, + +/* convert char to (u)long long */ +{ SCONV, INLL, + SHCH|SOREG|SNAME, TCHAR, + SANY, TLL, + NSPECIAL|NCREG|NCSL, RESC1, + " movsbl AL,%eax\n cltd\n", }, + +/* convert unsigned char to (u)long long */ +{ SCONV, INLL, + SHCH|SOREG|SNAME, TUCHAR, + SANY, TLL, + NCREG|NCSL, RESC1, + " movzbl AL,A1\n xorl U1,U1\n", }, + +/* convert char (in register) to double XXX - use NTEMP */ +{ SCONV, INFL, + SHCH|SOREG|SNAME, TCHAR, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG, RESC2, + " movsbl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* convert (u)char (in register) to double XXX - use NTEMP */ +{ SCONV, INFL, + SHCH|SOREG|SNAME, TUCHAR, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG, RESC2, + " movzbl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* short to something */ + +/* convert (u)short to (u)short. */ +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RLEFT, + "", }, + +/* convert short (in memory) to char */ +{ SCONV, INCH, + SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + " movb AL,A1\n", }, + +/* convert short (in reg) to char. */ +{ SCONV, INCH, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL|NBREG|NBSL, RESC1, + "ZM", }, + +/* convert short to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movswl AL,A1\n", }, + +/* convert unsigned short to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TUSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movzwl AL,A1\n", }, + +/* convert short to (u)long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TSHORT, + SHLL, TLL, + NSPECIAL|NCREG|NCSL, RESC1, + " movswl AL,%eax\n cltd\n", }, + +/* convert unsigned short to (u)long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TUSHORT, + SHLL, TLL, + NCREG|NCSL, RESC1, + " movzwl AL,A1\n xorl U1,U1\n", }, + +/* convert short (in memory) to float/double */ +{ SCONV, INFL, + SOREG|SNAME, TSHORT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fild AL\n", }, + +/* convert short (in register) to float/double */ +{ SCONV, INFL, + SAREG, TSHORT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushw AL\n fild (%esp)\n addl $2,%esp\n", }, + +/* convert unsigned short to double XXX - use NTEMP */ +{ SCONV, INFL, + SAREG|SOREG|SNAME, TUSHORT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG|NTEMP, RESC2, + " movzwl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* int to something */ + +/* convert int to char. This is done when register is loaded */ +{ SCONV, INCH, + SAREG, TWORD|TPOINT, + SANY, TCHAR|TUCHAR, + NSPECIAL|NBREG|NBSL, RESC1, + "ZM", }, + +/* convert int to short. Nothing to do */ +{ SCONV, INAREG, + SAREG, TWORD|TPOINT, + SANY, TSHORT|TUSHORT, + 0, RLEFT, + "", }, + +/* convert signed int to (u)long long */ +{ SCONV, INLL, + SHINT, TSWORD, + SHLL, TLL, + NSPECIAL|NCREG|NCSL, RESC1, + " cltd\n", }, + +/* convert unsigned int to (u)long long */ +{ SCONV, INLL, + SHINT|SOREG|SNAME, TUWORD|TPOINT, + SHLL, TLL, + NCSL|NCREG, RESC1, + " movl AL,A1\n xorl U1,U1\n", }, + +/* convert signed int (in memory) to double */ +{ SCONV, INFL, + SOREG|SNAME, TSWORD, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fildl AL\n", }, + +/* convert signed int (in register) to double */ +{ SCONV, INFL, + SAREG, TSWORD, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " pushl AL\n fildl (%esp)\n addl $4,%esp\n", }, + +/* convert unsigned int (reg&mem) to double */ +{ SCONV, INFL, + SOREG|SNAME|SAREG, TUWORD, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " pushl $0\n" + " pushl AL\n" + " fildq (%esp)\n" + " addl $8,%esp\n", }, + +/* long long to something */ + +/* convert (u)long long to (u)char (mem->reg) */ +{ SCONV, INCH, + SOREG|SNAME, TLL, + SANY, TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + " movb AL,A1\n", }, + +/* convert (u)long long to (u)char (reg->reg, hopefully nothing) */ +{ SCONV, INCH, + SHLL, TLL, + SANY, TCHAR|TUCHAR, + NBREG|NBSL|NTEMP, RESC1, + "ZS", }, + +/* convert (u)long long to (u)short (mem->reg) */ +{ SCONV, INAREG, + SOREG|SNAME, TLL, + SAREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " movw AL,A1\n", }, + +/* convert (u)long long to (u)short (reg->reg, hopefully nothing) */ +{ SCONV, INAREG, + SHLL|SOREG|SNAME, TLL, + SAREG, TSHORT|TUSHORT, + NAREG|NASL|NTEMP, RESC1, + "ZS", }, + +/* convert long long to int (mem->reg) */ +{ SCONV, INAREG, + SOREG|SNAME, TLL, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +/* convert long long to int (reg->reg, hopefully nothing) */ +{ SCONV, INAREG, + SHLL|SOREG|SNAME, TLL, + SAREG, TWORD|TPOINT, + NAREG|NASL|NTEMP, RESC1, + "ZS", }, + +/* convert long long (in memory) to floating */ +{ SCONV, INFL, + SOREG|SNAME, TLONGLONG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fildq AL\n", }, + +/* convert long long (in register) to floating */ +{ SCONV, INFL, + SHLL, TLONGLONG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushl UL\n pushl AL\n" + " fildq (%esp)\n addl $8,%esp\n", }, + +/* convert unsigned long long to floating */ +{ SCONV, INFL, + SCREG, TULONGLONG, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + "ZJ", }, + +/* float to something */ + +#if 0 /* go via int by adding an extra sconv in clocal() */ +/* convert float/double to (u) char. XXX should use NTEMP here */ +{ SCONV, INCH, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NBREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, + +/* convert float/double to (u) int/short/char. XXX should use NTEMP here */ +{ SCONV, INCH, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NCREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, +#endif + +/* convert float/double to int. XXX should use NTEMP here */ +{ SCONV, INAREG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SAREG, TSWORD, + NAREG, RESC1, + " subl $12,%esp\n" + " fnstcw (%esp)\n" + " fnstcw 4(%esp)\n" + " movb $12,1(%esp)\n" + " fldcw (%esp)\n" + " fistpl 8(%esp)\n" + " movl 8(%esp),A1\n" + " fldcw 4(%esp)\n" + " addl $12,%esp\n", }, + +/* convert float/double to unsigned int. XXX should use NTEMP here */ +{ SCONV, INAREG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SAREG, TUWORD, + NAREG, RESC1, + " subl $16,%esp\n" + " fnstcw (%esp)\n" + " fnstcw 4(%esp)\n" + " movb $12,1(%esp)\n" + " fldcw (%esp)\n" + " fistpq 8(%esp)\n" + " movl 8(%esp),A1\n" + " fldcw 4(%esp)\n" + " addl $16,%esp\n", }, + +/* convert float/double (in register) to long long */ +{ SCONV, INLL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHLL, TLONGLONG, + NCREG, RESC1, + " subl $16,%esp\n" + " fnstcw (%esp)\n" + " fnstcw 4(%esp)\n" + " movb $12,1(%esp)\n" + " fldcw (%esp)\n" + " fistpq 8(%esp)\n" + " movl 8(%esp),A1\n" + " movl 12(%esp),U1\n" + " fldcw 4(%esp)\n" + " addl $16,%esp\n", }, + +/* convert float/double (in register) to unsigned long long */ +{ SCONV, INLL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHLL, TULONGLONG, + NCREG, RESC1, + " subl $16,%esp\n" + " fnstcw (%esp)\n" + " fnstcw 4(%esp)\n" + " movb $7,1(%esp)\n" /* 64-bit, round down */ + " fldcw (%esp)\n" + " movl $0x5f000000, 8(%esp)\n" /* (float)(1<<63) */ + " fsubs 8(%esp)\n" /* keep in range of fistpq */ + " fistpq 8(%esp)\n" + " xorb $0x80,15(%esp)\n" /* addq $1>>63 to 8(%esp) */ + " movl 8(%esp),A1\n" + " movl 12(%esp),U1\n" + " fldcw 4(%esp)\n" + " addl $16,%esp\n", }, + + + +/* slut sconv */ + +/* + * Subroutine calls. + */ + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " call CL\nZC", }, + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " call CL\nZC", }, + +{ UCALL, FOREFF, + SCON, TANY, + SAREG, TWORD|TPOINT, + 0, 0, + " call CL\nZC", }, + +{ CALL, INAREG, + SCON, TANY, + SAREG, TSHORT|TUSHORT|TWORD|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INAREG, + SCON, TANY, + SAREG, TSHORT|TUSHORT|TWORD|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, TCHAR|TUCHAR, + NBREG, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INBREG, + SCON, TANY, + SBREG, TCHAR|TUCHAR, + NBREG, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, INDREG, + SCON, TANY, + SDREG, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INDREG, + SCON, TANY, + SDREG, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ CALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INDREG, + SAREG, TANY, + SANY, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INDREG, + SAREG, TANY, + SANY, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ STCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + " call CL\nZC", }, + +{ STCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ STCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +/* + * The next rules handle all binop-style operators. + */ +/* Special treatment for long long */ +{ PLUS, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " addl AR,AL\n adcl UR,UL\n", }, + +{ PLUS, INLL|FOREFF, + SHLL|SNAME|SOREG, TLL, + SHLL|SCON, TLL, + 0, RLEFT, + " addl AR,AL\n adcl UR,UL\n", }, + +/* Special treatment for long long XXX - fix commutative check */ +{ PLUS, INLL|FOREFF, + SHLL|SNAME|SOREG, TLL, + SHLL, TLL, + 0, RRIGHT, + " addl AL,AR\n adcl UL,UR\n", }, + +{ PLUS, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " faddl AR\n", }, + +{ PLUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " faddp\n", }, + +{ PLUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SONE, TANY, + 0, RLEFT, + " incl AL\n", }, + +{ PLUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SONE, TANY, + 0, RLEFT, + " incw AL\n", }, + +{ PLUS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SONE, TANY, + 0, RLEFT, + " incb AL\n", }, + +{ PLUS, INAREG, + SAREG, TWORD, + SAREG, TWORD, + NAREG|NASL|NASR, RESC1, + " leal (AL,AR),A1\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SONE, TANY, + 0, RLEFT, + " decl AL\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SONE, TANY, + 0, RLEFT, + " decw AL\n", }, + +{ MINUS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SONE, TANY, + 0, RLEFT, + " decb AL\n", }, + +/* address as register offset, negative */ +{ MINUS, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " subl AR,AL\n sbbl UR,UL\n", }, + +{ MINUS, INLL|FOREFF, + SHLL|SNAME|SOREG, TLL, + SHLL|SCON, TLL, + 0, RLEFT, + " subl AR,AL\n sbbl UR,UL\n", }, + +{ MINUS, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fsubl AR\n", }, + +{ MINUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fsubZAp\n", }, + +/* Simple r/m->reg ops */ +/* m/r |= r */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT|RESCC, + " Ol AR,AL\n", }, + +/* r |= r/m */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RLEFT|RESCC, + " Ol AR,AL\n", }, + +/* m/r |= r */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + SHINT, TSHORT|TUSHORT, + 0, RLEFT|RESCC, + " Ow AR,AL\n", }, + +/* r |= r/m */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SHINT, TSHORT|TUSHORT, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + 0, RLEFT|RESCC, + " Ow AR,AL\n", }, + +/* m/r |= r */ +{ OPSIMP, INCH|FOREFF|FORCC, + SHCH, TCHAR|TUCHAR, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + " Ob AR,AL\n", }, + +/* r |= r/m */ +{ OPSIMP, INCH|FOREFF|FORCC, + SHCH, TCHAR|TUCHAR, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + " Ob AR,AL\n", }, + +/* m/r |= const */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SCON, TWORD|TPOINT, + 0, RLEFT|RESCC, + " Ol AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF|FORCC, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RLEFT|RESCC, + " Ow AR,AL\n", }, + +{ OPSIMP, INCH|FOREFF|FORCC, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT|RESCC, + " Ob AR,AL\n", }, + +/* r |= r/m */ +{ OPSIMP, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " Ol AR,AL\n Ol UR,UL\n", }, + +/* m/r |= r/const */ +{ OPSIMP, INLL|FOREFF, + SHLL|SNAME|SOREG, TLL, + SHLL|SCON, TLL, + 0, RLEFT, + " Ol AR,AL\n Ol UR,UL\n", }, + +/* Try use-reg instructions first */ +{ PLUS, INAREG, + SAREG, TWORD|TPOINT, + SCON, TANY, + NAREG|NASL, RESC1, + " leal CR(AL),A1\n", }, + +{ MINUS, INAREG, + SAREG, TWORD|TPOINT, + SPCON, TANY, + NAREG|NASL, RESC1, + " leal -CR(AL),A1\n", }, + + +/* + * The next rules handle all shift operators. + */ +/* (u)longlong left shift is emulated */ +{ LS, INCREG, + SCREG, TLL, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + "ZO", }, + +/* r/m <<= r */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sall AR,AL\n", }, + +/* r/m <<= const */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD, + SCON, TANY, + 0, RLEFT, + " sall AR,AL\n", }, + +/* r/m <<= r */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shlw AR,AL\n", }, + +/* r/m <<= const */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RLEFT, + " shlw AR,AL\n", }, + +{ LS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " salb AR,AL\n", }, + +{ LS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT, + " salb AR,AL\n", }, + +/* (u)longlong right shift is emulated */ +{ RS, INCREG, + SCREG, TLL, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + "ZO", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSWORD, + SCON, TANY, + 0, RLEFT, + " sarl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUWORD, + SCON, TANY, + 0, RLEFT, + " shrl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SCON, TANY, + 0, RLEFT, + " sarw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SCON, TANY, + 0, RLEFT, + " shrw AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SCON, TANY, + 0, RLEFT, + " sarb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SCON, TANY, + 0, RLEFT, + " shrb AR,AL\n", }, + +/* + * The next rules takes care of assignments. "=". + */ +{ ASSIGN, FORCC|FOREFF|INLL, + SHLL, TLL, + SMIXOR, TANY, + 0, RDEST, + " xorl AL,AL\n xorl UL,UL\n", }, + +{ ASSIGN, FORCC|FOREFF|INLL, + SHLL, TLL, + SMILWXOR, TANY, + 0, RDEST, + " xorl AL,AL\n movl UR,UL\n", }, + +{ ASSIGN, FORCC|FOREFF|INLL, + SHLL, TLL, + SMIHWXOR, TANY, + 0, RDEST, + " movl AR,AL\n xorl UL,UL\n", }, + +{ ASSIGN, FOREFF|INLL, + SHLL, TLL, + SCON, TANY, + 0, RDEST, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF, + SHLL|SNAME|SOREG, TLL, + SCON, TANY, + 0, 0, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FORCC|FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SMIXOR, TANY, + 0, RDEST, + " xorl AL,AL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SCON, TANY, + 0, 0, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SCON, TANY, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FORCC|FOREFF|INAREG, + SAREG, TSHORT|TUSHORT, + SMIXOR, TANY, + 0, RDEST, + " xorw AL,AL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, 0, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RDEST, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, 0, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INCH, + SHCH, TCHAR|TUCHAR, + SCON, TANY, + 0, RDEST, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INLL, + SNAME|SOREG, TLL, + SHLL, TLL, + 0, RDEST, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF|INLL, + SHLL, TLL, + SHLL, TLL, + 0, RDEST, + "ZH", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RDEST, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF|INCH, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR|TWORD, + 0, RDEST, + " movb AR,AL\n", }, + +{ ASSIGN, INDREG|FOREFF, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + "", }, /* This will always be in the correct register */ + +/* order of table entries is very important here! */ +{ ASSIGN, INFL, + SNAME|SOREG, TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fstpt AL\n fldt AL\n", }, /* XXX */ + +{ ASSIGN, FOREFF, + SNAME|SOREG, TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstpt AL\n", }, + +{ ASSIGN, INFL, + SNAME|SOREG, TDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fstl AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstpl AL\n", }, + +{ ASSIGN, INFL, + SNAME|SOREG, TFLOAT, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fsts AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TFLOAT, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstps AL\n", }, +/* end very important order */ + +{ ASSIGN, INFL|FOREFF, + SHFL, TLDOUBLE, + SHFL|SOREG|SNAME, TLDOUBLE, + 0, RDEST, + " fldt AR\n", }, + +{ ASSIGN, INFL|FOREFF, + SHFL, TDOUBLE, + SHFL|SOREG|SNAME, TDOUBLE, + 0, RDEST, + " fldl AR\n", }, + +{ ASSIGN, INFL|FOREFF, + SHFL, TFLOAT, + SHFL|SOREG|SNAME, TFLOAT, + 0, RDEST, + " flds AR\n", }, + +/* Do not generate memcpy if return from funcall */ +#if 0 +{ STASG, INAREG|FOREFF, + SOREG|SNAME|SAREG, TPTRTO|TSTRUCT, + SFUNCALL, TPTRTO|TSTRUCT, + 0, RRIGHT, + "", }, +#endif + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG, TPTRTO|TANY, + NSPECIAL|NAREG, RDEST, + "F movl %esi,A1\nZQF movl A1,%esi\n", }, + +/* + * DIV/MOD/MUL + */ +/* long long div is emulated */ +{ DIV, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ DIV, INAREG, + SAREG, TSWORD, + SAREG|SNAME|SOREG, TWORD, + NSPECIAL, RDEST, + " cltd\n idivl AR\n", }, + +{ DIV, INAREG, + SAREG, TUWORD|TPOINT, + SAREG|SNAME|SOREG, TUWORD|TPOINT, + NSPECIAL, RDEST, + " xorl %edx,%edx\n divl AR\n", }, + +{ DIV, INAREG, + SAREG, TUSHORT, + SAREG|SNAME|SOREG, TUSHORT, + NSPECIAL, RDEST, + " xorl %edx,%edx\n divw AR\n", }, + +{ DIV, INCH, + SHCH, TUCHAR, + SHCH|SNAME|SOREG, TUCHAR, + NSPECIAL, RDEST, + " xorb %ah,%ah\n divb AR\n", }, + +{ DIV, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fdivl AR\n", }, + +{ DIV, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fdivZAp\n", }, + +/* (u)longlong mod is emulated */ +{ MOD, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ MOD, INAREG, + SAREG, TSWORD, + SAREG|SNAME|SOREG, TSWORD, + NAREG|NSPECIAL, RESC1, + " cltd\n idivl AR\n", }, + +{ MOD, INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG, TUWORD|TPOINT, + NAREG|NSPECIAL, RESC1, + " xorl %edx,%edx\n divl AR\n", }, + +{ MOD, INAREG, + SAREG, TUSHORT, + SAREG|SNAME|SOREG, TUSHORT, + NAREG|NSPECIAL, RESC1, + " xorl %edx,%edx\n divw AR\n", }, + +{ MOD, INCH, + SHCH, TUCHAR, + SHCH|SNAME|SOREG, TUCHAR, + NBREG|NSPECIAL, RESC1, + " xorb %ah,%ah\n divb AR\n", }, + +/* (u)longlong mul is emulated */ +{ MUL, INCREG, + SCREG, TLL, + SCREG, TLL, + NSPECIAL, RDEST, + "ZO", }, + +{ MUL, INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT, + " imull AR,AL\n", }, + +{ MUL, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + 0, RLEFT, + " imulw AR,AL\n", }, + +{ MUL, INCH, + SHCH, TCHAR|TUCHAR, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + NSPECIAL, RDEST, + " imulb AR\n", }, + +{ MUL, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fmull AR\n", }, + +{ MUL, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fmulp\n", }, + +/* + * Indirection operators. + */ +{ UMUL, INLL, + SANY, TANY, + SOREG, TLL, + NCREG, RESC1, + " movl UL,U1\n movl AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ UMUL, INCH, + SANY, TANY, + SOREG, TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + " movb AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " movw AL,A1\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TLDOUBLE, + NDREG|NDSL, RESC1, + " fldt AL\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TDOUBLE, + NDREG|NDSL, RESC1, + " fldl AL\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TFLOAT, + NDREG|NDSL, RESC1, + " flds AL\n", }, + +/* + * Logical/branching operators + */ + +/* Comparisions, take care of everything */ +{ OPLOG, FORCC, + SHLL|SOREG|SNAME, TLL, + SHLL, TLL, + 0, 0, + "ZD", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TWORD|TPOINT, + SCON|SAREG, TWORD|TPOINT, + 0, RESCC, + " cmpl AR,AL\n", }, + +#if 0 +{ OPLOG, FORCC, + SCON|SAREG, TWORD|TPOINT, + SAREG|SOREG|SNAME, TWORD|TPOINT, + 0, RESCC, + " cmpl AR,AL\n", }, +#endif + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + SCON|SAREG, TANY, + 0, RESCC, + " cmpw AR,AL\n", }, + +{ OPLOG, FORCC, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + SCON|SBREG, TANY, + 0, RESCC, + " cmpb AR,AL\n", }, + +{ OPLOG, FORCC, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NSPECIAL, RNOP, + "ZG", }, + +{ OPLOG, FORCC, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "diediedie!", }, + +/* AND/OR/ER/NOT */ +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TWORD, + SCON|SAREG, TWORD, + 0, RLEFT, + " andl AR,AL\n", }, + +{ AND, INCREG|FOREFF, + SCREG, TLL, + SCREG|SOREG|SNAME, TLL, + 0, RLEFT, + " andl AR,AL\n andl UR,UL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TWORD, + SAREG|SOREG|SNAME, TWORD, + 0, RLEFT, + " andl AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + SCON|SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " andw AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TSHORT|TUSHORT, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + 0, RLEFT, + " andw AR,AL\n", }, + +{ AND, INBREG|FOREFF, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + SCON|SBREG, TCHAR|TUCHAR, + 0, RLEFT, + " andb AR,AL\n", }, + +{ AND, INBREG|FOREFF, + SBREG, TCHAR|TUCHAR, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + 0, RLEFT, + " andb AR,AL\n", }, +/* AND/OR/ER/NOT */ + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jmp LL\n", }, + +#if defined(GCC_COMPAT) || defined(LANG_F77) +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " jmp *AL\n", }, +#endif + +/* + * Convert LTYPE to reg. + */ +{ OPLTYPE, FORCC|INLL, + SCREG, TLL, + SMIXOR, TANY, + NCREG, RESC1, + " xorl U1,U1\n xorl A1,A1\n", }, + +{ OPLTYPE, FORCC|INLL, + SCREG, TLL, + SMILWXOR, TANY, + NCREG, RESC1, + " movl UL,U1\n xorl A1,A1\n", }, + +{ OPLTYPE, FORCC|INLL, + SCREG, TLL, + SMIHWXOR, TANY, + NCREG, RESC1, + " xorl U1,U1\n movl AL,A1\n", }, + +{ OPLTYPE, INLL, + SANY, TANY, + SCREG, TLL, + NCREG, RESC1, + "ZK", }, + +{ OPLTYPE, INLL, + SANY, TANY, + SCON|SOREG|SNAME, TLL, + NCREG, RESC1, + " movl UL,U1\n movl AL,A1\n", }, + +{ OPLTYPE, FORCC|INAREG, + SAREG, TWORD|TPOINT, + SMIXOR, TANY, + NAREG|NASL, RESC1, + " xorl A1,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TWORD|TPOINT, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, + NBREG, RESC1, + " movb AL,A1\n", }, + +{ OPLTYPE, FORCC|INAREG, + SAREG, TSHORT|TUSHORT, + SMIXOR, TANY, + NAREG, RESC1, + " xorw A1,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT, + NAREG, RESC1, + " movw AL,A1\n", }, + +{ OPLTYPE, INDREG, + SANY, TLDOUBLE, + SOREG|SNAME, TLDOUBLE, + NDREG, RESC1, + " fldt AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TDOUBLE, + SOREG|SNAME, TDOUBLE, + NDREG, RESC1, + " fldl AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TFLOAT, + SOREG|SNAME, TFLOAT, + NDREG, RESC1, + " flds AL\n", }, + +/* Only used in ?: constructs. The stack already contains correct value */ +{ OPLTYPE, INDREG, + SANY, TFLOAT|TDOUBLE|TLDOUBLE, + SDREG, TFLOAT|TDOUBLE|TLDOUBLE, + NDREG, RESC1, + "", }, + +/* + * Negate a word. + */ + +{ UMINUS, INCREG|FOREFF, + SCREG, TLL, + SCREG, TLL, + 0, RLEFT, + " negl AL\n adcl $0,UL\n negl UL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + " negl AL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " negw AL\n", }, + +{ UMINUS, INBREG|FOREFF, + SBREG, TCHAR|TUCHAR, + SBREG, TCHAR|TUCHAR, + 0, RLEFT, + " negb AL\n", }, + +{ UMINUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fchs\n", }, + +{ COMPL, INCREG, + SCREG, TLL, + SANY, TANY, + 0, RLEFT, + " notl AL\n notl UL\n", }, + +{ COMPL, INAREG, + SAREG, TWORD, + SANY, TANY, + 0, RLEFT, + " notl AL\n", }, + +{ COMPL, INAREG, + SAREG, TSHORT|TUSHORT, + SANY, TANY, + 0, RLEFT, + " notw AL\n", }, + +{ COMPL, INBREG, + SBREG, TCHAR|TUCHAR, + SANY, TANY, + 0, RLEFT, + " notb AL\n", }, + +/* + * Arguments to functions. + */ +{ FUNARG, FOREFF, + SCON|SCREG|SNAME|SOREG, TLL, + SANY, TLL, + 0, RNULL, + " pushl UL\n pushl AL\n", }, + +{ FUNARG, FOREFF, + SCON|SAREG|SNAME|SOREG, TWORD|TPOINT, + SANY, TWORD|TPOINT, + 0, RNULL, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, RNULL, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SANY, TSHORT, + NAREG, 0, + " movswl AL,ZN\n pushl ZN\n", }, + +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SANY, TUSHORT, + NAREG, 0, + " movzwl AL,ZN\n pushl ZN\n", }, + +{ FUNARG, FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SANY, TCHAR, + NAREG, 0, + " movsbl AL,A1\n pushl A1\n", }, + +{ FUNARG, FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SANY, TUCHAR, + NAREG, 0, + " movzbl AL,A1\n pushl A1\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TDOUBLE, + SANY, TDOUBLE, + 0, 0, + " pushl UL\n pushl AL\n", }, + +{ FUNARG, FOREFF, + SDREG, TDOUBLE, + SANY, TDOUBLE, + 0, 0, + " subl $8,%esp\n fstpl (%esp)\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SDREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " subl $4,%esp\n fstps (%esp)\n", }, + +{ FUNARG, FOREFF, + SDREG, TLDOUBLE, + SANY, TLDOUBLE, + 0, 0, + " subl $12,%esp\n fstpt (%esp)\n", }, + +{ STARG, FOREFF, + SAREG, TPTRTO|TSTRUCT, + SANY, TSTRUCT, + NSPECIAL, 0, + "ZF", }, + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +/* { INIT, DF(INIT), }, */ + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/i86/TODO b/lang/pcc/pcc/arch/i86/TODO new file mode 100644 index 000000000..8edba2b19 --- /dev/null +++ b/lang/pcc/pcc/arch/i86/TODO @@ -0,0 +1,93 @@ + + +8086/80186 +---------- +Add CPU options +Make push immediate, imul, shift immediate and enter/leave 186 specific +Optimise >> 8 and friends as register moves (note that the core compiler +code also goes off and turns * 256 into << 8) + +Unstarted +--------- +Float + +Struct/Union testing + +Maths optimisation. Div/mul on 8086 are *slow* so generate stack/double and +other optimised forms + +Long helper methods (out of line 32bit mul etc) + +Make long long a class E with 64bit types and four virtual registers +rewritten as memory. + +Other call formats + +Optimisation +------------ +Avoid sp,bp set up if we can on entry/exit + +Delayed sp adjustments + +Don't adjust sp then reload it from bp! + +Register constant tracking (especially important as we often know where a +zero word or byte is and we can use it for push immediate #0) + +Spotting two halves of a 32bit value being the same and merging + +Allow moves between half registers and their full shadow (al->ax) for char +to short etc. How to balance compilers tendancy to allocate AL, AH, etc +which is good for register freedom and bad for chars ? + +Better uchar handling - if we allocated xL before xH somehow in all cases +then we would be able to do xL -> xX efficiently. + +We get very poor code because the compiler doesn't understand that type +converting al does not destroy al, only ah and the al/ax relationship. In +particular with char args it loves to write crap like + + + mov bl, 1 + ... + mov al, bl + cbw + push ax + mov al, bl + cbw + inc ax + push ax + +not + mov al, 1 + cbw + push ax + inc al + cbw + push ax + + + + + + + +Questions +--------- +An assembler programmer would not + + mov al, #14 + cbw + +but would + + mov ax, #0014 + +not obvious how we do that optimisation with pcc in all cases but its important + +Can we optimise compare with zero cases ? + +How do we make use of rep and loopXX, these are rather useful on 8086 but +need indexes to tend to use the right register + +Should there be a CPU type/feature match in table.c ? \ No newline at end of file diff --git a/lang/pcc/pcc/arch/i86/code.c b/lang/pcc/pcc/arch/i86/code.c new file mode 100644 index 000000000..02a221e11 --- /dev/null +++ b/lang/pcc/pcc/arch/i86/code.c @@ -0,0 +1,455 @@ +/* $Id: code.c,v 1.2 2014/11/11 07:43:07 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +/* + * Print out assembler segment name. + */ +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".TEXT"; break; + case DATA: + case LDATA: name = ".DATA"; break; + case UDATA: break; + case STRNG: + case RDATA: name = ".DATA"; break; + case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; + case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; + case NMSEG: + printf("\t.section %s,\"a%c\",@progbits\n", name, + cftnsp ? 'x' : 'w'); + return; + } + printf("\t%s\n", name); +} + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + char *name; + + if ((name = sp->soname) == NULL) + name = exname(sp->sname); + if (sp->sclass == EXTDEF) { + printf(" .globl %s\n", name); + } + if (sp->slevel == 0) + printf("%s:\n", name); + else + printf(LABFMT ":\n", sp->soffset); +} + +int structrettemp; + +/* + * code for the end of a function + * deals with struct return here + */ +void +efcode(void) +{ + extern int gotnr; + NODE *p, *q; + + gotnr = 0; /* new number for next fun */ + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + /* Create struct assignment */ + q = tempnode(structrettemp, PTR+STRTY, 0, cftnsp->sap); + q = buildtree(UMUL, q, NIL); + p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); + p = buildtree(UMUL, p, NIL); + p = buildtree(ASSIGN, q, p); + ecomp(p); + + /* put hidden arg in ax on return */ + q = tempnode(structrettemp, INT, 0, 0); + p = block(REG, NIL, NIL, INT, 0, 0); + regno(p) = AX; + ecomp(buildtree(ASSIGN, p, q)); +} + +static TWORD longregs[] = { AXDX, DXCX }; +static TWORD regpregs[] = { AX, DX, CX }; +static TWORD charregs[] = { AL, DL, CL }; + +/* + * code for the beginning of a function; a is an array of + * indices in symtab for the arguments; n is the number + * + * Classifying args on i386; not simple: + * - Args may be on stack or in registers (regparm) + * - There may be a hidden first arg, unless OpenBSD struct return. + * - Regparm syntax is not well documented. + * - There may be stdcall functions, where the called function pops stack + * - ...probably more + */ +void +bfcode(struct symtab **sp, int cnt) +{ + extern int argstacksize; +#ifdef GCC_COMPAT + struct attr *ap; +#endif + struct symtab *sp2; + extern int gotnr; + NODE *n, *p; + int i, regparmarg; + int argbase, nrarg, sz; + + argbase = ARGINIT; + nrarg = regparmarg = 0; + +#ifdef GCC_COMPAT + if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL) + cftnsp->sflags |= SSTDCALL; + if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM))) + regparmarg = ap->iarg(0); +#endif + + /* Function returns struct, create return arg node */ + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + { + if (regparmarg) { + n = block(REG, 0, 0, INT, 0, 0); + regno(n) = regpregs[nrarg++]; + } else { + n = block(OREG, 0, 0, INT, 0, 0); + n->n_lval = argbase/SZCHAR; + argbase += SZINT; + regno(n) = FPREG; + } + p = tempnode(0, INT, 0, 0); + structrettemp = regno(p); + p = buildtree(ASSIGN, p, n); + ecomp(p); + } + } + + /* + * Find where all params are so that they end up at the right place. + * At the same time recalculate their arg offset on stack. + * We also get the "pop size" for stdcall. + */ + for (i = 0; i < cnt; i++) { + sp2 = sp[i]; + sz = tsize(sp2->stype, sp2->sdf, sp2->sap); + + SETOFF(sz, SZINT); + + if (cisreg(sp2->stype) == 0 || + ((regparmarg - nrarg) * SZINT < sz)) { /* not in reg */ + sp2->soffset = argbase; + argbase += sz; + nrarg = regparmarg; /* no more in reg either */ + } else { /* in reg */ + sp2->soffset = nrarg; + nrarg += sz/SZINT; + sp2->sclass = REGISTER; + } + } + + /* + * Now (argbase - ARGINIT) is used space on stack. + * Move (if necessary) the args to something new. + */ + for (i = 0; i < cnt; i++) { + int reg, j; + + sp2 = sp[i]; + + if (ISSOU(sp2->stype) && sp2->sclass == REGISTER) { + /* must move to stack */ + sz = tsize(sp2->stype, sp2->sdf, sp2->sap); + SETOFF(sz, SZINT); + SETOFF(autooff, SZINT); + reg = sp2->soffset; + sp2->sclass = AUTO; + sp2->soffset = NOOFFSET; + oalloc(sp2, &autooff); + for (j = 0; j < sz/SZCHAR; j += 4) { + p = block(OREG, 0, 0, INT, 0, 0); + p->n_lval = sp2->soffset/SZCHAR + j; + regno(p) = FPREG; + n = block(REG, 0, 0, INT, 0, 0); + regno(n) = regpregs[reg++]; + p = block(ASSIGN, p, n, INT, 0, 0); + ecomp(p); + } + } else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) && + ((cqual(sp2->stype, sp2->squal) & VOL) == 0)) { + /* just put rest in temps */ + if (sp2->sclass == REGISTER) { + n = block(REG, 0, 0, sp2->stype, + sp2->sdf, sp2->sap); + if (ISLONGLONG(sp2->stype)|| sp2->stype == LONG || sp2->stype == ULONG) + regno(n) = longregs[sp2->soffset]; + else if (DEUNSIGN(sp2->stype) == CHAR || sp2->stype == BOOL) + regno(n) = charregs[sp2->soffset]; + else + regno(n) = regpregs[sp2->soffset]; + } else { + n = block(OREG, 0, 0, sp2->stype, + sp2->sdf, sp2->sap); + n->n_lval = sp2->soffset/SZCHAR; + regno(n) = FPREG; + } + p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap); + sp2->soffset = regno(p); + sp2->sflags |= STNODE; + n = buildtree(ASSIGN, p, n); + ecomp(n); + } + } + + argstacksize = 0; + if (cftnsp->sflags & SSTDCALL) { + argstacksize = (argbase - ARGINIT)/SZCHAR; + } + +} + + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ + printf("\t.asciz \"PCC: %s\"\n", VERSSTR); +} + +void +bjobcode(void) +{ + astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; +} + +/* + * Convert FUNARG to assign in case of regparm. + */ +static int regcvt, rparg; +static void +addreg(NODE *p) +{ + TWORD t; + NODE *q; + int sz, r; + + sz = tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR; + sz = (sz + 3) >> 2; /* sz in regs */ + if ((regcvt+sz) > rparg) { + regcvt = rparg; + return; + } + if (sz > 2) + uerror("cannot put struct in 3 regs (yet)"); + + if (sz == 2) + r = regcvt == 0 ? AXDX : DXCX; + else + r = regcvt == 0 ? AX : regcvt == 1 ? DX : CX; + + if (p->n_op == FUNARG) { + /* at most 2 regs */ + if (p->n_type < INT) { + p->n_left = ccast(p->n_left, INT, 0, 0, 0); + p->n_type = INT; + } + + p->n_op = ASSIGN; + p->n_right = p->n_left; + } else if (p->n_op == STARG) { + /* convert to ptr, put in reg */ + q = p->n_left; + t = sz == 2 ? LONGLONG : INT; + q = cast(q, INCREF(t), 0); + q = buildtree(UMUL, q, NIL); + p->n_op = ASSIGN; + p->n_type = t; + p->n_right = q; + } else + cerror("addreg"); + p->n_left = block(REG, 0, 0, p->n_type, 0, 0); + regno(p->n_left) = r; + regcvt += sz; +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + * Returns p. + */ +NODE * +funcode(NODE *p) +{ + extern int gotnr; +#ifdef GCC_COMPAT + struct attr *ap; +#endif + NODE *r, *l; + TWORD t = DECREF(DECREF(p->n_left->n_type)); + int stcall; + + stcall = ISSOU(t); + /* + * We may have to prepend: + * - Hidden arg0 for struct return (in reg or on stack). + * - ebx in case of PIC code. + */ + + /* Fix function call arguments. On x86, just add funarg */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + if (r->n_right->n_op != STARG) { + r->n_right = intprom(r->n_right); + r->n_right = block(FUNARG, r->n_right, NIL, + r->n_right->n_type, r->n_right->n_df, + r->n_right->n_ap); + } + } + if (r->n_op != STARG) { + l = talloc(); + *l = *r; + r->n_op = FUNARG; + r->n_left = l; + r->n_left = intprom(r->n_left); + r->n_type = r->n_left->n_type; + } + if (stcall) { + /* Prepend a placeholder for struct address. */ + /* Use BP, can never show up under normal circumstances */ + l = talloc(); + *l = *r; + r->n_op = CM; + r->n_right = l; + r->n_type = INT; + l = block(REG, 0, 0, INCREF(VOID), 0, 0); + regno(l) = BP; + l = block(FUNARG, l, 0, INCREF(VOID), 0, 0); + r->n_left = l; + } + +#ifdef GCC_COMPAT + if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM))) + rparg = ap->iarg(0); + else +#endif + rparg = 0; + + regcvt = 0; + if (rparg) + listf(p->n_right, addreg); + + return p; +} + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + +NODE * +builtin_return_address(const struct bitable *bt, NODE *a) +{ + int nframes; + NODE *f; + + if (a->n_op != ICON) + goto bad; + + nframes = (int)a->n_lval; + + tfree(a); + + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + + while (nframes--) + f = block(UMUL, f, NIL, PTR+VOID, 0, 0); + + f = block(PLUS, f, bcon(2), INCREF(PTR+VOID), 0, 0); + f = buildtree(UMUL, f, NIL); + + return f; +bad: + uerror("bad argument to __builtin_return_address"); + return bcon(0); +} + +NODE * +builtin_frame_address(const struct bitable *bt, NODE *a) +{ + int nframes; + NODE *f; + + if (a->n_op != ICON) + goto bad; + + nframes = (int)a->n_lval; + + tfree(a); + + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + + while (nframes--) + f = block(UMUL, f, NIL, PTR+VOID, 0, 0); + + return f; +bad: + uerror("bad argument to __builtin_frame_address"); + return bcon(0); +} + +/* + * Return "canonical frame address". + */ +NODE * +builtin_cfa(const struct bitable *bt, NODE *a) +{ + uerror("missing builtin_cfa"); + return bcon(0); +} + diff --git a/lang/pcc/pcc/arch/i86/flocal.c b/lang/pcc/pcc/arch/i86/flocal.c new file mode 100644 index 000000000..1cbe70ebd --- /dev/null +++ b/lang/pcc/pcc/arch/i86/flocal.c @@ -0,0 +1,231 @@ +/* $Id: flocal.c,v 1.1 2014/09/16 10:47:35 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 + +#include "defines.h" +#include "defs.h" + +void +prchars(int *s) +{ + printf("\t.byte 0%o,0%o\n", s[0], s[1]); +} + +void +setloc(int l) +{ + static int lastloc = -1; + static char *loctbl[] = + { "text", "data", "data", "data", "bss" }; + if (l == lastloc) + return; + printf("\t.%s\n", loctbl[l]); + lastloc = l; +} + +#ifdef FCOM + + +/* + 8086 - SPECIFIC PRINTING ROUTINES +*/ + +/* + * Called just before return from a subroutine. + */ +void +goret(int type) +{ +} + +/* + * Print out a label. + */ +void +prlabel(int k) +{ + printf(LABFMT ":\n", k); +} + +/* + * Print naming for location. + * name[0] is location type. + */ +void +prnloc(char *name) +{ + if (*name == '0') + setloc(DATA); + else + fatal("unhandled prnloc %c", *name); + printf("%s:\n", name+1); +} + +/* + * Print integer constant. + */ +void +prconi(FILE *fp, int type, ftnint n) +{ + fprintf(fp, "\t%s\t%ld\n", (type==TYSHORT ? ".word" : ".long"), n); +} + +/* + * Print address constant, given as a label number. + */ +void +prcona(ftnint a) +{ + printf("\t.long\t" LABFMT "\n", (int)a); +} + +/* + * Print out a floating constant. + */ +void +prconr(FILE *fp, int type, double x) +{ + fprintf(fp, "\t%s\t0f%e\n", (type==TYREAL ? ".float" : ".double"), x); +} + +void +preven(int k) +{ + if (k > 1) + printf("\t.align\t%d\n", k); +} + +/* + * Convert a tag and offset into the symtab table to a string. + * An external string is never longer than XL bytes. + */ +char * +memname(int stg, int mem) +{ +#define MLEN (XL + 10) + char *s = malloc(MLEN); + + switch(stg) { + case STGCOMMON: + case STGEXT: + snprintf(s, MLEN, "%s", varstr(XL, extsymtab[mem].extname)); + break; + + case STGBSS: + case STGINIT: + snprintf(s, MLEN, "v.%d", mem); + break; + + case STGCONST: + snprintf(s, MLEN, ".L%d", mem); + break; + + case STGEQUIV: + snprintf(s, MLEN, "q.%d", mem); + break; + + default: + fatal1("memname: invalid vstg %d", stg); + } + return(s); +} + +void +prlocvar(char *s, ftnint len) +{ + printf("%s:\t.blkb\t%ld\n", s, len); +} + + +void +prext(char *name, ftnint leng, int init) +{ + if(leng == 0) + printf("\t.globl\t%s\n", name); + else + printf("%s:\t.blkb %ld\n", name, leng); +} + +void +prendproc(void) +{ +} + +void +prtail(void) +{ +} + +void +prolog(struct entrypoint *ep, struct bigblock *argvec) +{ + /* Ignore for now. ENTRY is not supported */ +} + +void +prdbginfo(void) +{ +} + +static void +fcheck(NODE *p, void *arg) +{ + NODE *r, *l; + + switch (p->n_op) { + case CALL: /* fix arguments */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + r->n_right = mkunode(FUNARG, r->n_right, 0, + r->n_right->n_type); + } + l = talloc(); + *l = *r; + r->n_op = FUNARG; + r->n_left = l; + r->n_type = l->n_type; + break; + } +} + +/* + * Called just before the tree is written out to pass2. + */ +void p2tree(NODE *p); +void +p2tree(NODE *p) +{ + walkf(p, fcheck, 0); +} +#endif /* FCOM */ diff --git a/lang/pcc/pcc/arch/i86/local.c b/lang/pcc/pcc/arch/i86/local.c new file mode 100644 index 000000000..c55f7a9a2 --- /dev/null +++ b/lang/pcc/pcc/arch/i86/local.c @@ -0,0 +1,634 @@ +/* $Id: local.c,v 1.3 2015/07/24 08:00:12 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +/* this file contains code which is dependent on the target machine */ + +#ifdef notyet +/* + * Check if a constant is too large for a type. + */ +static int +toolarge(TWORD t, CONSZ con) +{ + U_CONSZ ucon = con; + + switch (t) { + case ULONGLONG: + case LONGLONG: + break; /* cannot be too large */ +#define SCHK(i) case i: if (con > MAX_##i || con < MIN_##i) return 1; break +#define UCHK(i) case i: if (ucon > MAX_##i) return 1; break + SCHK(INT); + SCHK(SHORT); + case BOOL: + SCHK(CHAR); + UCHK(UNSIGNED); + UCHK(USHORT); + UCHK(UCHAR); + default: + cerror("toolarge"); + } + return 0; +} +#endif + +#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) + + +int gotnr; /* tempnum for GOT register */ +int argstacksize; + +/* clocal() is called to do local transformations on + * an expression tree preparitory to its being + * written out in intermediate code. + * + * the major essential job is rewriting the + * automatic variables and arguments in terms of + * REG and OREG nodes + * conversion ops which are not necessary are also clobbered here + * in addition, any special features (such as rewriting + * exclusive or) are easily handled here as well + */ +NODE * +clocal(NODE *p) +{ + + struct attr *ap; + register struct symtab *q; + register NODE *r, *l; + register int o; + register int m; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + switch( o = p->n_op ){ + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + r->n_lval = 0; + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case USTATIC: + break; + case STATIC: + break; + + case REGISTER: + p->n_op = REG; + p->n_lval = 0; + p->n_rval = q->soffset; + break; + + case EXTERN: + case EXTDEF: + break; + } + break; + + case ADDROF: + break; + + case UCALL: + break; + + case USTCALL: + /* Add hidden arg0 */ + r = block(REG, NIL, NIL, INCREF(VOID), 0, 0); + regno(r) = BP; + if ((ap = attr_find(p->n_ap, GCC_ATYP_REGPARM)) != NULL && + ap->iarg(0) > 0) { + l = block(REG, NIL, NIL, INCREF(VOID), 0, 0); + regno(l) = AX; + p->n_right = buildtree(ASSIGN, l, r); + } else + p->n_right = block(FUNARG, r, NIL, INCREF(VOID), 0, 0); + p->n_op -= (UCALL-CALL); + + if (kflag == 0) + break; + l = block(REG, NIL, NIL, INT, 0, 0); + regno(l) = BX; + r = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); + p->n_right = block(CM, r, p->n_right, INT, 0, 0); + break; + +#ifdef notyet + /* XXX breaks sometimes */ + case CBRANCH: + l = p->n_left; + + /* + * Remove unnecessary conversion ops. + */ + if (!clogop(l->n_op) || l->n_left->n_op != SCONV) + break; + if (coptype(l->n_op) != BITYPE) + break; + if (l->n_right->n_op != ICON) + break; + r = l->n_left->n_left; + if (r->n_type >= FLOAT) + break; + if (toolarge(r->n_type, l->n_right->n_lval)) + break; + l->n_right->n_type = r->n_type; + if (l->n_op >= ULE && l->n_op <= UGT) + l->n_op -= (UGT-ULE); + p->n_left = buildtree(l->n_op, r, l->n_right); + nfree(l->n_left); + nfree(l); + break; +#endif + + case PCONV: + l = p->n_left; + + /* Make int type before pointer */ + if (l->n_type < INT || l->n_type == LONGLONG || + l->n_type == ULONGLONG || l->n_type == BOOL) { + /* float etc? */ + p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); + } + break; + + case SCONV: + if (p->n_left->n_op == COMOP) + break; /* may propagate wrong type later */ + l = p->n_left; + + if (p->n_type == l->n_type) { + nfree(p); + return l; + } + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + tsize(p->n_type, p->n_df, p->n_ap) == + tsize(l->n_type, l->n_df, l->n_ap)) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + return l; + } + } + } + + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && + coptype(l->n_op) == BITYPE && l->n_op != COMOP && + l->n_op != QUEST) { + l->n_type = p->n_type; + nfree(p); + return l; + } + + o = l->n_op; + m = p->n_type; + + if (o == ICON) { + /* + * Can only end up here if o is an address, + * and in that case the only compile-time conversion + * possible is to int. + */ + if ((TMASK & l->n_type) == 0 && l->n_sp == NULL) + cerror("SCONV ICON"); + if (l->n_sp == 0) { + p->n_type = UNSIGNED; + concast(l, m); + } else if (m != INT && m != UNSIGNED) + break; + l->n_type = m; + l->n_ap = 0; + nfree(p); + return l; + } else if (l->n_op == FCON) + cerror("SCONV FCON"); + if ((p->n_type == CHAR || p->n_type == UCHAR || + p->n_type == SHORT || p->n_type == USHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left->n_type = INT; + return p; + } + break; + + case MOD: + case DIV: + if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) + break; + if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) + break; + /* make it an int division by inserting conversions */ + p->n_left = makety(p->n_left, INT, 0, 0, 0); + p->n_right = makety(p->n_right, INT, 0, 0, 0); + o = p->n_type; + p->n_type = INT; + p = makety(p, o, 0, 0, 0); + break; + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + p->n_left->n_rval = p->n_left->n_type == BOOL ? + RETREG(CHAR) : RETREG(p->n_type); + break; + + case LS: + case RS: + /* shift count must be in a char */ + if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR) + break; + p->n_right = block(SCONV, p->n_right, NIL, CHAR, 0, 0); + break; + } +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal end: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + return(p); +} + +static void mangle(NODE *p); + +void +myp2tree(NODE *p) +{ + struct symtab *sp; + + mangle(p); + + if (p->n_op != FCON) + return; + + sp = IALLOC(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->sap = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + sp->sname = sp->soname = NULL; + + locctr(DATA, sp); + defloc(sp); + ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + + p->n_op = NAME; + p->n_lval = 0; + p->n_sp = sp; +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * Return 1 if a variable of type type is OK to put in register. + */ +int +cisreg(TWORD t) +{ + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return 0; /* not yet */ + return 1; +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a storeable node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ + + /* sub the size from sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(MINUSEQ, sp, p)); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); + sp->n_lval = 0; + sp->n_rval = STKREG; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + +} + +/* + * print out a constant node, may be associated with a label. + * Do not free the node after use. + * off is bit offset from the beginning of the aggregate + * fsz is the number of bits this is referring to + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; long double l; int i[3]; } u; + int i; + + switch (p->n_type) { + case LONGLONG: + case ULONGLONG: + i = (int)(p->n_lval >> 32); + p->n_lval &= 0xffffffff; + p->n_type = INT; + inval(off, 32, p); + p->n_lval = i; + inval(off+32, 32, p); + break; + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)p->n_dcon; +#if defined(HOST_BIG_ENDIAN) + /* XXX probably broken on most hosts */ + printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]); +#else + printf("\t.long\t%d,%d,%d\n", u.i[0], u.i[1], u.i[2] & 0177777); +#endif + break; + case DOUBLE: + u.d = (double)p->n_dcon; +#if defined(HOST_BIG_ENDIAN) + printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]); +#else + printf("\t.long\t%d,%d\n", u.i[0], u.i[1]); +#endif + break; + case FLOAT: + u.f = (float)p->n_dcon; + printf("\t.long\t%d\n", u.i[0]); + break; + default: + return 0; + } + return 1; +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ +#define NCHNAM 256 + static char text[NCHNAM+1]; + int i; + + if (p == NULL) + return ""; + + text[0] = '_'; + for (i=1; *p && isoname) == NULL) + name = exname(sp->sname); + al = talign(sp->stype, sp->sap)/SZCHAR; + off = (int)tsize(sp->stype, sp->sdf, sp->sap); + SETOFF(off,SZCHAR); + off /= SZCHAR; + printf("\t.align %d\n", al); + printf("%s:\t.blkb %d\n", name, off); +} + +static int stdcall; +static char *alias; +static int constructor; +static int destructor; + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + char *a2 = pragtok(NULL); + + if (strcmp(str, "stdcall") == 0) { + stdcall = 1; + return 1; + } + if (strcmp(str, "cdecl") == 0) { + stdcall = 0; + return 1; + } +#ifndef AOUTABI + if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { + constructor = 1; + return 1; + } + if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { + destructor = 1; + return 1; + } +#endif + if (strcmp(str, "alias") == 0 && a2 != NULL) { + alias = tmpstrdup(a2); + return 1; + } + + return 0; +} + +/* + * Called when a identifier has been declared. + */ +void +fixdef(struct symtab *sp) +{ +#ifdef GCC_COMPAT + struct attr *ap; +#endif +#ifdef GCC_COMPAT +#ifdef HAVE_WEAKREF + /* not many as'es have this directive */ + if ((ap = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) { + char *wr = ap->sarg(0); + char *sn = sp->soname ? sp->soname : sp->sname; + if (sp->sclass != STATIC && sp->sclass != USTATIC) + uerror("weakref %s must be static", sp->sname); + if (wr == NULL) { + if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS))) { + wr = ap->sarg(0); + } + } + if (wr == NULL) + printf("\t.weak %s\n", sn); + else + printf("\t.weakref %s,%s\n", sn, wr); + } else +#endif + if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) { + char *an = ap->sarg(0); + char *sn = sp->soname ? sp->soname : sp->sname; + char *v; + + v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl"; + printf("\t.%s %s\n", v, sn); + printf("\t.set %s,%s\n", sn, an); + } +#endif + if (alias != NULL && (sp->sclass != PARAM)) { + char *name; + if ((name = sp->soname) == NULL) + name = exname(sp->sname); + printf("\t.globl %s\n", name); + printf("%s = ", name); + printf("%s\n", exname(alias)); + alias = NULL; + } + if ((constructor || destructor) && (sp->sclass != PARAM)) { + printf("\t.section .%ctors,\"w\"\n", + constructor ? 'c' : 'd'); + printf("\t.p2align 2\n"); + printf("\t.long %s\n", exname(sp->sname)); + printf("\t.previous\n"); + constructor = destructor = 0; + } + if (stdcall && (sp->sclass != PARAM)) { + sp->sflags |= SSTDCALL; + stdcall = 0; + } +} + +/* + * Postfix external functions with the arguments size. + */ +static void +mangle(NODE *p) +{ + NODE *l; + + if (p->n_op != CALL && p->n_op != STCALL && + p->n_op != UCALL && p->n_op != USTCALL) + return; + + l = p->n_left; + while (cdope(l->n_op) & CALLFLG) + l = l->n_left; + if (l->n_op == TEMP) + return; + if (l->n_op == ADDROF) + l = l->n_left; + if (l->n_sp == NULL) + return; +#ifdef GCC_COMPAT + if (attr_find(l->n_sp->sap, GCC_ATYP_STDCALL) != NULL) + l->n_sp->sflags |= SSTDCALL; +#endif +} + +void +pass1_lastchance(struct interpass *ip) +{ + if (ip->type == IP_NODE && + (ip->ip_node->n_op == CALL || ip->ip_node->n_op == UCALL) && + ISFTY(ip->ip_node->n_type)) + ip->ip_node->n_ap = attr_add(ip->ip_node->n_ap, + attr_new(ATTR_I86_FPPOP, 1)); + if (ip->type == IP_EPILOG) { + struct interpass_prolog *ipp = (struct interpass_prolog *)ip; + ipp->ipp_argstacksize = argstacksize; + } +} diff --git a/lang/pcc/pcc/arch/i86/local2.c b/lang/pcc/pcc/arch/i86/local2.c new file mode 100644 index 000000000..c32e8df1c --- /dev/null +++ b/lang/pcc/pcc/arch/i86/local2.c @@ -0,0 +1,1544 @@ +/* $Id: local2.c,v 1.7 2015/07/24 08:00:12 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" +# include +# include + +#define EXPREFIX "_" + +static int stkpos; + +static int suppress_type; /* Don't display a type on the + next expansion */ + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static int regoff[7]; +static TWORD ftype; + +/* + * Print out the prolog assembler. + * addto and regoff are already calculated. + */ +static void +prtprolog(struct interpass_prolog *ipp, int addto) +{ + int i; + +#if 1 + /* FIXME: can't use enter/leave if generating i8086 */ + if (addto == 0 || addto > 65535 || 1) { + printf(" push bp\n\tmov bp,sp\n"); + if (addto) + printf(" sub sp,#%d\n", addto); + } else + printf(" enter %d,0\n", addto); +#endif + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) + printf(" mov -%d[%s],%s\n", + regoff[i], rnames[FPREG], rnames[i]); +} + +/* + * calculate stack size and offsets + */ +static int +offcalc(struct interpass_prolog *ipp) +{ + int i, addto; + + addto = p2maxautooff; + if (addto >= AUTOINIT/SZCHAR) + addto -= AUTOINIT/SZCHAR; + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) { + addto += SZINT/SZCHAR; + regoff[i] = addto; + } + return addto; +} + +void +prologue(struct interpass_prolog *ipp) +{ + int addto; + + ftype = ipp->ipp_type; + +#ifdef LANG_F77 + if (ipp->ipp_vis) + printf(" .globl %s\n", ipp->ipp_name); + printf(" .align 4\n"); + printf("%s:\n", ipp->ipp_name); +#endif + /* + * We here know what register to save and how much to + * add to the stack. + */ + addto = offcalc(ipp); + prtprolog(ipp, addto); +} + +void +eoftn(struct interpass_prolog *ipp) +{ + int i; + + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + /* return from function code */ + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) + printf(" mov %s,-%d[%s]\n", + rnames[i],regoff[i], rnames[FPREG]); + + /* struct return needs special treatment */ + if (ftype == STRTY || ftype == UNIONTY) { + printf(" mov ax, 8[bp]\n"); + printf(" leave\n"); + /* FIXME: ret n is not in 8086 */ + printf(" ret %d\n", 4 + ipp->ipp_argstacksize); + } else { + printf(" mov sp, bp\n"); + printf(" pop bp\n"); + if (ipp->ipp_argstacksize) + /* CHECK ME */ + printf(" add sp, #%d\n", ipp->ipp_argstacksize); + printf(" ret\n"); + } +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s", str); /* don't need %c f as far as I can see */ +} + +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(NODE *p) +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + case INT: + case UNSIGNED: + return(SZINT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case LONG: + case ULONG: + return(SZLONG/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +/* + * Emit code to compare two long numbers. + */ +static void +twollcomp(NODE *p) +{ + int u; + int s = getlab2(); + int e = p->n_label; + int cb1, cb2; + + u = p->n_op; + switch (p->n_op) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + u += (ULE-LE); + /* FALLTHROUGH */ + case ULE: + case ULT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + u += (ULE-LE); + /* FALLTHROUGH */ + case UGE: + case UGT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 4, cb2 += 4; + expand(p, 0, " cmp UL,UR\n"); + if (cb1) cbgen(cb1, s); + if (cb2) cbgen(cb2, e); + expand(p, 0, " cmp AL,AR\n"); + cbgen(u, e); + deflab(s); +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + comperr("fldexpand"); + return 0; +} + +/* + * Push a structure on stack as argument. + * the scratch registers are already free here + */ +static void +starg(NODE *p) +{ + NODE *q = p->n_left; + int s = (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) + 1) & ~1; + + if (s == 2) + printf(" dec sp\n dec sp\n"); + else + printf(" sub sp,#%d\n", s); + p->n_left = mklnode(OREG, 0, SP, INT); + zzzcode(p, 'Q'); + tfree(p->n_left); + p->n_left = q; +} + +/* + * Compare two floating point numbers. + */ +static void +fcomp(NODE *p) +{ + static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" }; + + if ((p->n_su & DORIGHT) == 0) + expand(p, 0, "\tfxch\n"); + expand(p, 0, "\tfucomip %st(1),%st\n"); /* emit compare insn */ + expand(p, 0, "\tfstp %st(0)\n"); /* pop fromstack */ + + if (p->n_op == NE || p->n_op == GT || p->n_op == GE) + expand(p, 0, "\tjp LC\n"); + else if (p->n_op == EQ) + printf("\tjp 1f\n"); + printf(" %s ", fpcb[p->n_op - EQ]); + expand(p, 0, "LC\n"); + if (p->n_op == EQ) + printf("1:\n"); +} + +/* + * Convert an unsigned long long to floating point number. + */ +static void +ulltofp(NODE *p) +{ + int jmplab; + + jmplab = getlab2(); + expand(p, 0, " push UL\n push AL\n"); + expand(p, 0, " fildq [sp]\n"); + expand(p, 0, " add sp, #8\n"); + expand(p, 0, " cmp UL, #0\n"); + printf(" jge " LABFMT "\n", jmplab); + + printf(" faddp %%st,%%st(1)\n"); + printf(LABFMT ":\n", jmplab); +} + +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + if (t < LONG) + return 2; + if (t == LONG || t == ULONG || t == LONGLONG || t == ULONGLONG) + return 4; + if (t == FLOAT) + return 4; + if (t > BTMASK) + return 2; + if (t == DOUBLE) + return 8; + if (t == LDOUBLE) + return 12; + if (t == STRTY || t == UNIONTY) + return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+1) & ~1; + comperr("argsiz"); + return 0; +} + +static void +fcast(NODE *p) +{ + TWORD t = p->n_type; + int sz, c; + + if (t >= p->n_left->n_type) + return; /* cast to more precision */ + if (t == FLOAT) + sz = 4, c = 's'; + else + sz = 8, c = 'l'; + + printf(" sub sp, #%d\n", sz); + printf(" fstp%c (%%sp)\n", c); + printf(" fld%c (%%sp)\n", c); + printf(" add sp, #%d\n", sz); +} + + +#if 0 + +static void +llshft(NODE *p) +{ + NODE *r = p->n_right; + /* FIXME: we have sal/shl/sar/shr but we are limited to + shift right or left 1 + shift right or left by CL */ + char *d[3]; + /* We ought to shortcut this earlier but it's not obivous how + to do a match and say 'any old register pair' FIXME */ + if (r->n_op == ICON) { + /* FIXME: we need different versions of this for signed right + shifting. Just test code - register setup needs checking + for ordering etc yet */ + if (r->n_lval == 16) { + if (p->n_op == RS) + printf("\tmov ax, dx\n\txor dx,dx\n"); + else + printf("\tmov dx, ax\n\txor ax,ax\n"); + return; + } + if (r->n_lval == 8) { + if (p->n_op == RS) + printf("\tmov al, ah\n\tmov ah, dl\n\tmov dl, dh\n\txor dh,dh\n"); + else + printf("\tmov ah, al\n\tmov dl, ah\n\tmov dh, dl\n\txor al, al\n"); + return; + } + if (r->n_lval == 24) { + if (p->n_op == RS) + printf("\txor dx,dx\n\tmov al, dh\n\txor ax,ax\n"); + else + printf("\txor ax,ax\n\tmov dh, al\n\txor dx,dx\n"); + return; + } + } + if (p->n_op == LS) { + d[0] = "l", d[1] = "ax", d[2] = "dx"; + } else + d[0] = "r", d[1] = "dx", d[2] = "ax"; + + printf("\tsh%sdl %s,%s\n",d[0], d[1], d[2]); + printf("\ts%s%sl %%cl,%s\n", p->n_op == RS && + (p->n_left->n_type == ULONG || p->n_left->n_type == ULONGLONG) ? + "h" : "a", d[0], d[1]); + printf("\ttestb $16,%%cl\n"); + printf("\tje 1f\n"); + printf("\tmov %s,%s\n", d[1], d[2]); + if (p->n_op == RS && (p->n_left->n_type == LONGLONG|| p->n_left->n_type == LONG)) + printf("\tsarl $31,%%edx\n"); + else + printf("\txor %s,%s\n",d[1],d[1]); + printf("1:\n"); +} +#endif + +void +zzzcode(NODE *p, int c) +{ + struct attr *ap; + NODE *l; + int pr, lr; + char *ch; + char sv; + + switch (c) { + case 'A': /* swap st0 and st1 if right is evaluated second */ + if ((p->n_su & DORIGHT) == 0) { + if (logop(p->n_op)) + printf(" fxch\n"); + else + printf("r"); + } + break; + + case 'C': /* remove from stack after subroutine call */ +#ifdef notdef + if (p->n_left->n_flags & FSTDCALL) + break; +#endif + pr = p->n_qual; + if (attr_find(p->n_ap, ATTR_I86_FPPOP)) + printf(" fstp st(0)\n"); + if (p->n_op == UCALL) + return; /* XXX remove ZC from UCALL */ + if (pr) { + if (pr == 2) + printf(" inc sp\n inc sp\n"); + else + printf(" add sp,#%d\n", pr); + } + break; + + case 'D': /* Long comparision */ + twollcomp(p); + break; + + case 'F': /* Structure argument */ + starg(p); + break; + + case 'G': /* Floating point compare */ + fcomp(p); + break; + + case 'H': /* assign of long between regs */ + rmove(DECRA(p->n_right->n_reg, 0), + DECRA(p->n_left->n_reg, 0), LONGLONG); + break; + + case 'I': /* float casts */ + fcast(p); + break; + + case 'J': /* convert unsigned long long to floating point */ + ulltofp(p); + break; + + case 'K': /* Load long reg into another reg */ + rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG); + break; + + case 'M': /* Output sconv move, if needed */ + l = getlr(p, 'L'); + /* XXX fixneed: regnum */ + pr = DECRA(p->n_reg, 0); + lr = DECRA(l->n_reg, 0); + if ((pr == AL && lr == AX) || (pr == BL && lr == BX) || + (pr == CL && lr == CX) || (pr == DL && lr == DX)) + ; + else + printf(" mov %s, %cL\n", + rnames[pr], rnames[lr][1]); + l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */ + break; + + case 'N': /* output extended reg name */ + printf("%s", rnames[getlr(p, '1')->n_rval]); + break; + + case 'O': /* print out emulated ops */ + pr = 8; + sv = 'l'; +#if 0 + if (p->n_op == RS || p->n_op == LS) { + llshft(p); + break; + } +#endif + if (p->n_op != RS && p->n_op != LS) { + /* For 64bit we will need to push pointers + not u64 */ + expand(p, INCREG, "\tpush UR\n\tpush AR\n"); + expand(p, INCREG, "\tpush UL\n\tpush AL\n"); + } else { + /* AR is a BREG so this goes wrong.. need an AREG + but putting an AREG in the table rule makes the + compiler shit itself - FIXME */ + expand(p, INAREG, "\tpush AR\n"); + expand(p, INCREG, "\tpush UL\n\tpush AL\n"); + pr = 6; + } + + if (p->n_type == LONGLONG || p->n_type == ULONGLONG) + sv = 'L'; + if (p->n_op == DIV && (p->n_type == ULONG || p->n_type == ULONGLONG)) + ch = "udiv"; + else if (p->n_op == MUL && (p->n_type == ULONG || p->n_type == ULONGLONG)) + ch = "umul"; + else if (p->n_op == DIV) ch = "div"; + else if (p->n_op == MUL) ch = "mul"; + else if (p->n_op == MOD && (p->n_type == ULONG || p->n_type == ULONGLONG)) + ch = "umod"; + else if (p->n_op == MOD) ch = "mod"; + else if (p->n_op == LS) ch = "ls"; + else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == ULONGLONG)) + ch = "rs"; + else if (p->n_op == RS) ch = "urs"; + else ch = 0, comperr("ZO"); + printf("\tcall " EXPREFIX "__%c%sdi3\n\tadd %s,#%d\n", + sv, ch, rnames[SP], pr); + break; + + case 'P': /* typeless right hand */ + suppress_type = 1; + break; + + case 'Q': /* emit struct assign */ + /* + * Put out some combination of movs{b,w} + * si/di/cx are available. + * FIXME: review es: and direction flag implications + */ + expand(p, INAREG, " lea al,di\n"); + ap = attr_find(p->n_ap, ATTR_P2STRUCT); + if (ap->iarg(0) < 32) { + int i = ap->iarg(0) >> 1; + while (i) { + expand(p, INAREG, " movsw\n"); + i--; + } + } else { + printf("\tmov cx, #%d\n", ap->iarg(0) >> 1); + printf(" rep movsw\n"); + } + if (ap->iarg(0) & 2) + printf(" movsw\n"); + if (ap->iarg(0) & 1) + printf(" movsb\n"); + break; + + case 'S': /* emit eventual move after cast from long */ + pr = DECRA(p->n_reg, 0); + lr = p->n_left->n_rval; + switch (p->n_type) { + case CHAR: + case UCHAR: + if (rnames[pr][1] == 'L' && rnames[lr][1] == 'X' && + rnames[pr][0] == rnames[lr][0]) + break; + if (rnames[lr][1] == 'X') { + printf("\tmov %s, %cL\n", + rnames[pr], rnames[lr][0]); + break; + } + /* Must go via stack */ + expand(p, INAREG, "\tmov A2,AL\n"); + expand(p, INBREG, "\tmov A1,A2\n"); +#ifdef notdef + /* cannot use freetemp() in instruction emission */ + s = freetemp(1); + printf("\tmov %ci,%d(bp)\n", rnames[lr][0], s); + printf("\tmov %s, %d(bp)\n", rnames[pr], s); +#endif + break; + + case INT: + case UNSIGNED: + if (rnames[lr][0] == rnames[pr][1] && + rnames[lr][1] == rnames[pr][2]) + break; + printf("\tmov %s, %c%c\n", + rnames[pr], rnames[lr][0], rnames[lr][1]); + break; + + default: + if (rnames[lr][0] == rnames[pr][1] && + rnames[lr][1] == rnames[pr][2]) + break; + comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]); + break; + } + break; + case 'T': + /* Conversions from unsigned char to int/ptr */ + /* Cannot be in DI or SI */ + l = getlr(p, 'L'); + lr = regno(l); + pr = regno(getlr(p, '1')); + if (l->n_op != REG) { /* NAME or OREG */ + /* Need to force a mov into the low half, using + a movw might fail in protected mode or with + mmio spaces */ + printf(" mov %cl, ", rnames[pr][0]); + expand(p, INAREG, "AL\n"); + } else { + if ((lr == AL && pr == AX) || + (lr == BL && pr == BX) || + (lr == CL && pr == CX) || + (lr == DL && pr == DX)) + ; + else + printf(" mov %cl,%cl\n", + rnames[pr][0],rnames[lr][0]); + } + printf(" xor %ch,%ch\n", + rnames[pr][0], rnames[pr][0]); + break; + break; + default: + comperr("zzzcode %c", c); + } +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left, SOREG))) + return(1); + return(0); +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + comperr("flshape"); + return 0; +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + return 0; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +void +adrcon(CONSZ val) +{ + printf("$" CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + int val = (int)p->n_lval; + + switch (p->n_op) { + case ICON: + if (p->n_name[0] != '\0') { + fprintf(fp, "#%s", p->n_name); + if (val) + fprintf(fp, "+%d", val); + } else + fprintf(fp, "#%d", val); + return; + + default: + comperr("illegal conput, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + + size /= SZCHAR; + switch (p->n_op) { + case REG: + printf("%s", &rnames[p->n_rval][2]); + break; + + case NAME: + case OREG: + p->n_lval += size; + adrput(stdout, p); + p->n_lval -= size; + break; + case ICON: + printf("#"CONFMT, p->n_lval >> 16); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +static void do_adrput(FILE *io, NODE *p, int ut) +{ + int r; + /* output an address, with offsets, from p */ + + switch (p->n_op) { + + case NAME: + if (!ut) { + switch (p->n_type) { + case SHORT: + case USHORT: + case INT: + case UNSIGNED: + printf("word ptr "); + break; + case CHAR: + case UCHAR: + printf("byte ptr "); + } + } + if (p->n_name[0] != '\0') { + fputs(p->n_name, io); + if (p->n_lval != 0) + fprintf(io, "+" CONFMT, p->n_lval); + } else + fprintf(io, "#"CONFMT, p->n_lval); + return; + + case OREG: + r = p->n_rval; + if (p->n_name[0]) + printf("%s%s", p->n_name, p->n_lval ? "+" : ""); + if (p->n_lval) + fprintf(io, "%d", (int)p->n_lval); + printf("["); + if (R2TEST(r)) { + fprintf(io, "%s,%s,4", rnames[R2UPK1(r)], + rnames[R2UPK2(r)]); + } else + fprintf(io, "%s", rnames[p->n_rval]); + printf("]"); + return; + case ICON: + /* addressable value of the constant */ + if (!ut) { + switch (p->n_type) { + case SHORT: + case USHORT: + case INT: + case UNSIGNED: + printf("word "); + break; + case CHAR: + case UCHAR: + printf("byte "); + } + } + conput(io, p); + return; + + case REG: + switch (p->n_type) { + case LONGLONG: + case ULONGLONG: + case LONG: + case ULONG: + fprintf(io, "%c%c", rnames[p->n_rval][0], + rnames[p->n_rval][1]); + break; + default: + fprintf(io, "%s", rnames[p->n_rval]); + } + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +void adrput(FILE *io, NODE *p) +{ + do_adrput(io, p, suppress_type); + suppress_type = 0; +} + +static char * +ccbranches[] = { + "je", /* jumpe */ + "jne", /* jumpn */ + "jle", /* jumple */ + "jl", /* jumpl */ + "jge", /* jumpge */ + "jg", /* jumpg */ + "jbe", /* jumple (jlequ) */ + "jb", /* jumpl (jlssu) */ + "jae", /* jumpge (jgequ) */ + "ja", /* jumpg (jgtru) */ +}; + + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + if (o < EQ || o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); +} + +static void +fixcalls(NODE *p, void *arg) +{ + /* Prepare for struct return by allocating bounce space on stack */ + switch (p->n_op) { + case STCALL: + case USTCALL: + if (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+p2autooff > stkpos) + stkpos = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+p2autooff; + break; + case LS: + case RS: + if (p->n_type != LONGLONG && p->n_type != ULONGLONG + && p->n_type != LONG && p->n_type != ULONG) + break; + if (p->n_right->n_op == ICON) /* constants must be char */ + p->n_right->n_type = CHAR; + break; + } +} + +/* + * Must store floats in memory if there are two function calls involved. + */ +static int +storefloat(struct interpass *ip, NODE *p) +{ + int l, r; + + switch (optype(p->n_op)) { + case BITYPE: + l = storefloat(ip, p->n_left); + r = storefloat(ip, p->n_right); + if (p->n_op == CM) + return 0; /* arguments, don't care */ + if (callop(p->n_op)) + return 1; /* found one */ +#define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \ + (p)->n_type == LDOUBLE) + if (ISF(p->n_left) && ISF(p->n_right) && l && r) { + /* must store one. store left */ + struct interpass *nip; + TWORD t = p->n_left->n_type; + NODE *ll; + int off; + + off = freetemp(szty(t)); + ll = mklnode(OREG, off, FPREG, t); + nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t)); + p->n_left = mklnode(OREG, off, FPREG, t); + DLIST_INSERT_BEFORE(ip, nip, qelem); + } + return l|r; + + case UTYPE: + l = storefloat(ip, p->n_left); + if (callop(p->n_op)) + l = 1; + return l; + default: + return 0; + } +} + +static void +outfargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c) +{ + struct interpass *ip2; + NODE *q, *r; + int i; + + for (i = 0; i < num; i++) + if (XASMVAL(cwp[i]) == c && (cwp[i] & (XASMASG|XASMINOUT))) + break; + if (i == num) + return; + q = ary[i]->n_left; + r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type); + ary[i]->n_left = tcopy(r); + ip2 = ipnode(mkbinode(ASSIGN, q, r, q->n_type)); + DLIST_INSERT_AFTER(ip, ip2, qelem); +} + +static void +infargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c) +{ + struct interpass *ip2; + NODE *q, *r; + int i; + + for (i = 0; i < num; i++) + if (XASMVAL(cwp[i]) == c && (cwp[i] & XASMASG) == 0) + break; + if (i == num) + return; + q = ary[i]->n_left; + q = (cwp[i] & XASMINOUT) ? tcopy(q) : q; + r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type); + if ((cwp[i] & XASMINOUT) == 0) + ary[i]->n_left = tcopy(r); + ip2 = ipnode(mkbinode(ASSIGN, r, q, q->n_type)); + DLIST_INSERT_BEFORE(ip, ip2, qelem); +} + +/* + * Extract float args to XASM and ensure that they are put on the stack + * in correct order. + * This should be done sow other way. + */ +static void +fixxfloat(struct interpass *ip, NODE *p) +{ + NODE *w, **ary; + int nn, i, c, *cwp; + + nn = 1; + w = p->n_left; + if (w->n_op == ICON && w->n_type == STRTY) + return; + /* index all xasm args first */ + for (; w->n_op == CM; w = w->n_left) + nn++; + ary = tmpcalloc(nn * sizeof(NODE *)); + cwp = tmpcalloc(nn * sizeof(int)); + for (i = 0, w = p->n_left; w->n_op == CM; w = w->n_left) { + ary[i] = w->n_right; + cwp[i] = xasmcode(ary[i]->n_name); + i++; + } + ary[i] = w; + cwp[i] = xasmcode(ary[i]->n_name); + for (i = 0; i < nn; i++) + if (XASMVAL(cwp[i]) == 't' || XASMVAL(cwp[i]) == 'u') + break; + if (i == nn) + return; + + for (i = 0; i < nn; i++) { + c = XASMVAL(cwp[i]); + if (c >= '0' && c <= '9') + cwp[i] = (cwp[i] & ~0377) | XASMVAL(cwp[c-'0']); + } + infargs(ip, ary, nn, cwp, 'u'); + infargs(ip, ary, nn, cwp, 't'); + outfargs(ip, ary, nn, cwp, 't'); + outfargs(ip, ary, nn, cwp, 'u'); +} + +static NODE * +lptr(NODE *p) +{ + if (p->n_op == ASSIGN && p->n_right->n_op == REG && + regno(p->n_right) == BP) + return p->n_right; + if (p->n_op == FUNARG && p->n_left->n_op == REG && + regno(p->n_left) == BP) + return p->n_left; + return NIL; +} + +/* + * Find arg reg that should be struct reference instead. + */ +static void +updatereg(NODE *p, void *arg) +{ + NODE *q; + + if (p->n_op != STCALL) + return; + if (p->n_right->n_op != CM) + p = p->n_right; + else for (p = p->n_right; + p->n_op == CM && p->n_left->n_op == CM; p = p->n_left) + ; + if (p->n_op == CM) { + if ((q = lptr(p->n_left))) + ; + else + q = lptr(p->n_right); + } else + q = lptr(p); + if (q == NIL) + comperr("bad STCALL hidden reg"); + + /* q is now the hidden arg */ + q->n_op = MINUS; + q->n_type = INCREF(CHAR); + q->n_left = mklnode(REG, 0, BP, INCREF(CHAR)); + q->n_right = mklnode(ICON, stkpos, 0, INT); +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + stkpos = p2autooff; + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, fixcalls, 0); + storefloat(ip, ip->ip_node); + if (ip->ip_node->n_op == XASM) + fixxfloat(ip, ip->ip_node); + } + if (stkpos != p2autooff) { + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, updatereg, 0); + } + } + if (stkpos > p2autooff) + p2autooff = stkpos; + if (stkpos > p2maxautooff) + p2maxautooff = stkpos; + if (x2debug) + printip(ipole); +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE *p, void *arg) +{ + NODE *q; + if (p->n_op == PLUS) { + if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2, 0); +} + +void +myoptim(struct interpass *ip) +{ +} + +static char rl[] = + { AX, AX, AX, AX, AX, DX, DX, DX, DX, CX, CX, CX, BX, BX, SI }; +static char rh[] = + { DX, CX, BX, SI, DI, CX, BX, SI, DI, BX, SI, DI, SI, DI, DI }; + +void +rmove(int s, int d, TWORD t) +{ + int sl, sh, dl, dh; + + switch (t) { + case LONGLONG: + case ULONGLONG: + case LONG: + case ULONG: /* ?? FIXME check */ +#if 1 + sl = rl[s-AXDX]; + sh = rh[s-AXDX]; + dl = rl[d-AXDX]; + dh = rh[d-AXDX]; + + /* sanity checks, remove when satisfied */ + if (memcmp(rnames[s], rnames[sl], 2) != 0 || + memcmp(rnames[s]+2, rnames[sh], 2) != 0) + comperr("rmove source error"); + if (memcmp(rnames[d], rnames[dl], 2) != 0 || + memcmp(rnames[d]+2, rnames[dh], 2) != 0) + comperr("rmove dest error"); +#define SW(x,y) { int i = x; x = y; y = i; } + if (sh == dl) { + /* Swap if overwriting */ + SW(sl, sh); + SW(dl, dh); + } + if (sl != dl) + printf(" mov %s,%s\n", rnames[dl], rnames[sl]); + if (sh != dh) + printf(" mov %s,%s\n", rnames[dh], rnames[sh]); +#else + if (memcmp(rnames[s], rnames[d], 2) != 0) + printf(" mov %c%c,%c%c\n", + rnames[d][0],rnames[d][1], + rnames[s][0],rnames[s][1]); + if (memcmp(&rnames[s][2], &rnames[d][2], 2) != 0) + printf(" mov %c%c,%c%c\n", + rnames[d][2],rnames[d][3] + rnames[s][2],rnames[s][3]); +#endif + break; + case CHAR: + case UCHAR: + printf(" mov %s,%s\n", rnames[d], rnames[s]); + break; + case FLOAT: + case DOUBLE: + case LDOUBLE: +#ifdef notdef + /* a=b()*c(); will generate this */ + comperr("bad float rmove: %d %d", s, d); +#endif + break; + default: + printf(" mov %s,%s\n", rnames[d], rnames[s]); + } +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int c, int *r) +{ + int num; + + switch (c) { + case CLASSA: + num = r[CLASSB] > 4 ? 4 : r[CLASSB]; + num += 2*r[CLASSC]; + num += r[CLASSA]; + return num < 6; + case CLASSB: + num = r[CLASSA]; + num += 2*r[CLASSC]; + num += r[CLASSB]; + return num < 4; + case CLASSC: + num = r[CLASSA]; + num += r[CLASSB] > 4 ? 4 : r[CLASSB]; + num += 2*r[CLASSC]; + return num < 5; + case CLASSD: + return r[CLASSD] < DREGCNT; + } + return 0; /* XXX gcc */ +} + +char *rnames[] = { + "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", + "al", "ah", "dl", "dh", "cl", "ch", "bl", "bh", + "axdx", "axcx", "axbx", "axsi", "axdi", "dxcx", + "dxbx", "dxsi", "dxdi", "cxbx", "cxsi", "cxdi", + "bxsi", "bxdi", "sidi", + "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7", +}; + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t == CHAR || t == UCHAR) + return CLASSB; + if (t == LONGLONG || t == ULONGLONG || t == LONG || t == ULONG) + return CLASSC; + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return CLASSD; + return CLASSA; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) { + if (p->n_right->n_op != ASSIGN) + size += argsiz(p->n_right); + } + if (p->n_op != ASSIGN) + size += argsiz(p); + + op->n_qual = size; /* XXX */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + int o = p->n_op; + + switch (shape) { + case SFUNCALL: + if (o == STCALL || o == USTCALL) + return SRREG; + break; + case SPCON: + if (o != ICON || p->n_name[0] || + p->n_lval < 0 || p->n_lval > 0x7fffffff) + break; + return SRDIR; + case SMIXOR: + return tshape(p, SZERO); + case SMILWXOR: + if (o != ICON || p->n_name[0] || + p->n_lval == 0 || p->n_lval & 0xffffffff) + break; + return SRDIR; + case SMIHWXOR: + if (o != ICON || p->n_name[0] || + p->n_lval == 0 || (p->n_lval >> 32) != 0) + break; + return SRDIR; + case STWO: + if (o == ICON && p->n_name[0] == 0 && p->n_lval == 2) + return SRDIR; + break; + case SMTWO: + if (o == ICON && p->n_name[0] == 0 && p->n_lval == -2) + return SRDIR; + break; + } + return SRNOPE; +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ +} + +/* + * Do something target-dependent for xasm arguments. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + struct interpass *ip2; + int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 }; + NODE *in = 0, *ut = 0; + TWORD t; + char *w; + int reg; + int c, cw; + CONSZ v; + + cw = xasmcode(p->n_name); + if (cw & (XASMASG|XASMINOUT)) + ut = p->n_left; + if ((cw & XASMASG) == 0) + in = p->n_left; + + c = XASMVAL(cw); + switch (c) { + case 'D': reg = DI; break; + case 'S': reg = SI; break; + case 'a': reg = AX; break; + case 'b': reg = BX; break; + case 'c': reg = CX; break; + case 'd': reg = DX; break; + + case 't': + case 'u': + p->n_name = tmpstrdup(p->n_name); + w = strchr(p->n_name, XASMVAL(cw)); + *w = 'r'; /* now reg */ + return 1; + + case 'A': reg = AXDX; break; + case 'q': { + /* Set edges in MYSETXARG */ + if (p->n_left->n_op == REG || p->n_left->n_op == TEMP) + return 1; + t = p->n_left->n_type; + if (in && ut) + in = tcopy(in); + p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t); + if (ut) { + ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t)); + DLIST_INSERT_AFTER(ip, ip2, qelem); + } + if (in) { + ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t)); + DLIST_INSERT_BEFORE(ip, ip2, qelem); + } + return 1; + } + + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + if (p->n_left->n_op != ICON) { + if ((c = XASMVAL1(cw)) != 0) { + p->n_name++; + return 0; /* Try again */ + } + uerror("xasm arg not constant"); + } + v = p->n_left->n_lval; + if ((c == 'K' && v < -128) || + (c == 'L' && v != 0xff && v != 0xffff) || + (c != 'K' && v < 0) || + (v > Cmax[c-'I'])) + uerror("xasm val out of range"); + p->n_name = "i"; + return 1; + + default: + return 0; + } + /* If there are requested either memory or register, delete memory */ + w = p->n_name = tmpstrdup(p->n_name); + if (*w == '=') + w++; + *w++ = 'r'; + *w = 0; + + t = p->n_left->n_type; + if (reg == AXDX) { + ; + } else { + if (t == CHAR || t == UCHAR) { + reg = reg * 2 + 8; + } + } + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) { + reg += 037; + } + + if (in && ut) + in = tcopy(in); + p->n_left = mklnode(REG, 0, reg, t); + if (ut) { + ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t)); + DLIST_INSERT_AFTER(ip, ip2, qelem); + } + if (in) { + ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t)); + DLIST_INSERT_BEFORE(ip, ip2, qelem); + } + return 1; +} + +void +targarg(char *w, void *arg) +{ + NODE **ary = arg; + NODE *p, *q; + + if (ary[(int)w[1]-'0'] == 0) + p = ary[(int)w[1]-'0'-1]->n_left; /* XXX */ + else + p = ary[(int)w[1]-'0']->n_left; + if (optype(p->n_op) != LTYPE) + comperr("bad xarg op %d", p->n_op); + q = tcopy(p); + if (q->n_op == REG) { + if (*w == 'k') { + q->n_type = INT; + } else if (*w != 'w') { + if (q->n_type > UCHAR) { + regno(q) = regno(q)*2+8; + if (*w == 'h') + regno(q)++; + } + q->n_type = INT; + } else + q->n_type = SHORT; + } + adrput(stdout, q); + tfree(q); +} + +/* + * target-specific conversion of numeric arguments. + */ +int +numconv(void *ip, void *p1, void *q1) +{ + NODE *p = p1, *q = q1; + int cw = xasmcode(q->n_name); + + switch (XASMVAL(cw)) { + case 'a': + case 'b': + case 'c': + case 'd': + p->n_name = tmpcalloc(2); + p->n_name[0] = (char)XASMVAL(cw); + return 1; + default: + return 0; + } +} + +static struct { + char *name; int num; +} xcr[] = { + { "ax", AX }, + { "bx", BX }, + { "cx", CX }, + { "dx", DX }, + { "si", SI }, + { "di", DI }, + { NULL, 0 }, +}; + +/* + * Check for other names of the xasm constraints registers. + */ + +/* + * Check for other names of the xasm constraints registers. + */ +int xasmconstregs(char *s) +{ + int i; + + if (strncmp(s, "st", 2) == 0) { + int off =0; + if (s[2] == '(' && s[4] == ')') + off = s[3] - '0'; + return SIDI + 1 + off; + } + + for (i = 0; xcr[i].name; i++) + if (strcmp(xcr[i].name, s) == 0) + return xcr[i].num; + return -1; +} + diff --git a/lang/pcc/pcc/arch/i86/macdefs.h b/lang/pcc/pcc/arch/i86/macdefs.h new file mode 100644 index 000000000..0574b1588 --- /dev/null +++ b/lang/pcc/pcc/arch/i86/macdefs.h @@ -0,0 +1,334 @@ +/* $Id: macdefs.h,v 1.7 2016/03/05 15:53:04 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +#define ARGINIT 64 /* # bits above fp where arguments start */ +#define AUTOINIT 0 /* # bits below fp where automatics start */ + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZBOOL 8 +#define SZINT 16 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 96 +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 64 /* Doesn't work usefully yet */ +#define SZPOINT(t) 16 /* FIXME: 32 for large model work */ + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALBOOL 8 +#define ALINT 16 +#define ALFLOAT 32 +#define ALDOUBLE 32 +#define ALLDOUBLE 32 +#define ALLONG 16 +#define ALLONGLONG 16 +#define ALSHORT 16 +#define ALPOINT 16 +#undef ALSTRUCT /* Not defined if ELF ABI */ +#define ALSTACK 16 +#define ALMAX 128 /* not yet supported type */ + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT MIN_SHORT +#define MAX_INT MAX_SHORT +#define MAX_UNSIGNED MAX_USHORT +#define MIN_LONG (-0x7fffffff-1) +#define MAX_LONG 0x7fffffff +#define MAX_ULONG 0xffffffff +#define MIN_LONGLONG MIN_LONG +#define MAX_LONGLONG MAX_LONG +#define MAX_ULONGLONG MAX_ULONG + +/* Default char is signed */ +#undef CHAR_UNSIGNED +#define BOOL_TYPE UCHAR /* what used to store _Bool */ +#undef UNALIGNED_ACCESS +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#define LABFMT "L%d" /* format for printing labels */ +#define STABLBL "LL%d" /* format for stab (debugging) labels */ +#ifdef LANG_F77 +#define BLANKCOMMON "_BLNK_" +#define MSKIREG (M(TYSHORT)|M(TYLONG)) +#define TYIREG TYLONG +#define FSZLENG FSZLONG +#define AUTOREG BP +#define ARGREG BP +#define ARGOFFSET 4 +#endif + +#define BACKAUTO /* stack grows negatively for automatics */ +#define BACKTEMP /* stack grows negatively for temporaries */ + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_LE + +#define FINDMOPS /* i86 has instructions that modifies memory */ +#define CC_DIV_0 /* division by zero is safe in the compiler */ + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&03) +#define wdal(k) (BYTEOFF(k)==0) + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) +#define genfcall(a,b) gencall(a,b) + +/* FIXME: float sizes wrong at this point ? */ +#define szty(t) (((t) == DOUBLE || (t) == FLOAT || \ + (t) == LONG || t == ULONG || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : (t) == LDOUBLE ? 3 : 1) + +/* + * The x86 has a bunch of register classes, most of them interfering + * with each other. All registers are given a sequential number to + * identify it which must match rnames[] in local2.c. + * Class membership and overlaps are defined in the macros RSTATUS + * and ROVERLAP below. + * + * The classes used on x86 are: + * A - short and int regs + * B - char regs + * C - long and longlong regs + * D - floating point + */ +#define AX 000 /* Scratch and return register */ +#define DX 001 /* Scratch and secondary return register */ +#define CX 002 /* Scratch (and shift count) register */ +#define BX 003 /* GDT pointer or callee-saved temporary register */ +#define SI 004 /* Callee-saved temporary register */ +#define DI 005 /* Callee-saved temporary register */ +#define BP 006 /* Frame pointer */ +#define SP 007 /* Stack pointer */ + +#define AL 010 +#define AH 011 +#define DL 012 +#define DH 013 +#define CL 014 +#define CH 015 +#define BL 016 +#define BH 017 + +#define AXDX 020 +#define AXCX 021 +#define AXBX 022 +#define AXSI 023 +#define AXDI 024 +#define DXCX 025 +#define DXBX 026 +#define DXSI 027 +#define DXDI 030 +#define CXBX 031 +#define CXSI 032 +#define CXDI 033 +#define BXSI 034 +#define BXDI 035 +#define SIDI 036 + +/* The 8 math registers in class D lacks names */ + +#define MAXREGS 047 /* 39 registers */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, 0, 0, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, + +#define ROVERLAP \ + /* 8 basic registers */\ + { AL, AH, AXDX, AXCX, AXBX, AXSI, AXDI, -1 },\ + { DL, DH, AXDX, DXCX, DXBX, DXSI, DXDI, -1 },\ + { CL, CH, AXCX, DXCX, CXBX, CXSI, CXDI, -1 },\ + { BL, BH, AXBX, DXBX, CXBX, BXSI, BXDI, -1 },\ + { AXSI, DXSI, CXSI, BXSI, SIDI, -1 },\ + { AXDI, DXDI, CXDI, BXDI, SIDI, -1 },\ + { -1 },\ + { -1 },\ +\ + /* 8 char registers */\ + { AX, AXDX, AXCX, AXBX, AXSI, AXDI, -1 },\ + { AX, AXDX, AXCX, AXBX, AXSI, AXDI, -1 },\ + { DX, AXDX, DXCX, DXBX, DXSI, DXDI, -1 },\ + { DX, AXDX, DXCX, DXBX, DXSI, DXDI, -1 },\ + { CX, AXCX, DXCX, CXBX, CXSI, CXDI, -1 },\ + { CX, AXCX, DXCX, CXBX, CXSI, CXDI, -1 },\ + { BX, AXBX, DXBX, CXBX, BXSI, BXDI, -1 },\ + { BX, AXBX, DXBX, CXBX, BXSI, BXDI, -1 },\ +\ + /* 15 long emulating registers */\ + { AX, AL, AH, DX, DL, DH, AXCX, AXBX, AXSI, /* axdx */\ + AXDI, DXCX, DXBX, DXSI, DXDI, -1, },\ + { AX, AL, AH, CX, CL, CH, AXDX, AXBX, AXSI, /* axcx */\ + AXDI, DXCX, CXBX, CXSI, CXDI, -1 },\ + { AX, AL, AH, BX, BL, BH, AXDX, AXCX, AXSI, /* axbx */\ + AXDI, DXBX, CXBX, BXSI, BXDI, -1 },\ + { AX, AL, AH, SI, AXDX, AXCX, AXBX, AXDI, /* axsi */\ + DXSI, CXSI, BXSI, SIDI, -1 },\ + { AX, AL, AH, DI, AXDX, AXCX, AXBX, AXSI, /* axdi */\ + DXDI, CXDI, BXDI, SIDI, -1 },\ + { DX, DL, DH, CX, CL, CH, AXDX, AXCX, DXBX, /* dxcx */\ + DXSI, DXDI, CXBX, CXSI, CXDI, -1 },\ + { DX, DL, DH, BX, BL, BH, AXDX, DXCX, DXSI, /* dxbx */\ + DXDI, AXBX, CXBX, BXSI, BXDI, -1 },\ + { DX, DL, DH, SI, AXDX, DXCX, DXBX, DXDI, /* dxsi */\ + AXSI, CXSI, BXSI, SIDI, -1 },\ + { DX, DL, DH, DI, AXDX, DXCX, DXBX, DXSI, /* dxdi */\ + AXDI, CXDI, BXDI, SIDI, -1 },\ + { CX, CL, CH, BX, BL, BH, AXCX, DXCX, CXSI, /* cxbx */\ + CXDI, AXBX, DXBX, BXSI, BXDI, -1 },\ + { CX, CL, CH, SI, AXCX, DXCX, CXBX, CXDI, /* cxsi */\ + AXSI, DXSI, BXSI, SIDI, -1 },\ + { CX, CL, CH, DI, AXCX, DXCX, CXBX, CXSI, /* cxdi */\ + AXDI, DXDI, BXDI, SIDI, -1 },\ + { BX, BL, BH, SI, AXBX, DXBX, CXBX, BXDI, /* bxsi */\ + AXSI, DXSI, CXSI, SIDI, -1 },\ + { BX, BL, BH, DI, AXBX, DXBX, CXBX, BXSI, /* bxdi */\ + AXDI, DXDI, CXDI, SIDI, -1 },\ + { SI, DI, AXSI, DXSI, CXSI, BXSI, /* sidi */\ + AXDI, DXDI, CXDI, BXDI, -1 },\ +\ + /* The fp registers do not overlap with anything */\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 }, + + +/* Return a register class based on the type of the node */ +/* FIXME: <= UCHAR includes long ?? check */ +#define PCLASS(p) (p->n_type <= UCHAR ? SBREG : \ + (p->n_type == LONG || p->n_type == ULONG || p->n_type == LONGLONG || p->n_type == ULONGLONG ? SCREG : \ + (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SDREG : SAREG))) + +#define NUMCLASS 4 /* highest number of reg classes used */ + +int COLORMAP(int c, int *r); +#define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 31 ? CLASSC : CLASSD) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ +/* XXX - return char in al? */ +#define RETREG(x) (x == CHAR || x == UCHAR ? AL : \ + x == LONG || x == ULONG || x == LONGLONG || x == ULONGLONG ? AXDX : \ + x == FLOAT || x == DOUBLE || x == LDOUBLE ? 31 : AX) + +#if 0 +#define R2REGS 1 /* permit double indexing */ +#endif + +/* XXX - to die */ +#define FPREG BP /* frame pointer */ +#define STKREG SP /* stack pointer */ + +#define SHSTR (MAXSPECIAL+1) /* short struct */ +#define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */ +#define SPCON (MAXSPECIAL+3) /* positive nonnamed constant */ + +/* + * Specials that indicate the applicability of machine idioms. + */ +#define SMIXOR (MAXSPECIAL+4) +#define SMILWXOR (MAXSPECIAL+5) +#define SMIHWXOR (MAXSPECIAL+6) +#define STWO (MAXSPECIAL+7) /* exactly two */ +#define SMTWO (MAXSPECIAL+8) /* exactly minus two */ + +/* + * i86-specific symbol table flags. + */ +#define SSECTION SLOCAL1 +#define SSTDCALL SLOCAL2 +#define SDLLINDIRECT SLOCAL3 + +/* + * i86-specific interpass stuff. + */ + +#define TARGET_IPP_MEMBERS \ + int ipp_argstacksize; + +#define HAVE_WEAKREF +#define TARGET_FLT_EVAL_METHOD 2 /* all as long double */ + +/* + * Extended assembler macros. + */ +void targarg(char *w, void *arg); +#define XASM_TARGARG(w, ary) \ + (w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' ? \ + w++, targarg(w, ary), 1 : 0) +int numconv(void *ip, void *p, void *q); +#define XASM_NUMCONV(ip, p, q) numconv(ip, p, q) +int xasmconstregs(char *); +#define XASMCONSTREGS(x) xasmconstregs(x) +#define MYSETXARG if (XASMVAL(cw) == 'q') { \ + c = 'r'; addalledges(&ablock[SI]); addalledges(&ablock[DI]); } + +/* target specific attributes */ +#define ATTR_MI_TARGET ATTR_I86_FPPOP diff --git a/lang/pcc/pcc/arch/i86/order.c b/lang/pcc/pcc/arch/i86/order.c new file mode 100644 index 000000000..e04bd0d5b --- /dev/null +++ b/lang/pcc/pcc/arch/i86/order.c @@ -0,0 +1,334 @@ +/* $Id: order.c,v 1.3 2014/12/27 21:18:19 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +#include + +int canaddr(NODE *); + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + return(0); /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + * Be careful about register classes, this is a place where classes change. + */ +void +offstar(NODE *p, int shape) +{ + NODE *r; + + if (x2debug) + printf("offstar(%p)\n", p); + + if (isreg(p)) + return; /* Is already OREG */ + + r = p->n_right; + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( r->n_op == ICON ){ + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + if (r->n_op == LS && r->n_right->n_op == ICON && + r->n_right->n_lval == 2 && p->n_op == PLUS) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + if (isreg(r->n_left) == 0) + (void)geninsn(r->n_left, INAREG); + return; + } + } + (void)geninsn(p, INAREG); +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + */ +void +myormake(NODE *q) +{ + NODE *p, *r; + + if (x2debug) + printf("myormake(%p)\n", q); + + p = q->n_left; + if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && + r->n_right->n_op == ICON && r->n_right->n_lval == 2 && + p->n_left->n_op == REG && r->n_left->n_op == REG) { + q->n_op = OREG; + q->n_lval = 0; + q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0); + tfree(p); + } +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Turns currently anything into OREG on x86 */ + if (shape & SOREG) + return SROREG; + return SRNOPE; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + * + * FIXME: review 32bit specials, a lot can go as we use helpers + */ +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + case OPLOG: + { + static struct rspecial s[] = { { NEVER, AX }, { 0 } }; + return s; + } + + case STASG: + { + static struct rspecial s[] = { + { NEVER, DI }, + { NRIGHT, SI }, { NOLEFT, SI }, + { NOLEFT, CX }, { NORIGHT, CX }, + { NEVER, CX }, { 0 } }; + return s; + } + + case STARG: + { + static struct rspecial s[] = { + { NEVER, DI }, { NEVER, CX }, + { NLEFT, SI }, { 0 } }; + return s; + } + + case SCONV: + /* Force signed conversions into al/ax to use cbw */ + if ((q->ltype & TCHAR) && + q->rtype == (TINT|TUNSIGNED)) { + static struct rspecial s[] = { + { NLEFT, AL }, { NRES, AX }, + { NEVER, AX }, { NEVER, AH}, {NEVER, AL }, + { 0 } }; + return s; + } + /* FIXME: do we need this rule with and based moves ? */ + /* Force signed unconversions to avoid si and di */ + if ((q->ltype & TUCHAR) && + q->rtype == (TINT|TUNSIGNED)) { + static struct rspecial s[] = { + { NEVER, SI }, { NEVER, DI }, + { 0 } }; + return s; + } else if ((q->ltype & (TINT|TUNSIGNED)) && + q->rtype == (TCHAR|TUCHAR)) { + static struct rspecial s[] = { + { NOLEFT, SI }, { NOLEFT, DI }, { 0 } }; + return s; + /* Need to be able to use cwd */ + } else if ((q->ltype & (TINT|TSHORT)) && + q->rtype == (TLONG|TULONG)) { + static struct rspecial s[] = { + { NLEFT, AX }, { NRES, AXDX }, + { NEVER, AX }, { NEVER, DX }, + { 0 } }; + return s; + /* Need to be use cbw cwd */ + } else if (q->ltype == TCHAR && + q->rtype == (TLONG|TULONG)) { + static struct rspecial s[] = { + { NRES, AXDX }, { NLEFT, AL }, + { NEVER, AX }, { NEVER, DX }, + { NEVER, AH }, { NEVER, AL }, + { 0 } }; + return s; + } + break; + case DIV: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NEVER, AL }, { NEVER, AH }, + { NLEFT, AL }, { NRES, AL }, + { NORIGHT, AH }, { NORIGHT, AL }, { 0 } }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NEVER, AX }, { NEVER, DX }, + { NLEFT, AX }, { NRES, AX }, + { NORIGHT, DX }, { NORIGHT, AX }, { 0 } }; + return s; + } +/* using helpers */ + else if (q->lshape & SCREG) { + static struct rspecial s[] = { + { NEVER, AX }, { NEVER, DX }, + { NEVER, CX }, { NRES, AXDX }, { 0 } }; + return s; + } + break; + case MOD: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NEVER, AL }, { NEVER, AH }, + { NLEFT, AL }, { NRES, AH }, + { NORIGHT, AH }, { NORIGHT, AL }, { 0 } }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NEVER, AX }, { NEVER, DX }, + { NLEFT, AX }, { NRES, DX }, + { NORIGHT, DX }, { NORIGHT, AX }, { 0 } }; + return s; + } else if (q->lshape & SCREG) { + static struct rspecial s[] = { + { NEVER, AX }, { NEVER, DX }, + { NEVER, CX }, { NRES, AXDX }, { 0 } }; + return s; + } + break; + case MUL: + if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NEVER, AX }, { NEVER, DX }, + { NLEFT, AX }, { NRES, AX }, + { NORIGHT, DX }, {NORIGHT, AX }, + { 0 } }; + return s; + } + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NEVER, AL }, { NEVER, AH }, + { NLEFT, AL }, { NRES, AL }, { 0 } }; + return s; + } else if (q->lshape & SCREG) { + static struct rspecial s[] = { + { NEVER, AX }, { NEVER, DX }, + { NEVER, CX }, { NRES, AXDX }, { 0 } }; + return s; + } + break; + case LS: + case RS: + if (q->visit & (INAREG|INBREG)) { + static struct rspecial s[] = { + { NRIGHT, CL }, { NOLEFT, CX }, { 0 } }; + return s; + } else if (q->visit & INCREG) { + static struct rspecial s[] = { + { NLEFT, AXDX }, { NRIGHT, CL }, + { NRES, AXDX }, { 0 } }; + return s; + } + break; + + default: + break; + } + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; /* nothing differs on x86 */ +} + +/* + * set registers in calling conventions live. + */ +int * +livecall(NODE *p) +{ + static int r[] = { AX, BX, -1 }; + int off = 1; + return kflag ? &r[off] : &r[2]; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/i86/table.c b/lang/pcc/pcc/arch/i86/table.c new file mode 100644 index 000000000..3a6f489cc --- /dev/null +++ b/lang/pcc/pcc/arch/i86/table.c @@ -0,0 +1,1564 @@ +/* $Id: table.c,v 1.5 2014/12/27 21:18:19 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * Copyright (c) 2014 Alan Cox (alan@lxorguk.ukuu.org.uk). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +/* + * TODO + * - clean up TLL usage so we are ready for 64bit longlong (T32 and T64?) + * - Clean up all the SHINT SHCH etc oddities for clarity + * - Better optimisation of constant multiply/divide etc on 8086 + * - some how lose the final bogus sp adjust we generate + * - write helper lib for long and longlong ops + * - add an E class and virtual 4 register longlong model + * - bcc fastcall format + * + * - How to do configurable code-gen + * For 80186 we want to use the better shifts, push constant, mul/div + * features and enter/leave + * For 80286 it's not clear we need to do anything for real mode. However + * for large data/huge models protected mode means minimising ds/es + * reloads with the same data + * With 80386 there is lots more - but who wants 80386/16bit optimised + * code ! + * + * - FPU has not been tackled. FPU/FPU should be fine (barring the odd + * gnu style instruction forms), but FPU/other is quite different + * because the 4 byte conversions are now long not int and two register + * while 8 byte longlong ones are going to need some gymnastics once + * we support the virtual 64bit registers + * + * - FPU/noFPU option. Assuming FPU present on 8086 is a bit obnoxious + * as a default. Need to be able to generate entirely soft-float calls. + * + * - We can't currently do various conversions we'd like to have, notably + * things like "and ax, $ff" to convert AL into AX from uchar to uint + * (that needs core changes and also allocator changes to try and avoid + * high bits being occupied by other users) + * + * - Shifts should be optimised for 8/16/24/32 cases + * + * - No attempt is made to deal with larger models than tiny + * + * small mode should work (just keep constant data in data segments) + * + * large code/small data should be fine-ish. Really that implies 32bit + * void * but for most uses you want 32bit only to be function pointers + * even if its not to spec. Function entry/exit needs to allow for the + * extra 2 bytes, call becomes call far, call ptr becomes a bit trickier + * but not a lot. Not that ld86 can link large model yet! + * + * large data is much harder because an address is 32bit, half of which + * needs to keep getting stuck into a segment register. However we often + * (usually) work with multiple pointers to the same object. Any given + * object has a single segment so we will badly need optimisations to + * "share" segment data and avoid lots of duplicate register uses and + * mov es, foo statements. + * + * huge model makes all pointers 32bit and all objects 32bit sized. That + * probably makes the sharing es issue go away somewhat, but raises the + * ugly problems of pointer normalisation (00:10 is the same as 01:00 + * which b*ggers up comparisons royally) and also protected mode where + * your segment jump as you go over 64K boundaries is different. On the + * bright side huge model performance will suck whatever the compiler + * does. + * + */ + +/* 64bit values */ +# define T64 TLONGLONG|TULONGLONG +/* 32bit values */ +# define T32 TLONG|TULONG +/* 16bit values */ +# define T16 TINT|TUNSIGNED +/* 16bit values including pointers */ +# define TP16 TINT|TUNSIGNED|TPOINT +/* 8bit values */ +# define T8 TCHAR|TUCHAR + +#define SHINT SAREG /* short and int */ +#define ININT INAREG +#define SHCH SBREG /* shape for char */ +#define INCH INBREG +#define SHLL SCREG /* shape for long long FIXME */ +#define INLL INCREG +#define SHL SCREG /* shape for long*/ +#define INL INCREG +#define SHFL SDREG /* shape for float/double */ +#define INFL INDREG /* shape for float/double */ + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are usually not necessary */ +{ PCONV, INAREG, + SAREG, T16|TPOINT, + SAREG, T16|TPOINT, + 0, RLEFT, + "", }, + +/* + * A bunch conversions of integral<->integral types + * There are lots of them, first in table conversions to itself + * and then conversions from each type to the others. + */ + +/* itself to itself, including pointers */ + +/* convert (u)char to (u)char. */ +{ SCONV, INCH, + SHCH, T8, + SHCH, T8, + 0, RLEFT, + "", }, + +/* convert pointers to int. */ +{ SCONV, ININT, + SHINT, TPOINT|T16, + SANY, T16, + 0, RLEFT, + "", }, + +/* convert (u)long to (u)long. */ +{ SCONV, INL, + SHL, T32, + SHL, T32, + 0, RLEFT, + "", }, + +/* convert (u)long and (u)longlong to (u)longlong. */ +{ SCONV, INLL, + SHLL, T64, + SHLL, T64, + 0, RLEFT, + "", }, + +/* convert between float/double/long double. */ +{ SCONV, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + "ZI", }, + +/* convert pointers to pointers. */ +{ SCONV, ININT, + SHINT, TPOINT, + SANY, TPOINT, + 0, RLEFT, + "", }, + +/* char to something */ + +/* convert char to 16bit types. */ + +/* 8086: Only as op on AL,AX */ +{ SCONV, ININT, + SBREG, TCHAR, + SAREG, T16, + NSPECIAL|NAREG|NASL, RESC1, + " cbw\n", }, + +/* convert unsigned char to 16bit types. + We can do this one with any register */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TUCHAR, + SAREG, T16, + NSPECIAL|NAREG, RESC1, + "ZT", }, + +/* convert char to (u)long + 8086 can only do cbw/cwd on AX and AX:DX pair */ +{ SCONV, INL, + SHCH, TCHAR, + SCREG, T32, + NSPECIAL|NCREG|NCSL, RESC1, + "; using AL\n cbw\n cwd\n", }, + +/* convert unsigned char to (u)long + we can do this with any register */ +{ SCONV, INL, + SHCH|SOREG|SNAME, TUCHAR, + SANY, T32, + NCREG|NCSL, RESC1, + "ZT xor U1,U1\n", }, + +/* convert char (in register) to double XXX - use NTEMP */ +/* FIXME : need NSPECIAL to force into AL + check AX:DX right way around ! */ +{ SCONV, INFL, + SHCH|SOREG|SNAME, TCHAR, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG, RESC2, + " cbw\n cwd\n push ax\n push dx\n" + " fildl [sp]\n add sp, #4\n", }, + +/* convert (u)char (in register) to double XXX - use NTEMP */ +/* FIXME : needs to use ZT to get sizes right, need a register + from somewhere to put 0 on the stack for the high bits */ +{ SCONV, INFL, + SHCH|SOREG|SNAME, TUCHAR, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG, RESC2, + " mov A1 AL\n and A1, #0xff\n push A1\npush #0\n" + " fildl [sp]\n add sp,#4\n", }, + +/* 16bit to something */ + +/* convert 16bit to 16bit. */ +{ SCONV, INAREG, + SAREG, T16, + SAREG, T16, + 0, RLEFT, + "", }, + +/* convert 16bit (in memory) to char */ +/* NOTE: uses new 'ZP' type for 'untyped right' */ +{ SCONV, INCH, + SNAME|SOREG, TP16, + SHCH, T8, + NBREG|NBSL, RESC1, + " mov A1,ZP AL\n", }, + +/* convert 16bit (in reg) to char. Done as a special but basically a mov */ +{ SCONV, INCH, + SAREG|SNAME|SOREG, TP16, + SHCH, T8, + NSPECIAL|NBREG|NBSL, RESC1, + "ZM", }, + +/* convert short/int to (u)long + This must go via AX so we can use cwd */ +{ SCONV, INL, + SAREG, TINT, + SHL, T32, + NSPECIAL|NCREG|NCSL, RESC1, + " mov A1, AL\n cwd\n", }, + +/* convert unsigned short/int to (u)long + Any pair will do. Note currently the compiler can't optimise + out the reg->reg move involved */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TUNSIGNED|TPOINT, + SHL, T32, + NCREG|NCSL, RESC1, + " mov A1,AL\n xor U1,U1\n", }, + +/* convert short/int (in memory) to float/double */ +{ SCONV, INFL, + SOREG|SNAME, TINT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fild AL\n", }, + +/* convert short/int (in register) to float/double */ +{ SCONV, INFL, + SAREG, TINT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " push AL\n fild [sp]\n" + " inc sp\n inc sp\n", }, + +/* convert unsigned short/int/ptr to double XXX - use NTEMP */ +/* FIXME: need to force this via AX so we can cwd, fix stack setup to + push both ax.dx*/ +{ SCONV, INFL, + SAREG|SOREG|SNAME, TUNSIGNED|TPOINT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG|NTEMP, RESC2, + " cwd\n push ax\n" + " fild [sp]\n inc sp\n" + " inc sp\n", }, + +/* long to something */ + +/* convert (u)long to (u)char (mem->reg) */ +{ SCONV, INCH, + SOREG|SNAME, T32, + SANY, T8, + NBREG|NBSL, RESC1, + " mov A1, AL\n", }, + +/* convert (u)long to (u)char (reg->reg, hopefully nothing) */ +{ SCONV, INCH, + SHL, T32, + SANY, T8, + NBREG|NBSL|NTEMP, RESC1, + "ZS", }, + +/* convert (u)long to (u)short (mem->reg) */ +{ SCONV, INAREG, + SOREG|SNAME, T32, + SAREG, TP16, + NAREG|NASL, RESC1, + " mov A1,AL\n", }, + +/* convert (u)long to 16bit (reg->reg, hopefully nothing) */ +{ SCONV, INAREG, + SHL|SOREG|SNAME, T32, + SAREG, T16, + NAREG|NASL|NTEMP, RESC1, + "ZS", }, + +/* FIXME: float stuff is all TODO */ + +/* convert long long (in memory) to floating */ +{ SCONV, INFL, + SOREG|SNAME, TLONGLONG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fild AL\n", }, + +/* convert long (in register) to floating */ +{ SCONV, INFL, + SHL, TLONGLONG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " push UL\n push AL\n" + " fild [sp]\n add sp, #8\n", }, + +/* convert unsigned long to floating */ +{ SCONV, INFL, + SCREG, TULONGLONG, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + "ZJ", }, + +/* float to something */ + +#if 0 /* go via int by adding an extra sconv in clocal() */ +/* convert float/double to (u) char. XXX should use NTEMP here */ +{ SCONV, INCH, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHCH, T16|T8, + NBREG, RESC1, + " sub sp,#4\n fistpl [sp]\n pop A1\n pop U1\n", }, + +/* convert float/double to (u) int/short/char. XXX should use NTEMP here */ +{ SCONV, INCH, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHCH, T16|T8, + NCREG, RESC1, + " sub sp,#4\n fistpl (%sp)\n pop A1\n inc sp\n inc sp\n", }, +#endif + +/* convert float/double to long XXX should use NTEMP here */ +{ SCONV, INAREG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SAREG, TLONG, + NAREG, RESC1, + " sub sp, #12\n" + " fstcw sp\n" + " fstcw 4[sp]\n" + " mov byte ptr 1[sp], #12\n" + " fldcw sp\n" + " fistp 8[sp]\n" + " movl A1, 8(p)\n" + " fldcw 4[sp]\n" + " add sp, #4\n", }, + +/* convert float/double to unsigned long. XXX should use NTEMP here */ +{ SCONV, INAREG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SAREG, TULONG, + NAREG, RESC1, + " sub sp, #16\n" + " fnstcw [sp]\n" + " fnstcw 4[sp]\n" + " mov byte ptr 1[sp], #12\n" + " fldcw [sp[\n" + " fistpq 8[sp]\n" + " mov word ptr 8[sp],A1\n" + " mov word ptr 10[sp],U1\n" + " fldcw 4[sp]\n" + " add sp, #16\n", }, + +/* convert float/double (in register) to long long */ +{ SCONV, INLL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHLL, TLONGLONG, + NCREG, RESC1, + " sub sp, #16\n" + " fnstcw [sp]\n" + " fnstcw [sp]\n" + " mov byte ptr 1[sp], #12\n" + " fldcw [sp]\n" + " fistpq 8[sp]\n" + " movl 8[sp],A1\n" + " movl 10[sp],U1\n" + /* need to put 12/14 somewhere FIXME */ + " fldcw 4[sp]\n" + " add sp, #16\n", }, + +/* convert float/double (in register) to unsigned long long */ +{ SCONV, INLL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHLL, TULONGLONG, + NCREG, RESC1, + " sub sp, #16\n" + " fnstcw [sp]\n" + " fnstcw 4[sp]\n" + " mov byte ptr 1[sp], #15\n" /* 64-bit prec */ + " fldcw [sp]\n" + " movl $0x5f000000, 8(%sp)\n" /* (float)(1<<63) */ + " fsubs 8[sp]\n" /* keep in range of fistpq */ + " fistpq 8[sp]\n" + " xor byte ptr 15[sp], #0x80\n" /* addq $1>>63 to 8(%sp) */ + " movl A1, 8[sp]\n" + " movl U1, 10[sp]\n" + " fldcw 4[sp]\n" + " add sp, #16\n", }, + + + +/* slut sconv */ + +/* + * Subroutine calls. + */ + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " call CL\nZC", }, + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " call CL\nZC", }, + +//{ UCALL, FOREFF, +// SCON, TANY, +// SAREG, TP16, +// 0, 0, +// " call CL\nZC", }, + +{ CALL, INAREG, + SCON, TANY, + SAREG, TP16, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INAREG, + SCON, TANY, + SAREG, TP16, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, T8, + NBREG, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INBREG, + SCON, TANY, + SBREG, T8, + NBREG, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, INDREG, + SCON, TANY, + SDREG, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INDREG, + SCON, TANY, + SDREG, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ CALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INDREG, + SAREG, TANY, + SANY, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INDREG, + SAREG, TANY, + SANY, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ STCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + " call CL\nZC", }, + +{ STCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ STCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +/* + * The next rules handle all binop-style operators. + * + * 8 and 16bit we do directly, 32bit is a mix of helpers and + * direct operations. 64bit TODO, FPU lives in it's own little + * world. + */ +{ PLUS, INL|FOREFF, + SHL, T32, + SHL|SNAME|SOREG, T32, + 0, RLEFT, + " add AL,AR\n adc UL,UR\n", }, + +{ PLUS, INL|FOREFF, + SHL|SNAME|SOREG, T32, + SHL|SCON, T32, + 0, RLEFT, + " add AL,AR\n adc UL,UR\n", }, + +/* Special treatment for long XXX - fix commutative check */ +{ PLUS, INL|FOREFF, + SHL|SNAME|SOREG, T32, + SHL, T32, + 0, RRIGHT, + " add AL,AR\n adc UL,UR\n", }, + +{ PLUS, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " faddl AR\n", }, + +{ PLUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " faddp\n", }, + +{ PLUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TP16, + SONE, TANY, + 0, RLEFT, + " inc AL\n", }, + +{ PLUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TP16, + STWO, TANY, + 0, RLEFT, + " inc AL\n inc AL\n", }, + +{ PLUS, INCH|FOREFF, + SHCH|SNAME|SOREG, T8, + SONE, TANY, + 0, RLEFT, + " inc AL\n", }, + +{ PLUS, INCH|FOREFF, + SHCH|SNAME|SOREG, T8, + STWO, TANY, + 0, RLEFT, + " inc AL\n inc AL\n", }, + +{ PLUS, INAREG, + SAREG, T16, + SAREG, T16, + NAREG|NASL|NASR, RESC1, + " lea A1, [AL+AR]\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TP16, + SONE, TANY, + 0, RLEFT, + " dec AL\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TP16, + STWO, TANY, + 0, RLEFT, + " dec AL\n dec AL\n", }, + +{ MINUS, INCH|FOREFF, + SHCH|SNAME|SOREG, T8, + SONE, TANY, + 0, RLEFT, + " dec AL\n", }, + +{ MINUS, INCH|FOREFF, + SHCH|SNAME|SOREG, T8, + STWO, TANY, + 0, RLEFT, + " dec AL\n decl AL\n", }, + +/* address as register offset, negative */ +{ MINUS, INLL|FOREFF, + SHL, T32, + SHL|SNAME|SOREG, T32, + 0, RLEFT, + " sub AL,AR\n sbb UL,UR\n", }, + +{ MINUS, INL|FOREFF, + SHL|SNAME|SOREG, T32, + SHL|SCON, T32, + 0, RLEFT, + " sub AL,AR\n sbb UL,UR\n", }, + +{ MINUS, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fsubl AR\n", }, + +{ MINUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fsubZAp\n", }, + +/* Simple r/m->reg ops */ +/* m/r |= r */ + +{ OPSIMP, INAREG|FOREFF|FORCC, + SHINT|SNAME|SOREG, TP16, + SHINT, TP16, + 0, RLEFT|RESCC, + " Ow AL,AR\n", }, + +/* r |= r/m */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SHINT, T16, + SHINT|SNAME|SOREG, T16, + 0, RLEFT|RESCC, + " Ow AL,AR\n", }, + +/* m/r |= r */ +{ OPSIMP, INCH|FOREFF|FORCC, + SHCH, T8, + SHCH|SNAME|SOREG, T8, + 0, RLEFT|RESCC, + " Ob AL,AR\n", }, + +/* r |= r/m */ +{ OPSIMP, INCH|FOREFF|FORCC, + SHCH, T8, + SHCH|SNAME|SOREG, T8, + 0, RLEFT|RESCC, + " Ob AL,AR\n", }, + +/* m/r |= const */ +{ OPSIMP, INAREG|FOREFF|FORCC, + SHINT|SNAME|SOREG, TP16, + SCON, TANY, + 0, RLEFT|RESCC, + " Ow AL,AR\n", }, + +{ OPSIMP, INCH|FOREFF|FORCC, + SHCH|SNAME|SOREG, T8, + SCON, TANY, + 0, RLEFT|RESCC, + " Ob AL,AR\n", }, + +/* r |= r/m */ +{ OPSIMP, INL|FOREFF, + SHL, T32, + SHL|SNAME|SOREG, T32, + 0, RLEFT, + " Ow AL,AR\n Ow UL,UR\n", }, + +/* m/r |= r/const */ +{ OPSIMP, INL|FOREFF, + SHL|SNAME|SOREG, T32, + SHL|SCON, T32, + 0, RLEFT, + " Ow AL,AR\n Ow UL,UR\n", }, + +/* Try use-reg instructions first */ +{ PLUS, INAREG, + SAREG, TP16, + SCON, TANY, + NAREG|NASL, RESC1, + " lea A1, CR[AL]\n", }, + +{ MINUS, INAREG, + SAREG, TP16, + SPCON, TANY, + NAREG|NASL, RESC1, + " lea A1, -CR[AL]\n", }, + + +/* + * The next rules handle all shift operators. + */ +/* (u)long left shift is emulated, longlong to do */ + +/* For 8086 we only have shift by 1 or shift by CL + + We need a way to optimise shifts by 8/16/24/32/etc + shifts by 8 16 24 and 32 as moves between registers for + the bigger types. (eg >> 16 on a long might be mov dx, ax, + xor ax, ax) */ + +{ LS, INCREG, + SCREG, T32, + SHCH, T8, + 0, RLEFT, + "ZO", }, + +/* Register 8086 timing is 2 for #1 versus 8 + 4/bin for multiple + so a lot of shifts would in fact best be done without using the cl + variant, especially including the cost of a) loading cl b) probably + having to boot something out of cx in the first place. For memory + its 15+EA v 20 + EA + 4/bit, so the other way. + + 8,16,24 should of course be done by loads.. FIXME + + Also the compiler keeps generating mov dh, #8, mov cl, dh.. FIXME + + For 80186 onwards we have shl reg, immediate (other than 1), 186 shift + is also much faster */ + + +/* r/m <<= const 1*/ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, T16, + SONE, TANY, + 0, RLEFT, + " shl AL,#1\n", }, + +/* r <<= const 2 */ +{ LS, INAREG|FOREFF, + SAREG, T16, + STWO, TANY, + 0, RLEFT, + " shl AL,#1\n shl AL,#1\n", }, + +/* r/m <<= r */ +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, T16, + SHCH, T8, + NSPECIAL, RLEFT, + " shl AL,AR\n", }, + +{ LS, INCH|FOREFF, + SHCH|SNAME|SOREG, T8, + SONE, TANY, + NSPECIAL, RLEFT, + " sal AL,#1\n", }, + +{ LS, INCH|FOREFF, + SHCH, T8, + STWO, TANY, + NSPECIAL, RLEFT, + " sal AL,#1\n sal AL,#1", }, + +{ LS, INCH|FOREFF, + SHCH|SNAME|SOREG, T8, + SHCH, T8, + NSPECIAL, RLEFT, + " sal AL,AR\n", }, + +/* (u)long right shift is emulated. Use a 16bit register so the push + comes out sanely */ +{ RS, INCREG, + SCREG, T32, + SHCH, T8, + 0, RLEFT, + "ZO", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TINT, + SHCH, T8, + NSPECIAL, RLEFT, + " sar AL,AR\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TINT, + SONE, TANY, + NSPECIAL, RLEFT, + " sar AL,#1\n", }, + +{ RS, INAREG|FOREFF, + SAREG, TINT, + STWO, TANY, + NSPECIAL, RLEFT, + " sar AL,#1\n sar AL,#1", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUNSIGNED|TPOINT, + SHCH, T8, + NSPECIAL, RLEFT, + " shr AL,AR\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUNSIGNED, + SONE, TANY, + 0, RLEFT, + " shr AL,#1\n", }, + +{ RS, INAREG|FOREFF, + SAREG, TUNSIGNED, + STWO, TANY, + 0, RLEFT, + " shr AL,#1 shr AL,#1\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SHCH, T8, + NSPECIAL, RLEFT, + " sar AL,AR\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SONE, TANY, + NSPECIAL, RLEFT, + " sar AL,#1\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + STWO, TANY, + NSPECIAL, RLEFT, + " sar AL,#1\n sar AL,#1\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SHCH, T8, + NSPECIAL, RLEFT, + " shr AL,AR\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SONE, TANY, + NSPECIAL, RLEFT, + " shr AL,#1\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + STWO, TANY, + NSPECIAL, RLEFT, + " shr AL,#1\n shr AL,#1\n", }, + +/* + * The next rules takes care of assignments. "=". + */ + +{ ASSIGN, FORCC|FOREFF|INL, + SHL, T32, + SMIXOR, TANY, + 0, RDEST, + " xor AL,AL\n xor UL,UL\n", }, + +{ ASSIGN, FORCC|FOREFF|INL, + SHL, T32, + SMILWXOR, TANY, + 0, RDEST, + " xor AL,AL\n mov UR,UL\n", }, + +{ ASSIGN, FORCC|FOREFF|INL, + SHL, T32, + SMIHWXOR, TANY, + 0, RDEST, + " mov AL,AR\n xor UL,UL\n", }, + +{ ASSIGN, FOREFF|INL, + SHL, T32, + SCON, TANY, + 0, RDEST, + " mov AL,AR\n mov UL,UR\n", }, + +{ ASSIGN, FOREFF, + SHL|SNAME|SOREG, T32, + SCON, TANY, + 0, 0, + " mov AL,AR\n mov UL,UR\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TP16, + SCON, TANY, + 0, 0, + " mov AL, AR\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TP16, + SCON, TANY, + 0, RDEST, + " mov AL, AR\n", }, + +{ ASSIGN, FOREFF, + SHCH|SNAME|SOREG, T8, + SCON, TANY, + 0, 0, + " mov AL, AR\n", }, + +{ ASSIGN, FOREFF|INCH, + SHCH, T8, + SCON, TANY, + 0, RDEST, + " mov AL, AR\n", }, + +{ ASSIGN, FOREFF|INL, + SNAME|SOREG, T32, + SHL, T32, + 0, RDEST, + " mov AL,AR\n mov UL,UR\n", }, + +{ ASSIGN, FOREFF|INL, + SHL, T32, + SHL, T32, + 0, RDEST, + "ZH", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TP16, + SAREG, TP16, + 0, RDEST, + " mov AL,AR\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TP16, + SAREG|SNAME|SOREG, TP16, + 0, RDEST, + " mov AL,AR\n", }, + +{ ASSIGN, FOREFF|INCH, + SHCH|SNAME|SOREG, T8, + SHCH, T8|T16, + 0, RDEST, + " mov AL,AR\n", }, + +{ ASSIGN, INDREG|FOREFF, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + "", }, /* This will always be in the correct register */ + +/* order of table entries is very important here! */ +{ ASSIGN, INFL, + SNAME|SOREG, TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fstpt AL\n fldt AL\n", }, /* XXX */ + +{ ASSIGN, FOREFF, + SNAME|SOREG, TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstpt AL\n", }, + +{ ASSIGN, INFL, + SNAME|SOREG, TDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fstl AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstpl AL\n", }, + +{ ASSIGN, INFL, + SNAME|SOREG, TFLOAT, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fsts AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TFLOAT, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstps AL\n", }, +/* end very important order */ + +{ ASSIGN, INFL|FOREFF, + SHFL, TLDOUBLE, + SHFL|SOREG|SNAME, TLDOUBLE, + 0, RDEST, + " fldt AR\n", }, + +{ ASSIGN, INFL|FOREFF, + SHFL, TDOUBLE, + SHFL|SOREG|SNAME, TDOUBLE, + 0, RDEST, + " fldl AR\n", }, + +{ ASSIGN, INFL|FOREFF, + SHFL, TFLOAT, + SHFL|SOREG|SNAME, TFLOAT, + 0, RDEST, + " flds AR\n", }, + +/* Do not generate memcpy if return from funcall */ +#if 0 +{ STASG, INAREG|FOREFF, + SOREG|SNAME|SAREG, TPTRTO|TSTRUCT, + SFUNCALL, TPTRTO|TSTRUCT, + 0, RRIGHT, + "", }, +#endif + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG, TPTRTO|TANY, + NSPECIAL|NAREG, RDEST, + "F mov A1,si\nZQF mov si,A1\n", }, + +/* + * DIV/MOD/MUL + */ +/* long div is emulated */ +{ DIV, INCREG, + SCREG|SNAME|SOREG|SCON, T32, + SCREG|SNAME|SOREG|SCON, T32, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +/* REVIEW We can only do (i)divb ax/byte and (i)divw (dx:ax)/word + and the results are always in ah/al (remainer/mod) + or dx:ax (dx = remainer, ax = mod) + + Power of two needs to be done by shifts. For other cases of constants + we need to implement two things + 1. Spotting add sequences for constants with few 1 bits on one side + 2. Spotting cases we can compute the magic constant to multiply with for + the same result */ + + +{ DIV, INAREG, + SAREG, TUNSIGNED|TPOINT, + SAREG|SNAME|SOREG, TUNSIGNED|TPOINT, + NSPECIAL, RDEST, + " xor dx,dx\n divw AR\n", }, + +{ DIV, INCH, + SHCH, TUCHAR, + SHCH|SNAME|SOREG, TUCHAR, + NSPECIAL, RDEST, + " xor ah,ah\n divb AR\n", }, + +{ DIV, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fdivl AR\n", }, + +{ DIV, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fdivZAp\n", }, + +/* (u)long mod is emulated */ +{ MOD, INCREG, + SCREG|SNAME|SOREG|SCON, T32, + SCREG|SNAME|SOREG|SCON, T32, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ MOD, INAREG, + SAREG, TP16, + SAREG|SNAME|SOREG, TP16, + NAREG|NSPECIAL, RESC1, + " xor dx,dx\n divw AR\n", }, + +{ MOD, INCH, + SHCH, TUCHAR, + SHCH|SNAME|SOREG, TUCHAR, + NBREG|NSPECIAL, RESC1, + " xor ah,ah\n divb AR\n", }, + +/* (u)long mul is emulated */ +/* On 8086 we can only do multiplies of al * value into ax (for 8bit) + or ax * value into dx:ax for 16bit + + 80186 allows us to do a signed multiply of a register with a constant + into a second register + + Same about shifts, and add optimisations applies here too */ + +/* 32bit mul is emulated (for now) */ +{ MUL, INCREG, + SCREG|SNAME|SOREG|SCON, T32, + SCREG|SNAME|SOREG|SCON, T32, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +/* FIMXE: need special rules */ +{ MUL, INAREG, + SAREG, T16|TPOINT, + SAREG|SNAME|SOREG, T16|TPOINT, + NSPECIAL, RDEST, + " mul AR\n", }, + +{ MUL, INCH, + SHCH, T8, + SHCH|SNAME|SOREG, T8, + NSPECIAL, RDEST, + " mulb AR\n", }, + +{ MUL, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fmull AR\n", }, + +{ MUL, INFL, + SHFL , TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fmulp\n", }, + +/* + * Indirection operators. + */ +{ UMUL, INLL, + SANY, TANY, + SOREG, T32, + NCREG, RESC1, + " mov UL,U1\n mov AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TP16, + SOREG, TP16, + NAREG|NASL, RESC1, + " mov AL,A1\n", }, + +{ UMUL, INCH, + SANY, TANY, + SOREG, T8, + NBREG|NBSL, RESC1, + " mov AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG, T16, + NAREG|NASL, RESC1, + " mov AL,A1\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TLDOUBLE, + NDREG|NDSL, RESC1, + " fldt AL\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TDOUBLE, + NDREG|NDSL, RESC1, + " fldl AL\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TFLOAT, + NDREG|NDSL, RESC1, + " flds AL\n", }, + +/* + * Logical/branching operators + */ + +/* Comparisions, take care of everything */ +{ OPLOG, FORCC, + SHL|SOREG|SNAME, T32, + SHL, T32, + 0, 0, + "ZD", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TP16, + SCON|SAREG, TP16, + 0, RESCC, + " cmp AL,AR\n", }, + + +{ OPLOG, FORCC, + SCON|SAREG, TP16, + SAREG|SOREG|SNAME, TP16, + 0, RESCC, + " cmp AL,AR\n", }, + +{ OPLOG, FORCC, + SBREG|SOREG|SNAME, T8, + SCON|SBREG, TANY, + 0, RESCC, + " cmpb AL,AR\n", }, + +{ OPLOG, FORCC, + SCON|SBREG, T8, + SBREG|SOREG|SNAME, TANY, + 0, RESCC, + " cmpb AL,AR\n", }, + +{ OPLOG, FORCC, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RNOP, + "ZG", }, + +{ OPLOG, FORCC, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "diediedie!", }, + +/* AND/OR/ER/NOT */ + +/* FIXME: pcc generates nonsense ands, but they should be fixed somewhere + if possible. In particular it will do the classic 32bit and with a 16bit + 0xFFFF by generating and ax,#ffff and bx,#0 + eg compiling + sum1 = (sum1 & 0xFFFF) + (sum1 >> 16); + writes a pile of crap code. +*/ + + +{ AND, INCREG|FOREFF, + SCREG, T32, + SCREG|SOREG|SNAME, T32, + 0, RLEFT, + " and AR,AL\n and UR,UL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, T16, + SAREG|SOREG|SNAME, T16, + 0, RLEFT, + " and AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, T16, + SCON|SAREG, T16, + 0, RLEFT, + " and AR,AL\n", }, + +{ AND, INBREG|FOREFF, + SBREG|SOREG|SNAME, T8, + SCON|SBREG, T8, + 0, RLEFT, + " and AR,AL\n", }, + +{ AND, INBREG|FOREFF, + SBREG, T8, + SBREG|SOREG|SNAME, T8, + 0, RLEFT, + " and AR,AL\n", }, +/* AND/OR/ER/NOT */ + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jmp LL\n", }, + +#if defined(GCC_COMPAT) || defined(LANG_F77) +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " jmp *AL\n", }, +#endif + +/* + * Convert LTYPE to reg. + */ +{ OPLTYPE, FORCC|INL, + SCREG, T32, + SMIXOR, TANY, + NCREG, RESC1, + " xor U1,U1\n xor A1,A1\n", }, + +{ OPLTYPE, FORCC|INL, + SCREG, T32, + SMILWXOR, TANY, + NCREG, RESC1, + " mov U1,UL\n xor A1,A1\n", }, + +{ OPLTYPE, FORCC|INL, + SCREG, T32, + SMIHWXOR, TANY, + NCREG, RESC1, + " xor U1,U1\n mov A1,AL\n", }, + +{ OPLTYPE, INL, + SANY, TANY, + SCREG, T32, + NCREG, RESC1, + "ZK", }, + +{ OPLTYPE, INL, + SANY, TANY, + SCON|SOREG|SNAME, T32, + NCREG, RESC1, + " mov U1,UL\n mov A1,AL\n", }, + +{ OPLTYPE, FORCC|INAREG, + SAREG, TP16, + SMIXOR, TANY, + NAREG|NASL, RESC1, + " xor A1,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TP16, + NAREG|NASL, RESC1, + " mov A1,AL\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG|SOREG|SNAME|SCON, T8, + NBREG, RESC1, + " mov A1,AL\n", }, + +{ OPLTYPE, FORCC|INAREG, + SAREG, T16, + SMIXOR, TANY, + NAREG, RESC1, + " xor A1,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SOREG|SNAME|SCON, T16, + NAREG, RESC1, + " mov A1,AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TLDOUBLE, + SOREG|SNAME, TLDOUBLE, + NDREG, RESC1, + " fldt AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TDOUBLE, + SOREG|SNAME, TDOUBLE, + NDREG, RESC1, + " fldl AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TFLOAT, + SOREG|SNAME, TFLOAT, + NDREG, RESC1, + " flds AL\n", }, + +/* Only used in ?: constructs. The stack already contains correct value */ +{ OPLTYPE, INDREG, + SANY, TFLOAT|TDOUBLE|TLDOUBLE, + SDREG, TFLOAT|TDOUBLE|TLDOUBLE, + NDREG, RESC1, + "", }, + +/* + * Negate a word. + */ + +{ UMINUS, INCREG|FOREFF, + SCREG, T32, + SCREG, T32, + 0, RLEFT, + " neg AL\n adc UL,#0\n neg UL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TP16, + SAREG, TP16, + 0, RLEFT, + " neg AL\n", }, + +{ UMINUS, INBREG|FOREFF, + SBREG, T8, + SBREG, T8, + 0, RLEFT, + " neg AL\n", }, + +{ UMINUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fchs\n", }, + +{ COMPL, INCREG, + SCREG, T32, + SANY, TANY, + 0, RLEFT, + " not AL\n not UL\n", }, + +{ COMPL, INAREG, + SAREG, T16, + SANY, TANY, + 0, RLEFT, + " not AL\n", }, + +{ COMPL, INBREG, + SBREG, T8, + SANY, TANY, + 0, RLEFT, + " not AL\n", }, + +/* + * Arguments to functions. + * + * char has already been promoted to integer types + */ + +/* Push immediate not 8086... Loading a register and pushing costs us + 4 + 11 clocks, loading memory would cost us 16 + EA */ +{ FUNARG, FOREFF, + /*SCON|*/SCREG|SNAME|SOREG, T32, + SANY, T32, + 0, RNULL, + " push UL\n push AL\n", }, + +{ FUNARG, FOREFF, + /*SCON|*/SAREG|SNAME|SOREG, T16|TPOINT, + SANY, TP16, + 0, RNULL, + " push AL\n", }, + +/* FIXME: FPU needs reworking into 4 regs or a memcpy */ +{ FUNARG, FOREFF, + SNAME|SOREG, TDOUBLE, + SANY, TDOUBLE, + 0, 0, + " pushl UL\n pushl AL\n", }, + +{ FUNARG, FOREFF, + SDREG, TDOUBLE, + SANY, TDOUBLE, + 0, 0, + " sub sp,#8\n fstpl [sp]\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " push UL\n push AL\n", }, + +{ FUNARG, FOREFF, + SDREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " sub sp,#4\n fstps [sp]\n", }, + +{ FUNARG, FOREFF, + SDREG, TLDOUBLE, + SANY, TLDOUBLE, + 0, 0, + " sub sp,#12\n fstpt [sp]\n", }, + +{ STARG, FOREFF, + SAREG, TPTRTO|TSTRUCT, + SANY, TSTRUCT, + NSPECIAL, 0, + "ZF", }, + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +/* { INIT, DF(INIT), }, */ + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/m16c/TODO b/lang/pcc/pcc/arch/m16c/TODO new file mode 100644 index 000000000..5ef0ba4b4 --- /dev/null +++ b/lang/pcc/pcc/arch/m16c/TODO @@ -0,0 +1 @@ +* Mul/Div does not work. \ No newline at end of file diff --git a/lang/pcc/pcc/arch/m16c/code.c b/lang/pcc/pcc/arch/m16c/code.c new file mode 100644 index 000000000..cbad1edab --- /dev/null +++ b/lang/pcc/pcc/arch/m16c/code.c @@ -0,0 +1,333 @@ +/* $Id: code.c,v 1.25 2014/05/29 19:20:02 plunky Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +/* + * cause the alignment to become a multiple of n + */ +void +defalign(int n) +{ +#if 0 + char *s; + + n /= SZCHAR; + if (lastloc == PROG || n == 1) + return; + s = (isinlining ? permalloc(40) : tmpalloc(40)); + sprintf(s, "\t.align %d\n", n); + send_passt(IP_ASM, s); +#endif +} + +/* + * define the current location as the name p->soname + */ +void +defnam(struct symtab *p) +{ + char *c = p->soname; + + if (p->sclass == EXTDEF) + printf(" PUBLIC %s\n", c); + printf("%s:\n", c); +} + + +/* + * code for the end of a function + * deals with struct return here + */ +void +efcode(void) +{ + NODE *p, *q; + int sz; + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + /* address of return struct is in eax */ + /* create a call to memcpy() */ + /* will get the result in eax */ + p = block(REG, NIL, NIL, CHAR+PTR, 0, 0); + p->n_rval = R0; + q = block(OREG, NIL, NIL, CHAR+PTR, 0, 0); + q->n_rval = FB; + q->n_lval = 8; /* return buffer offset */ + p = block(CM, q, p, INT, 0, 0); + sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR; + p = block(CM, p, bcon(sz), INT, 0, 0); + p->n_right->n_name = ""; + p = block(CALL, bcon(0), p, CHAR+PTR, 0, 0); + p->n_left->n_name = "memcpy"; + send_passt(IP_NODE, p); +} + +/* + * helper for bfcode() to put register arguments on stack. + */ +static void +argmove(struct symtab *s, int regno) +{ + NODE *p, *r; + + s->sclass = AUTO; + s->soffset = NOOFFSET; + oalloc(s, &autooff); + p = nametree(s); + r = bcon(0); + r->n_op = REG; + r->n_rval = regno; + r->n_type = p->n_type; + r->n_sue = p->n_sue; + r->n_df = p->n_df; + ecode(buildtree(ASSIGN, p, r)); +} + +/* + * code for the beginning of a function; a is an array of + * indices in symtab for the arguments; n is the number + * On m16k, space is allocated on stack for register arguments, + * arguments are moved to the stack and symtab is updated accordingly. + */ +void +bfcode(struct symtab **a, int n) +{ + struct symtab *s; + int i, r0l, r0h, a0, r2, sz, hasch, stk; + int argoff = ARGINIT; + + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + /* Function returns struct, adjust arg offset */ + for (i = 0; i < n; i++) + a[i]->soffset += SZPOINT(INT); + } + /* first check if there are 1-byte parameters */ + for (hasch = i = 0; i < n && i < 6; i++) + if (DEUNSIGN(a[i]->stype) == CHAR) + hasch = 1; + + stk = r0l = r0h = a0 = r2 = 0; + for (i = 0; i < n; i++) { + s = a[i]; + sz = tsize(s->stype, s->sdf, s->ssue); + if (ISPTR(s->stype) && ISFTN(DECREF(s->stype))) + sz = SZLONG; /* function pointers are always 32 */ + if (stk == 0) + switch (sz) { + case SZCHAR: + if (r0l) { + if (r0h) + break; + argmove(s, 1); + r0h = 1; + } else { + argmove(s, 0); + r0l = 1; + } + continue; + + case SZINT: + if (s->stype > BTMASK) { + /* is a pointer */ + if (a0) { + if (r0l || hasch) { + if (r2) + break; + argmove(s, R2); + r2 = 1; + } else { + argmove(s, R0); + r0l = r0h = 1; + } + } else { + argmove(s, A0); + a0 = 1; + } + } else if (r0l || hasch) { + if (r2) { + if (a0) + break; + argmove(s, A0); + a0 = 1; + } else { + argmove(s, R2); + r2 = 1; + } + } else { + argmove(s, R0); + r0l = r0h = 1; + } + continue; + case SZLONG: + if (r0l||r0h||r2) + break; + argmove(s, R0); + r0l = r0h = r2 = 1; + continue; + + default: + break; + } + stk = 1; + s->soffset = argoff; + argoff += sz; + } +} + +/* + * Add a symbol to an internal list printed out at the end. + */ +void addsym(struct symtab *); +static struct symlst { + struct symlst *next; + struct symtab *sp; +} *sympole; + +void +addsym(struct symtab *q) +{ + struct symlst *w = sympole; + + if (q == NULL) + return; + + while (w) { + if (q == w->sp) + return; /* exists */ + w = w->next; + } + w = permalloc(sizeof(struct symlst)); + w->sp = q; + w->next = sympole; + sympole = w; +} + +struct caps { + char *cap, *stat; +} caps[] = { + { "__64bit_doubles", "Disabled" }, + { "__calling_convention", "Normal" }, + { "__constant_data", "near" }, + { "__data_alignment", "2" }, + { "__data_model", "near" }, + { "__processor", "M16C" }, + { "__rt_version", "1" }, + { "__variable_data", "near" }, + { NULL, NULL }, +}; + +/* + * Called before parsing begins. + */ +void +bjobcode(void) +{ + struct caps *c; + + printf(" NAME gurka.c\n"); /* Don't have the name */ + for (c = caps; c->cap; c++) + printf(" RTMODEL \"%s\", \"%s\"\n", c->cap, c->stat); + //printf(" RSEG CODE:CODE:REORDER:NOROOT(0)\n"); +} + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ + struct symlst *w = sympole; + + for (w = sympole; w; w = w->next) { + if (w->sp->sclass != EXTERN) + continue; + printf(" EXTERN %s\n", w->sp->soname); + } + + printf(" END\n"); +} + +/* + * Print character t at position i in one string, until t == -1. + * Locctr & label is already defined. + */ +void +bycode(int t, int i) +{ + static int lastoctal = 0; + + /* put byte i+1 in a string */ + + if (t < 0) { + if (i != 0) + puts("\""); + } else { + if (i == 0) + printf("\t.ascii \""); + if (t == '\\' || t == '"') { + lastoctal = 0; + putchar('\\'); + putchar(t); + } else if (t < 040 || t >= 0177) { + lastoctal++; + printf("\\%o",t); + } else if (lastoctal && '0' <= t && t <= '9') { + lastoctal = 0; + printf("\"\n\t.ascii \"%c", t); + } else { + lastoctal = 0; + putchar(t); + } + } +} + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + */ +NODE * +funcode(NODE *p) +{ + return p; +} diff --git a/lang/pcc/pcc/arch/m16c/local.c b/lang/pcc/pcc/arch/m16c/local.c new file mode 100644 index 000000000..259427bf6 --- /dev/null +++ b/lang/pcc/pcc/arch/m16c/local.c @@ -0,0 +1,454 @@ +/* $Id: local.c,v 1.22 2015/08/18 10:15:08 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +/* this file contains code which is dependent on the target machine */ + +NODE * +clocal(NODE *p) +{ + /* this is called to do local transformations on + an expression tree preparitory to its being + written out in intermediate code. + */ + + /* the major essential job is rewriting the + automatic variables and arguments in terms of + REG and OREG nodes */ + /* conversion ops which are not necessary are also clobbered here */ + /* in addition, any special features (such as rewriting + exclusive or) are easily handled here as well */ + + struct symtab *q; + NODE *l, *r; + int o; + TWORD ml; + + switch( o = p->n_op ){ + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + r->n_lval = 0; + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case STATIC: + if (q->slevel == 0) + break; + p->n_lval = 0; + p->n_sp = q; + break; + + case REGISTER: + p->n_op = REG; + p->n_lval = 0; + p->n_rval = q->soffset; + break; + + } + break; + + case PCONV: + ml = p->n_left->n_type; + l = p->n_left; + if ((ml == CHAR || ml == UCHAR) && l->n_op != ICON) + break; + l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_sue = p->n_sue; + nfree(p); + p = l; + break; + + case SCONV: + l = p->n_left; + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT) { + nfree(p); + return l; + } + if (l->n_op == ICON) { + CONSZ val = l->n_lval; + switch (p->n_type) { + case CHAR: + l->n_lval = (char)val; + break; + case UCHAR: + l->n_lval = val & 0377; + break; + case SHORT: + case INT: + l->n_lval = (short)val; + break; + case USHORT: + case UNSIGNED: + l->n_lval = val & 0177777; + break; + case ULONG: + case ULONGLONG: + l->n_lval = val & 0xffffffff; + break; + case LONG: + case LONGLONG: + l->n_lval = (int)val; + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = val; + break; + default: + cerror("unknown type %d", p->n_type); + } + l->n_type = p->n_type; + nfree(p); + return l; + } + break; + + + } + + return(p); +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * is an automatic variable of type t OK for a register variable + */ +int +cisreg(TWORD t) +{ + if (t == INT || t == UNSIGNED || t == CHAR || t == UCHAR || + ISPTR(t)) + return(1); + return 0; /* XXX - fix reg assignment in pftn.c */ +} + + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a NAME node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + if ((off % SZINT) == 0) + p = buildtree(MUL, p, bcon(off/SZINT)); + else if ((off % SZSHORT) == 0) { + p = buildtree(MUL, p, bcon(off/SZSHORT)); + p = buildtree(PLUS, p, bcon(1)); + p = buildtree(RS, p, bcon(1)); + } else if ((off % SZCHAR) == 0) { + p = buildtree(MUL, p, bcon(off/SZCHAR)); + p = buildtree(PLUS, p, bcon(3)); + p = buildtree(RS, p, bcon(2)); + } else + cerror("roundsp"); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); + sp->n_lval = 0; + sp->n_rval = STKREG; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + + /* add the size to sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(PLUSEQ, sp, p)); +} + +/* + * print out a constant node + * mat be associated with a label + */ +int +ninval(NODE *p) +{ + struct symtab *q; + TWORD t; + + p = p->n_left; + t = p->n_type; + if (t > BTMASK) + t = p->n_type = INT; /* pointer */ + + switch (t) { + case LONGLONG: + case ULONGLONG: + inval(p->n_lval & 0xffffffff); + inval(p->n_lval >> 32); + break; + case LONG: + case ULONG: + case INT: + case UNSIGNED: + printf("\t.long 0x%x", (int)p->n_lval); + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0)) { + printf("+" LABFMT, q->soffset); + } else + printf("+%s", exname(q->soname)); + } + printf("\n"); + break; + default: + fwalk(p, eprint, 0); + return 0; + } + return 1; +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ + if (p == NULL) + return ""; + return p; +} + +/* + * map types which are not defined on the local machine + */ +TWORD +ctype(TWORD type) +{ + switch (BTYPE(type)) { + case SHORT: + MODTYPE(type,INT); + break; + + case USHORT: + MODTYPE(type,UNSIGNED); + break; + + case LONGLONG: + MODTYPE(type,LONG); + break; + + case ULONGLONG: + MODTYPE(type,ULONG); + break; + + case LDOUBLE: + MODTYPE(type,DOUBLE); + break; + } + return (type); +} + +/* curid is a variable which is defined but + * is not initialized (and not a function ); + * This routine returns the storage class for an uninitialized declaration + */ +int +noinit() +{ + return(EXTERN); +} + +/* + * Extern variable not necessary common. + */ +void +extdec(struct symtab *q) +{ + extern void addsym(struct symtab *); + addsym(q); +} + +/* + * Call to a function + */ +void +calldec(NODE *p, NODE *r) +{ + struct symtab *q = p->n_sp; + extern void addsym(struct symtab *); + addsym(q); +} + +/* make a common declaration for id, if reasonable */ +void +commdec(struct symtab *q) +{ + int off; + char *c = q->soname; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + + printf(" PUBLIC %s\n", c); + /* XXX - NOROOT??? */ + printf(" RSEG DATA16_Z:NEARDATA:SORT:NOROOT(1)\n"); + printf("%s:\n", c); + printf(" DS8 %d\n", off); + printf(" REQUIRE __data16_zero\n"); +} + +/* make a local common declaration for id, if reasonable */ +void +lcommdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + if (q->slevel == 0) + printf(" .lcomm %s,0%o\n", exname(q->soname), off); + else + printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off); +} + +/* + * print a (non-prog) label. + */ +void +deflab1(int label) +{ + printf(LABFMT ":\n", label); +} + +void +setloc1(int locc) +{ + if (locc == lastloc) + return; + lastloc = locc; +} + +/* + * special handling before tree is written out. + */ +void +myp2tree(NODE *p) +{ + struct symtab *sp; + union dimfun *df; + union arglist *al; + NODE *q; + int i; + + switch (p->n_op) { + case MOD: + case DIV: + if (p->n_type == LONG || p->n_type == ULONG) { + /* Swap arguments for hardops() later */ + q = p->n_left; + p->n_left = p->n_right; + p->n_right = q; + } + break; + + case CALL: + case STCALL: + /* + * inform pass2 about varargs. + * store first variadic argument number in n_stalign + * in the CM node. + */ + if (p->n_right->n_op != CM) + break; /* nothing to care about */ + df = p->n_left->n_df; + if (df && (al = df->dfun)) { + for (i = 0; i < 6; i++, al++) { + if (al->type == TELLIPSIS || al->type == TNULL) + break; + } + p->n_right->n_stalign = al->type == TELLIPSIS ? i : 0; + } else + p->n_right->n_stalign = 0; + break; + + case FCON: + /* Write float constants to memory */ + sp = tmpalloc(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->ssue = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + + defloc(sp); + ninval(0, sp->ssue->suesize, p); + + p->n_op = NAME; + p->n_lval = 0; + p->n_sp = sp; + break; + } + +} + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char **ary) +{ + return 0; +} + +/* + * Called when a identifier has been declared, to give target last word. + */ +void +fixdef(struct symtab *sp) +{ +} + +void +pass1_lastchance(struct interpass *ip) +{ +} diff --git a/lang/pcc/pcc/arch/m16c/local2.c b/lang/pcc/pcc/arch/m16c/local2.c new file mode 100644 index 000000000..f3f63d821 --- /dev/null +++ b/lang/pcc/pcc/arch/m16c/local2.c @@ -0,0 +1,664 @@ +/* $Id: local2.c,v 1.43 2015/01/04 19:17:23 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" +# include + +void acon(NODE *p); +int argsize(NODE *p); +void genargs(NODE *p); + +static int ftlab1, ftlab2; + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static TWORD ftype; +static int addto; + +void +prologue(struct interpass_prolog *ipp) +{ + ftype = ipp->ipp_type; + +#if 0 + if (ipp->ipp_regs > 0 && ipp->ipp_regs != MINRVAR) + comperr("fix prologue register savings", ipp->ipp_regs); +#endif + + printf(" RSEG CODE:CODE:REORDER:NOROOT(0)\n"); + if (ipp->ipp_vis) + printf(" PUBLIC %s\n", ipp->ipp_name); + printf("%s:\n", ipp->ipp_name); + +#if 0 + if (xsaveip) { + /* Optimizer running, save space on stack */ + addto = (p2maxautooff - AUTOINIT)/SZCHAR; + printf(" enter #%d\n", addto); + } else { +#endif + + /* non-optimized code, jump to epilogue for code generation */ + ftlab1 = getlab2(); + ftlab2 = getlab2(); + printf(" jmp.w " LABFMT "\n", ftlab1); + deflab(ftlab2); +} + +/* + * End of block. + */ +void +eoftn(struct interpass_prolog *ipp) +{ +#if 0 + if (ipp->ipp_regs != MINRVAR) + comperr("fix eoftn register savings %x", ipp->ipp_regs); +#endif + + // if (xsaveip == 0) + addto = (p2maxautooff - AUTOINIT)/SZCHAR; + + /* return from function code */ + //deflab(ipp->ipp_ip.ip_lbl); //XXX - is this necessary? + + /* If retval is a pointer and not a function pointer, put in A0 */ + if (ISPTR(DECREF(ipp->ipp_type)) && + !ISFTN(DECREF(DECREF(ipp->ipp_type)))) + printf(" mov.w r0,a0\n"); + + /* struct return needs special treatment */ + if (ftype == STRTY || ftype == UNIONTY) { + comperr("fix struct return in eoftn"); + } else + printf(" exitd\n"); + + /* Prolog code */ + // if (xsaveip == 0) { + deflab(ftlab1); + printf(" enter #%d\n", addto); + printf(" jmp.w " LABFMT "\n", ftlab2); + //} +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s.%c", str, f); +} + +char * +rnames[] = { /* keyed to register number tokens */ + "r0", "r2", "r1", "r3", "a0", "a1", "fb", "sp", "r0h", "r0l", + "r1h", "r1l", +}; + +/* + * Return the size (in bytes) of some types. + */ +int +tlen(p) NODE *p; +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case INT: + case UNSIGNED: + case FLOAT: + return 2; + + case DOUBLE: + case LONG: + case ULONG: + return 4; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +/* + * Emit code to compare two longlong numbers. + */ +static void +twollcomp(NODE *p) +{ + int o = p->n_op; + int s = getlab2(); + int e = p->n_label; + int cb1, cb2; + + if (o >= ULE) + o -= (ULE-LE); + switch (o) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 4, cb2 += 4; + expand(p, 0, " cmp.w UR,UL\n"); + if (cb1) cbgen(cb1, s); + if (cb2) cbgen(cb2, e); + expand(p, 0, " cmp.w AR,AL\n"); + cbgen(p->n_op, e); + deflab(s); +} + + +void +zzzcode(NODE *p, int c) +{ + NODE *l; + + switch (c) { + case 'A': /* print negative shift constant */ + p = getlr(p, 'R'); + if (p->n_op != ICON) + comperr("ZA bad use"); + p->n_lval = -p->n_lval; + adrput(stdout, p); + p->n_lval = -p->n_lval; + break; + + case 'B': + if (p->n_rval) + printf(" add.b #%d,%s\n", + p->n_rval, rnames[STKREG]); + break; + + case 'C': /* Print label address */ + p = p->n_left; + if (p->n_lval) + printf(LABFMT, (int)p->n_lval); + else + printf("%s", p->n_name); + break; + + case 'D': /* copy function pointers */ + l = p->n_left; + printf("\tmov.w #HWRD(%s),%s\n\tmov.w #LWRD(%s),%s\n", + p->n_right->n_name, rnames[l->n_rval+1], + p->n_right->n_name, rnames[l->n_rval]); + break; + + case 'E': /* double-reg printout */ + /* XXX - always r0r2 here */ + printf("%s%s", rnames[R0], rnames[R2]); + break; + + case 'F': /* long comparisions */ + twollcomp(p); + break; + + case 'G': + printf("R0R2"); + break; + + case 'H': /* push 32-bit address (for functions) */ + printf("\tpush.w #HWRD(%s)\n\tpush.w #LWRD(%s)\n", + p->n_left->n_name, p->n_left->n_name); + break; + + case 'I': /* push 32-bit address (for functions) */ + l = p->n_left; + printf("\tpush.w %d[%s]\n\tpush.w %d[%s]\n", + (int)l->n_lval, rnames[l->n_rval], + (int)l->n_lval+2, rnames[l->n_rval]); + break; + + default: + comperr("bad zzzcode %c", c); + } +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left, SOREG) == SRDIR)) + return(1); + return(0); +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + return 0; +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + int o = p->n_op; + + if (o == OREG || o == REG || o == NAME) + return SRDIR; /* Direct match */ + if (o == UMUL && shumul(p->n_left, SOREG)) + return SROREG; /* Convert into oreg */ + return SRREG; /* put it into a register */ +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + return 0; +} + +void +adrcon(CONSZ val) +{ + printf("$" CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + int val = p->n_lval; + + switch (p->n_op) { + case ICON: + if (p->n_name[0] != '\0') { + fprintf(fp, "%s", p->n_name); + if (val) + fprintf(fp, "+%d", val); + } else + fprintf(fp, "%d", val); + return; + + default: + comperr("illegal conput"); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + + size /= SZINT; + switch (p->n_op) { + case REG: + printf("%s", rnames[p->n_rval + 1]); + break; + + case NAME: + case OREG: + p->n_lval += size; + adrput(stdout, p); + p->n_lval -= size; + break; + case ICON: + printf("#" CONFMT, p->n_lval >> 16); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *io, NODE *p) +{ + /* output an address, with offsets, from p */ + + if (p->n_op == FLD) + p = p->n_left; + + switch (p->n_op) { + + case NAME: + if (p->n_name[0] != '\0') + fputs(p->n_name, io); + if (p->n_lval != 0) + fprintf(io, "+" CONFMT, p->n_lval); + return; + + case OREG: + if (p->n_lval) + fprintf(io, "%d", (int)p->n_lval); + fprintf(io, "[%s]", rnames[p->n_rval]); + return; + case ICON: + /* addressable value of the constant */ + fputc('#', io); + conput(io, p); + return; + + case REG: + /*if (DEUNSIGN(p->n_type) == CHAR) { + fprintf(io, "R%c%c", p->n_rval < 2 ? '0' : '1', + (p->n_rval & 1) ? 'H' : 'L'); + } else*/ + fprintf(io, "%s", rnames[p->n_rval]); + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +static char * +ccbranches[] = { + "jeq", /* jumpe */ + "jne", /* jumpn */ + "jle", /* jumple */ + "jlt", /* jumpl */ + "jge", /* jumpge */ + "jgt", /* jumpg */ + "jleu", /* jumple (jlequ) */ + "jltu", /* jumpl (jlssu) */ + "jgeu", /* jumpge (jgequ) */ + "jgtu", /* jumpg (jgtru) */ +}; + + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + if (o < EQ || o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); +} + +void +mycanon(NODE *p) +{ +} + +void +myoptim(struct interpass *ip) +{ +} + +#if 0 +void +mygenregs(NODE *p) +{ + + if (p->n_op == MINUS && p->n_type == DOUBLE && + (p->n_su & (LMASK|RMASK)) == (LREG|RREG)) { + p->n_su |= DORIGHT; + } + /* Must walk down correct node first for logops to work */ + if (p->n_op != CBRANCH) + return; + p = p->n_left; + if ((p->n_su & (LMASK|RMASK)) != (LREG|RREG)) + return; + p->n_su &= ~DORIGHT; + +} +#endif + +struct hardops hardops[] = { + { PLUS, FLOAT, "?F_ADD_L04" }, + { MUL, LONG, "?L_MUL_L03" }, + { MUL, ULONG, "?L_MUL_L03" }, + { DIV, LONG, "?SL_DIV_L03" }, + { DIV, ULONG, "?UL_DIV_L03" }, + { MOD, LONG, "?SL_MOD_L03" }, + { MOD, ULONG, "?UL_MOD_L03" }, + { RS, LONGLONG, "__ashrdi3" }, + { RS, ULONGLONG, "__lshrdi3" }, + { LS, LONGLONG, "__ashldi3" }, + { LS, ULONGLONG, "__ashldi3" }, + { 0 }, +}; + +int +special(NODE *p, int shape) +{ + switch (shape) { + case SFTN: + if (ISPTR(p->n_type) && ISFTN(DECREF(p->n_type))) { + if (p->n_op == NAME || p->n_op == OREG) + return SRDIR; + else + return SRREG; + } + break; + } + return SRNOPE; +} + +void +myreader(NODE *p) +{ + NODE *q, *r, *s, *right; + + if (optype(p->n_op) == LTYPE) + return; + if (optype(p->n_op) != UTYPE) + myreader(p->n_right); + myreader(p->n_left); + + switch (p->n_op) { + case PLUS: + case MINUS: + if (p->n_type != LONG && p->n_type != ULONG) + break; + if (p->n_right->n_op == NAME || p->n_right->n_op == OREG) + break; + /* Must convert right into OREG */ + right = p->n_right; + q = mklnode(OREG, (freetemp(szty(right->n_type))), + FPREG, right->n_type); + s = mkbinode(ASSIGN, q, right, right->n_type); + r = talloc(); + *r = *q; + p->n_right = r; + pass2_compile(ipnode(s)); + break; + } +} + + +void +rmove(int s, int d, TWORD t) +{ + switch (t) { + case CHAR: + case UCHAR: + printf(" mov.b %s,%s\n", rnames[s], rnames[d]); + break; + default: + printf(" mov.w %s,%s\n", rnames[s], rnames[d]); + } +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int c, int *r) +{ + int num; + + switch (c) { + case CLASSA: + num = r[CLASSA]; + num += r[CLASSC]; + return num < 4; + case CLASSB: + num = r[CLASSB]; + return num < 2; + case CLASSC: + num = 2*r[CLASSA]; + num += r[CLASSC]; + return num < 4; + } + return 0; /* XXX gcc */ +} + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t == CHAR || t == UCHAR) + return CLASSC; + + if(ISPTR(t)) + return CLASSB; + + return CLASSA; +} + +static int sizen; + +/* XXX: Fix this. */ +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (t < LONGLONG || t > MAXTYPES) + return 4; + if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) + return 8; + if (t == LDOUBLE) + return 12; + if (t == STRTY) + return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + comperr("argsiz"); + return 0; +} + +/* + * Calculate argument sizes. + * XXX: Fix this. + */ +void +lastcall(NODE *p) +{ + sizen = 0; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + sizen += argsiz(p->n_right); + sizen += argsiz(p); +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ +} +/* + * Do something target-dependent for xasm arguments. + * Supposed to find target-specific constraints and rewrite them. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + return 0; +} diff --git a/lang/pcc/pcc/arch/m16c/macdefs.h b/lang/pcc/pcc/arch/m16c/macdefs.h new file mode 100644 index 000000000..5c095af4b --- /dev/null +++ b/lang/pcc/pcc/arch/m16c/macdefs.h @@ -0,0 +1,195 @@ +/* $Id: macdefs.h,v 1.27 2016/03/05 15:53:04 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Machine-dependent defines for both passes. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<8)>>8); + +#define ARGINIT 40 /* # bits above fp where arguments start */ +#define AUTOINIT 0 /* # bits below fp where automatics start */ + +/* + * Convert (multi-)character constant to integer. + * Assume: If only one value; store at left side (char size), otherwise + * treat it as an integer. + */ + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZINT 16 +#define SZFLOAT 16 +#define SZDOUBLE 16 +#define SZLDOUBLE 16 +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 32 +/* pointers are of different sizes on m16c */ +#define SZPOINT(t) (ISFTN(DECREF(t)) ? 32 : 16) + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALINT 16 +#define ALFLOAT 16 +#define ALDOUBLE 16 +#define ALLDOUBLE 16 +#define ALLONG 16 +#define ALLONGLONG 16 +#define ALSHORT 16 +#define ALPOINT 16 +#define ALSTRUCT 16 +#define ALSTACK 16 + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT -32768 +#define MAX_INT 32767 +#define MAX_UNSIGNED 65535 +#define MIN_LONG -2147483648 +#define MAX_LONG 2147483647 +#define MAX_ULONG 4294967295UL +#define MIN_LONGLONG -2147483648 +#define MAX_LONGLONG 2147483647 +#define MAX_ULONGLONG 4294967295UL + +/* Default char is unsigned */ +#undef CHAR_UNSIGNED + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#define LABFMT "L%d" /* format for printing labels */ + +#define BACKAUTO /* stack grows negatively for automatics */ +#define BACKTEMP /* stack grows negatively for temporaries */ + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_LE + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) 1 + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) +#define genfcall(a,b) gencall(a,b) + +#define szty(t) (((t) == LONG || (t) == ULONG || \ + (ISPTR(t) && ISFTN(DECREF(t)))) ? 2 : 1) + +/* + * m16c register classes: + * A - 16-bit data registers R0-R3 + * B - 16-bit address registers A0-A1 + * C - 8-bit data registers R0H, R0L, R1H, R1L + */ + +#define R0 0 +#define R2 1 +#define R1 2 +#define R3 3 + +#define A0 4 +#define A1 5 +#define FB 6 +#define SP 7 + +#define R0H 8 +#define R0L 9 +#define R1H 10 +#define R1L 11 + +#define NUMCLASS 4 /* Number of register classes */ + +#define RETREG(x) (x == CHAR || x == UCHAR ? R0L : R0) + +#define FPREG FB /* frame pointer */ +#define STKREG SP /* stack pointer */ + +#if 0 +#define REGSZ 8 /* Number of registers */ +#define MINRVAR R1 /* first register variable */ +#define MAXRVAR R2 /* last register variable */ +#endif + +#define MAXREGS 12 /* 12 registers */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|PERMREG, SAREG|TEMPREG, SAREG|PERMREG, \ + SBREG|TEMPREG, SBREG|PERMREG, 0, 0, SCREG, SCREG, SCREG, SCREG, + +#define ROVERLAP \ + {R0H, R0L, -1},\ + {-1},\ + {R1H, R1L, -1},\ + {-1},\ +\ + {-1},\ + {-1},\ +\ + {-1},\ + {-1},\ +\ + {R0, -1},\ + {R0, -1},\ + {R1, -1},\ + {R1, -1}, + +#define PCLASS(p) (p->n_type <= UCHAR ? SCREG : ISPTR(p->n_type) ? SBREG:SAREG) + +int COLORMAP(int c, int *r); +#define GCLASS(x) (x < 4 ? CLASSA : x < 6 ? CLASSB : x < 12 ? CLASSC : CLASSD) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ + +#define MYADDEDGE(x, t) + +#ifndef NEW_READER +//#define TAILCALL +#endif +#define SFTN (SPECIAL|6) diff --git a/lang/pcc/pcc/arch/m16c/order.c b/lang/pcc/pcc/arch/m16c/order.c new file mode 100644 index 000000000..1aaf0fe39 --- /dev/null +++ b/lang/pcc/pcc/arch/m16c/order.c @@ -0,0 +1,621 @@ +/* $Id: order.c,v 1.22 2014/06/01 11:35:02 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" +# include + +int canaddr(NODE *); + +/* + * should the assignment op p be stored, + * given that it lies as the right operand of o + * (or the left, if o==UNARY MUL) + */ +/* +void +stoasg(NODE *p, int o) +{ + if (x2debug) + printf("stoasg(%p, %o)\n", p, o); +} +*/ +/* should we delay the INCR or DECR operation p */ +int +deltest(NODE *p) +{ + return 0; +} + +/* + * Check if p can be autoincremented. + * XXX - nothing can be autoincremented for now. + */ +int +autoincr(NODE *p) +{ + return 0; +} + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + return(0); /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + */ +int +offstar(NODE *p, int shape) +{ + if (x2debug) + printf("offstar(%p)\n", p); + + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( p->n_right->n_op == ICON ){ + geninsn(p->n_left, INBREG); + p->n_su = -1; + return 1; + } + } + geninsn(p, INBREG); + return 0; +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ +// NODE *l = p->n_left; + +#ifdef PCC_DEBUG + if (x2debug) { + printf("shumul(%p)\n", p); + fwalk(p, e2print, 0); + } +#endif + /* XXX - fix */ + + /* Can only generate OREG of BREGs (or FB) */ + if (p->n_op == REG && (isbreg(p->n_rval) || p->n_rval == FB)) + return SROREG; +#if 0 + if ((p->n_op == PLUS || p->n_op == MINUS) && + (l->n_op == REG && (isbreg(l->n_rval) || l->n_rval == FB)) && + p->n_right->n_op == ICON) + return SOREG; + return 0; +#else + return SROREG; +#endif +} + +/* + * Rewrite increment/decrement operation. + */ +int +setincr(NODE *p) +{ + if (x2debug) + printf("setincr(%p)\n", p); + + return(0); +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +#if 0 +/* + * register allocation for instructions with special preferences. + */ +regcode +regalloc(NODE *p, struct optab *q, int wantreg) +{ + regcode regc; + + if (q->op == DIV || q->op == MOD) { + /* + * 16-bit div. + */ + if (regblk[R0] & 1 || regblk[R2] & 1) + comperr("regalloc: needed regs inuse, node %p", p); + if (p->n_su & DORIGHT) { + regc = alloregs(p->n_right, A0); + if (REGNUM(regc) != A0) { + p->n_right = movenode(p->n_right, A0); + if ((p->n_su & RMASK) == ROREG) { + p->n_su &= ~RMASK; + p->n_su |= RREG; + p->n_right->n_su &= ~LMASK; + p->n_right->n_su |= LOREG; + } + freeregs(regc); + regblk[A0] |= 1; + } + } + regc = alloregs(p->n_left, R0); + if (REGNUM(regc) != R0) { + p->n_left = movenode(p->n_left, R0); + freeregs(regc); + regblk[R0] |= 1; + } + if ((p->n_su & RMASK) && !(p->n_su & DORIGHT)) { + regc = alloregs(p->n_right, A0); + if (REGNUM(regc) != A0) { + p->n_right = movenode(p->n_right, A0); + if ((p->n_su & RMASK) == ROREG) { + p->n_su &= ~RMASK; + p->n_su |= RREG; + p->n_right->n_su &= ~LMASK; + p->n_right->n_su |= LOREG; + } + } + } + regblk[A0] &= ~1; + regblk[R0] &= ~1; + regblk[R2] &= ~1; + if (q->op == DIV) { + MKREGC(regc, R0, 1); + regblk[R0] |= 1; + } else { + MKREGC(regc, R2, 1); + regblk[R2] |= 1; + } + } else + comperr("regalloc"); + p->n_rall = REGNUM(regc); + return regc; +} +#endif + +/* + * Special handling of some instruction register allocation. + * - left is the register that left node wants. + * - right is the register that right node wants. + * - res is in which register the result will end up. + * - mask is registers that will be clobbered. + * + * XXX - Fix this function + */ +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + + case DIV: + case MOD: + if(q->ltype & (TINT|TSHORT)){ + static struct rspecial s[] = { + { NRES, R0 }, { NRES, R2}, { 0 } }; + return s; + } + /* + else if(q->ltype & TCHAR) { + static struct rspecial s[] = { + { NRES, R0L }, { NRES, R0H}, { 0 } }; + return s; + }*/ + break; + + case MUL: + /* + if(q->ltype & (TINT|TSHORT)){ + static struct rspecial s[] = { + { NRES, R0 }, { NRES, R2}, { 0 } }; + return s; + }*/ + comperr("multiplication not implemented"); + break; + + default: + break; + } + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + + +/* + * Splitup a function call and give away its arguments first. + * Calling convention used ("normal" in IAR syntax) is: + * - 1-byte parameters in R0L if possible, otherwise in R0H. + * - 2-byte pointers in A0. + * - 2-byte non-pointers in R0 if no byte-size arguments are found in + * in the first 6 bytes of parameters, otherwise R2 or at last A0. + * - 4-byte parameters in R2R0. + */ +void +gencall(NODE *p, NODE *prev) +{ + NODE *n = 0; /* XXX gcc */ + static int storearg(NODE *); + int o = p->n_op; + int ty = optype(o); + + if (ty == LTYPE) + return; + + switch (o) { + case CALL: + /* swap arguments on some hardop-converted insns */ + /* Normal call, just push args and be done with it */ + p->n_op = UCALL; +//printf("call\n"); + /* Check if left can be evaluated directly */ + if (p->n_left->n_op == UMUL) { + TWORD t = p->n_left->n_type; + int k = (freetemp(szty(t))); + NODE *n = mklnode(OREG, k, FB, t); + NODE *q = tcopy(n); + pass2_compile(ipnode(mkbinode(ASSIGN, n, p->n_left,t))); + p->n_left = q; + } + gencall(p->n_left, p); + p->n_rval = storearg(p->n_right); +//printf("end call\n"); + break; + + case UFORTCALL: + case FORTCALL: + comperr("FORTCALL"); + + case USTCALL: + case STCALL: + /* + * Structure return. Look at the node above + * to decide about buffer address: + * - FUNARG, allocate space on stack, don't remove. + * - nothing, allocate space on stack and remove. + * - STASG, get the address of the left side as arg. + * - FORCE, this ends up in a return, get supplied addr. + * (this is not pretty, but what to do?) + */ + if (prev == NULL || prev->n_op == FUNARG) { + /* Create nodes to generate stack space */ + n = mkbinode(ASSIGN, mklnode(REG, 0, STKREG, INT), + mkbinode(MINUS, mklnode(REG, 0, STKREG, INT), + mklnode(ICON, p->n_stsize, 0, INT), INT), INT); +//printf("stsize %d\n", p->n_stsize); + pass2_compile(ipnode(n)); + } else if (prev->n_op == STASG) { + n = prev->n_left; + if (n->n_op == UMUL) + n = nfree(n); + else if (n->n_op == NAME) { + n->n_op = ICON; /* Constant reference */ + n->n_type = INCREF(n->n_type); + } else + comperr("gencall stasg"); + } else if (prev->n_op == FORCE) { + ; /* do nothing here */ + } else { + comperr("gencall bad op %d", prev->n_op); + } + + /* Deal with standard arguments */ + gencall(p->n_left, p); + if (o == STCALL) { + p->n_op = USTCALL; + p->n_rval = storearg(p->n_right); + } else + p->n_rval = 0; + /* push return struct address */ + if (prev == NULL || prev->n_op == FUNARG) { + n = mklnode(REG, 0, STKREG, INT); + if (p->n_rval) + n = mkbinode(PLUS, n, + mklnode(ICON, p->n_rval, 0, INT), INT); + pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); + if (prev == NULL) + p->n_rval += p->n_stsize/4; + } else if (prev->n_op == FORCE) { + /* return value for this function */ + n = mklnode(OREG, 8, FPREG, INT); + pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); + p->n_rval++; + } else { + pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); + n = p; + *prev = *p; + nfree(n); + } +//printf("end stcall\n"); + break; + + default: + if (ty != UTYPE) + gencall(p->n_right, p); + gencall(p->n_left, p); + break; + } +} + +/* + * Create separate node trees for function arguments. + * This is partly ticky, the strange calling convention + * may cause a bunch of code reorganization here. + */ +static int +storearg(NODE *p) +{ + NODE *n, *q, **narry; + int nch, k, i, nn, rary[4]; + int r0l, r0h, r2, a0, stk, sz; + TWORD t; + int maxrargs = 0; + + if (p->n_op == CM) + maxrargs = p->n_stalign; + + /* count the arguments */ + for (i = 1, q = p; q->n_op == CM; q = q->n_left) + i++; + nn = i; + + /* allocate array to store arguments */ + narry = tmpalloc(sizeof(NODE *)*nn); + + /* enter nodes into array */ + for (q = p; q->n_op == CM; q = q->n_left) + narry[--i] = q->n_right; + narry[--i] = q; + + /* free CM nodes */ + for (q = p; q->n_op == CM; ) { + n = q->n_left; + nfree(q); + q = n; + } + + /* count char args */ + r0l = r0h = r2 = a0 = 0; + for (sz = nch = i = 0; i < nn && i < 6; i++) { + TWORD t = narry[i]->n_type; + if (sz >= 6) + break; + if (t == CHAR || t == UCHAR) { + nch++; + sz++; + } else if ((t >= SHORT && t <= UNSIGNED) || + t > BTMASK || t == FLOAT) { + sz += 2; + } else /* long, double */ + sz += 4; + + } + + /* + * Now the tricky part. The parameters that should be on stack + * must be found and pushed first, then the register parameters. + * For the latter, be sure that evaluating them do not use any + * registers where argument values already are inserted. + * XXX - function pointers? + * XXX foo(long a, char b) ??? + */ + for (stk = 0; stk < 4; stk++) { + TWORD t; + + if (stk == nn) + break; + t = narry[stk]->n_type; + if (ISFTN(DECREF(t))) + t = LONG; + switch (t) { + case CHAR: case UCHAR: + if (r0l) { + if (r0h) + break; + rary[stk] = R2; /* char talk for 'R0H' */ + r0h = 1; + } else { + rary[stk] = R0; + r0l = 1; + } + continue; + + case INT: case UNSIGNED: + if (r0l || nch) { + if (r2) { + if (a0) + break; + rary[stk] = A0; + a0 = 1; + } else { + rary[stk] = R2; + r2 = 1; + } + } else { + rary[stk] = R0; + r0l = r0h = 1; + } + continue; + + case LONG: case ULONG: + if (r0l || r2) + break; + rary[stk] = R0; + r0l = r0h = r2 = 1; + continue; + + default: + if (ISPTR(narry[stk]->n_type) && + !ISFTN(DECREF(narry[stk]->n_type))) { + if (a0) { + if (r0l || nch) { + if (r2) + break; + rary[stk] = R2; + r2 = 1; + } else { + rary[stk] = R0; + r0l = r0h = 1; + } + } else { + rary[stk] = A0; + a0 = 1; + } + continue; + } + break; + } + break; + } + + /* + * The arguments that must be on stack are stk->nn args. + * Argument 0->stk-1 should be put in the rary[] register. + */ + for (sz = 0, i = nn-1; i >= stk; i--) { /* first stack args */ + NODE nod; + pass2_compile(ipnode(mkunode(FUNARG, + narry[i], 0, narry[i]->n_type))); + nod.n_type = narry[i]->n_type; + sz += tlen(&nod); + } + /* if param cannot be addressed directly, evaluate and put on stack */ + for (i = 0; i < stk; i++) { + + if (canaddr(narry[i])) + continue; + t = narry[i]->n_type; + k = (freetemp(szty(t))); + n = mklnode(OREG, k, FB, t); + q = tcopy(n); + pass2_compile(ipnode(mkbinode(ASSIGN, n, narry[i], t))); + narry[i] = q; + } + /* move args to registers */ + for (i = 0; i < stk; i++) { + t = narry[i]->n_type; + pass2_compile(ipnode(mkbinode(ASSIGN, + mklnode(REG, 0, rary[i], t), narry[i], t))); + } + return sz; +} + +/* + * Tell if a register can hold a specific datatype. + */ +#if 0 +int +mayuse(int reg, TWORD type) +{ + return 1; /* Everything is OK */ +} +#endif + +#ifdef TAILCALL +void +mktailopt(struct interpass *ip1, struct interpass *ip2) +{ + extern int earlylab; + extern char *cftname; + char *fn; + NODE *p; + + p = ip1->ip_node->n_left->n_left; + if (p->n_op == ICON) { + fn = p->n_name; + /* calling ourselves */ + p = ip1->ip_node->n_left; + if (p->n_op == CALL) { + if (storearg(p->n_right)) + comperr("too many args: fix mktailopt"); + p->n_op = UCALL; + } + tfree(ip1->ip_node); + p = ip2->ip_node->n_left; + if (strcmp(fn, cftname)) { + /* Not us, must generate fake prologue */ + ip1->type = IP_ASM; + ip1->ip_asm = "\tmov.w FB,SP\n\tpop.w FB\n"; + pass2_compile(ip1); + p->n_lval = p->n_rval = 0; + p->n_name = fn; + } else + p->n_lval = earlylab; + } else { + pass2_compile(ip1); + } + pass2_compile(ip2); +} +#endif +/* + * Set registers "live" at function calls (like arguments in registers). + * This is for liveness analysis of registers. + */ +int * +livecall(NODE *p) +{ + static int r[1] = { -1 }; /* Terminate with -1 */ + + return &r[0]; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/m16c/table.c b/lang/pcc/pcc/arch/m16c/table.c new file mode 100644 index 000000000..e8f186e05 --- /dev/null +++ b/lang/pcc/pcc/arch/m16c/table.c @@ -0,0 +1,589 @@ +/* $Id: table.c,v 1.35 2011/06/05 08:54:42 plunky Exp $ */ + +#include "pass2.h" + +# define ANYSIGNED TINT|TLONG|TCHAR +# define ANYUSIGNED TUNSIGNED|TULONG|TUCHAR +# define ANYFIXED ANYSIGNED|ANYUSIGNED +# define TL TLONG|TULONG +# define TWORD TUNSIGNED|TINT +# define TCH TCHAR|TUCHAR + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* (signed) char -> int/pointer */ +{ SCONV, INAREG, + SCREG, TCHAR, + SANY, TINT|TPOINT, + NAREG, RESC1, + " mov.b AL, A1\n\texts.b A1\n", }, + +/* (unsigned) char -> int/pointer */ +{ SCONV, INAREG, + SCREG, TUCHAR, + SANY, TINT|TPOINT, + NAREG, RESC1, + " mov.b AL, A1\n", }, + +/* unsigned char -> long */ +{ SCONV, INAREG, + SCREG, TUCHAR, + SANY, TL, + NAREG|NASL, RESC1, + " mov.b AL, A1\n mov.w #0,U1\n", }, + +/* int or pointer -> (unsigned) long */ +{ SCONV, INAREG, + SAREG|SNAME, TWORD|TPOINT, + SANY, TL, + NAREG|NASL, RESC1, + " mov.w AL,A1\n mov.w #0,U1\n", }, + +/* char -> (signed) long */ +{ SCONV, INAREG, + SAREG|SNAME, TCHAR, + SANY, TLONG, + NAREG|NASL, RESC1, + " exts.b AL\n exts.w AL\n", }, + +/* long -> ulong */ +{ SCONV, INAREG, + SAREG, TL, + SANY, TL, + 0, RLEFT, + "", }, + +/* long -> int or pointer */ +{ SCONV, INAREG, + SAREG|SOREG|SNAME, TL, + SANY, TWORD|TPOINT, + NAREG|NASL, RESC1, + " mov.w AL,A1\n", }, + +/* int -> char */ +{ SCONV, INCREG, + SAREG, TWORD, + SANY, TCH, + NCREG, RESC1, + " mov.b AL, A1\n", }, + +/* int -> long */ +{ SCONV, INAREG, + SAREG, TWORD, + SANY, TLONG, + NAREG|NASL, RESC1, + " exts.w AL", }, + +/* long -> char */ +{ SCONV, INAREG, + SAREG, TL, + SANY, TCH, + NAREG|NASL, RESC1, + "", }, + +{ SCONV, INAREG, + SAREG, TPOINT, + SANY, TWORD, + 0, RLEFT, + "", }, + +{ PLUS, INAREG|FOREFF, + SAREG, TL, + SCON|SNAME|SOREG, TL, + 0, RLEFT, + " add.w AR,AL\n adc.w UR,UL\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG, TL, + SCON|SNAME|SOREG, TL, + 0, RLEFT, + " sub.w AR,AL\n sbb.w UR,UL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TL, + SAREG|SNAME|SOREG, TL, + 0, RLEFT, + " and.w AR,AL\n and.w UR,UL\n", }, + +{ ER, INAREG|FOREFF, + SAREG, TL, + SAREG|SNAME|SOREG, TL, + 0, RLEFT, + " xor.w AR,AL\n xor.w UR,UL\n", }, + +{ OR, INAREG|FOREFF, + SAREG, TL, + SAREG|SNAME|SOREG, TL, + 0, RLEFT, + " xor.w AR,AL\n xor.w UR,UL\n", }, + +{ COMPL, INAREG|FOREFF, + SAREG, TL, + SAREG|SNAME|SOREG, TL, + 0, RLEFT, + " not.w AR,AL\n not.w UR,UL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT, + " Ow AR,AL\n", }, + +/* XXX - Is this rule really correct? Having a SAREG shape seems kind of + strange. Doesn't work. Gives a areg as A1. */ +#if 0 +{ OPSIMP, INBREG, + SAREG, TWORD|TPOINT, + SAREG|SBREG|SNAME|SOREG|SCON, TWORD|TPOINT, + NBREG, RESC1, + " ++Ow AR,A1\n", }, +#endif + +{ OPSIMP, INBREG, + SBREG, TWORD|TPOINT, + SAREG|SBREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT, + " Ow AR,AL\n", }, + +{ OPSIMP, INCREG|FOREFF, + SCREG, TCH, + SCREG|SNAME|SOREG|SCON, TCH, + 0, RLEFT, + " Ob AR,AL\n", }, + +/* XXX - Do these work? check nspecial in order.c */ +/* signed integer division */ +{ DIV, INAREG, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + /*2*NAREG|NASL|*/NSPECIAL, RLEFT, + " div.w AR\n mov.w r0,AL\n", }, + // " xor.w r2\n div.w AR\n", }, + + +/* signed integer/char division - separate entry for FOREFF */ +{ DIV, FOREFF, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + 0, 0, + "", }, + +#if 0 +/* signed char division */ +{ DIV, INCREG, + SCREG, TCHAR, + SCREG|SNAME|SOREG, TCH, + 2*NCREG|NCSL|NSPECIAL, RLEFT, + " div.b AR\n\tmov.b r0l,AL\n", }, + // " xor.w r2\n div.w AR\n", }, +#endif + +/* signed integer modulus, equal to above */ +{ MOD, INAREG, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + /*2*NAREG|NASL|*/NSPECIAL, RLEFT, + " div.w AR\n\tmov r2,AL\n", }, + +/* signed integer modulus - separate entry for FOREFF */ +{ MOD, FOREFF, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + 0, 0, + "", }, + +/* signed integer multiplication */ +{ MUL, INAREG, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + 2*NAREG|NASL|NSPECIAL, RESC1, + " mul.w AL,AR\n", }, + +{ MUL, FOREFF, + SAREG, TINT, + SAREG|SNAME|SOREG, TWORD, + 0, 0, + "", }, + +#if 0 +{ LS, INAREG, + SAREG, TWORD, + SCON, TANY, + 0, RLEFT, + " shl.w AR,AL\n", }, +#endif + +{ LS, INAREG, + SAREG, TWORD, + SAREG, TWORD, + 0, RLEFT, + " push.b r1h\n" + " mov.b AR,r1h\n" + " shl.w r1h,AL\n" + " pop.b r1h\n", }, + +{ LS, INAREG, + SAREG, TL, + SAREG, TWORD, + 0, RLEFT, + " push.b r1h\n" + " mov.b AR,r1h\n" + " shl.l r1h,ZG\n" + " pop.b r1h\n", }, + +{ RS, INAREG, + SAREG, TWORD, + SAREG, TWORD, + 0, RLEFT, + " push.b r1h\n" + " mov.b AR,r1h\n" + " neg.b r1h\n" + " shl.w r1h,AL\n" + " pop.b r1h\n", }, + +{ RS, INAREG, + SAREG, TL, + SAREG, TWORD, + 0, RLEFT, + " push.b r1h\n" + " mov.b AR,r1h\n" + " neg.b r1h\n" + " shl.l r1h,ZG\n" + " pop.b r1h\n", }, + +#if 0 +{ RS, INAREG, + SAREG, TUNSIGNED, + SCON, TANY, + 0, RLEFT, + " shl ZA,AL\n", }, + +{ RS, INAREG, + SAREG, TINT, + SCON, TANY, + 0, RLEFT, + " sha ZA,AL\n", }, +#endif + +{ OPLOG, FORCC, + SAREG|SBREG|SOREG|SNAME, TL, + SAREG|SBREG|SOREG|SNAME, TL, + 0, 0, + "ZF", }, + +{ OPLOG, FORCC, + SBREG|SOREG, TWORD|TPOINT, + SCON, TWORD|TPOINT, + 0, RESCC, + " cmp.w AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG|SBREG|SOREG|SNAME, TWORD|TPOINT, + SAREG|SBREG|SOREG|SNAME, TWORD|TPOINT, + 0, RESCC, + " cmp.w AR,AL\n", }, + +{ OPLOG, FORCC, + SCREG|SOREG|SNAME, TCH, + SCREG|SOREG|SNAME, TCH, + 0, RESCC, + " cmp.b AR,AL\n", }, + +{ OPLOG, FORCC, + SCREG|SOREG|SNAME, TCH, + SCREG|SOREG|SNAME, TCH, + 0, RESCC, + " cmp.b AR,AL\n", }, + +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jmp.w ZC\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON|SNAME|SOREG|SAREG, TL|TFTN, + NAREG, RESC1, + " mov.w AR,A1\n mov.w UR,U1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON|SNAME|SOREG|SAREG|SBREG, TWORD|TPOINT, + NAREG, RESC1, + " mov.w AR,A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG|SCON|SNAME|SOREG|SAREG, TWORD|TPOINT, + NBREG, RESC1, + " mov.w AR,A1\n", }, + /* +{ OPLTYPE, INAREG, + SANY, TANY, + SCON|SNAME|SOREG, TCH, + NAREG, RESC1, + " mov.b AR, A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SCON|SNAME|SOREG, TCHAR|TUCHAR, + NBREG, RESC1, + " mov.b AR,A1\n", }, + */ + +{ OPLTYPE, INCREG, + SANY, TANY, + SCON|SNAME|SOREG, TCHAR|TUCHAR, + NCREG, RESC1, + " mov.b AR,A1\n", }, + +{ COMPL, INAREG, + SAREG, TWORD, + SANY, TANY, + 0, RLEFT, + " not.w AL\n", }, + +{ COMPL, INCREG, + SCREG, TCH, + SANY, TANY, + 0, RLEFT, + " not.b AL\n", }, + +/* Push function address */ +{ FUNARG, FOREFF, + SCON, TFTN, + SANY, TANY, + 0, RNULL, + "ZH", }, + +{ FUNARG, FOREFF, + SOREG, TFTN, + SANY, TANY, + 0, RNULL, + "ZI", }, + +{ FUNARG, FOREFF, + SNAME|SAREG, TL|TFTN, + SANY, TANY, + 0, RNULL, + " push.w UL\n push.w AL\n", }, + +{ FUNARG, FOREFF, + SCON|SAREG|SNAME|SOREG, TWORD|TPOINT, + SANY, TANY, + 0, RNULL, + " push.w AL\n", }, + +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SANY, TANY, + 0, RNULL, + " push.b AL\n", }, + +/* Match function pointers first */ +#if 0 +{ ASSIGN, FOREFF, + SFTN, TWORD|TPOINT, + SFTN, TWORD|TPOINT, + NAREG, 0, + "ZD", }, +#endif + +{ ASSIGN, INAREG, + SAREG, TFTN, + SCON, TFTN, + 0, RLEFT, + "ZD", }, + +{ ASSIGN, INBREG, + SBREG, TFTN, + SCON, TFTN, + 0, RLEFT, + "ZD", }, + +{ ASSIGN, INAREG, + SAREG, TFTN, + SBREG|SAREG|SOREG|SNAME, TFTN, + 0, RLEFT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, INBREG, + SBREG, TFTN, + SBREG|SAREG|SOREG|SNAME, TFTN, + 0, RLEFT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, INAREG, + SBREG|SAREG|SOREG|SNAME, TFTN, + SAREG, TFTN, + 0, RRIGHT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, INBREG, + SBREG|SAREG|SOREG|SNAME, TFTN, + SBREG, TFTN, + 0, RRIGHT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +/* a reg -> a reg */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + " mov.w AR,AL\n", }, + +{ ASSIGN, INAREG, + SBREG|SAREG|SOREG|SNAME, TL, + SAREG, TL, + 0, RRIGHT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, INBREG, + SBREG|SAREG|SOREG|SNAME, TL, + SBREG, TL, + 0, RRIGHT, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, FOREFF, + SBREG|SAREG|SOREG|SNAME, TL, + SCON|SBREG|SAREG|SOREG|SNAME, TL, + 0, 0, + " mov.w AR,AL\n mov.w UR,UL\n", }, + +{ ASSIGN, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SCON, TANY, + 0, RLEFT, + " mov.w AR,AL\n", }, + +{ ASSIGN, INBREG|FOREFF, + SBREG, TWORD|TPOINT, + SCON, TANY, + 0, RLEFT, + " mov.w AR,AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TWORD|TPOINT, + SCON, TANY, + 0, 0, + " mov.w AR,AL\n", }, + +/* char, oreg/name -> c reg */ +{ ASSIGN, FOREFF|INCREG, + SCREG, TCHAR|TUCHAR, + SOREG|SNAME|SCON, TCHAR|TUCHAR, + 0, RLEFT, + " mov.b AR,AL\n", }, + +/* int, oreg/name -> a reg */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SOREG|SNAME, TWORD|TPOINT, + 0, RLEFT, + " mov.w AR,AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TWORD|TPOINT, + SOREG|SNAME, TWORD|TPOINT, + 0, RLEFT, + " mov.w AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RRIGHT, + " mov.w AR,AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG|SNAME, TWORD|TPOINT, + SBREG, TWORD|TPOINT, + 0, RRIGHT, + " mov.w AR,AL\n", }, + +{ ASSIGN, FOREFF|INCREG, + SOREG|SNAME, TCHAR|TUCHAR, + SCREG, TCHAR|TUCHAR, + 0, RRIGHT, + " mov.b AR,AL\n", }, + +{ ASSIGN, FOREFF|INCREG, + SCREG, TCHAR|TUCHAR, + SCREG, TCHAR|TUCHAR, + 0, RRIGHT, + " mov.b AR,AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TWORD|TPOINT, + SBREG, TWORD|TPOINT, + 0, RRIGHT, + " mov.w AR,AL\n", }, + +{ UMUL, INAREG, + SBREG, TPOINT|TWORD, + SANY, TFTN, + NAREG, RESC1, + " mov.w [AL],A1\n mov.w 2[AL],U1\n", }, + +{ UMUL, INAREG, + SBREG, TPOINT|TWORD, + SANY, TPOINT|TWORD, + NAREG, RESC1, + " mov.w [AL],A1\n", }, + +{ UMUL, INBREG, + SBREG, TPOINT|TWORD, + SANY, TPOINT|TWORD, + NBREG|NBSL, RESC1, + " mov.w [AL],A1\n", }, + +{ UMUL, INAREG, + SBREG, TCHAR|TUCHAR|TPTRTO, + SANY, TCHAR|TUCHAR, + NAREG, RESC1, + " mov.b [AL], A1\n", }, + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " jsr.w CL\nZB", }, + +{ UCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG, RESC1, + " jsr.w CL\nZB", }, + +{ UCALL, INAREG, + SNAME|SOREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " jsri.a AL\nZB", }, + +{ UCALL, FOREFF, + SNAME|SOREG, TANY, + SANY, TANY, + 0, 0, + " jsri.a AL\nZB", }, + +{ UCALL, INAREG, + SBREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " jsri.a [AL]\nZB", }, + +{ UCALL, FOREFF, + SBREG, TANY, + SANY, TANY, + 0, 0, + " jsri.a [AL]\nZB", }, + + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); + diff --git a/lang/pcc/pcc/arch/m68k/code.c b/lang/pcc/pcc/arch/m68k/code.c new file mode 100644 index 000000000..bb1f8f13f --- /dev/null +++ b/lang/pcc/pcc/arch/m68k/code.c @@ -0,0 +1,296 @@ +/* $Id: code.c,v 1.8 2016/01/30 17:26:19 ragge Exp $ */ +/* + * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#ifdef LANG_CXX +#define p1listf listf +#define p1tfree tfree +#else +#define NODE P1ND +#define talloc p1alloc +#define tfree p1tfree +#endif + +extern int gotnr; + +/* + * Print out assembler segment name. + */ +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + case DATA: + case LDATA: name = ".data"; break; + case STRNG: + case RDATA: name = ".section .rodata"; break; + case UDATA: break; + case PICLDATA: + case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; + case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; + case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; + case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; + case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; + case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; + case NMSEG: + printf("\t.section %s,\"a%c\",@progbits\n", name, + cftnsp ? 'x' : 'w'); + return; + } + printf("\t%s\n", name); +} + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + char *name; + + name = getexname(sp); + if (sp->sclass == EXTDEF) { + printf("\t.globl %s\n", name); + if (ISFTN(sp->stype)) { + printf("\t.type %s,@function\n", name); + } else { + printf("\t.type %s,@object\n", name); + printf("\t.size %s,%d\n", name, + (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR); + } + } + if (sp->slevel == 0) + printf("%s:\n", name); + else + printf(LABFMT ":\n", sp->soffset); +} + +/* + * code for the end of a function + * deals with struct return here + * The return value is in (or pointed to by) RETREG. + */ +int sttemp; + +void +efcode(void) +{ + NODE *p, *q; + + gotnr = 0; + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + /* use stasg to get call to memcpy() */ + p = buildtree(UMUL, tempnode(sttemp, INCREF(STRTY), + cftnsp->sdf, cftnsp->sap), NIL); + q = block(REG, 0, 0, INCREF(STRTY), cftnsp->sdf, cftnsp->sap); + regno(q) = A0; + q = buildtree(UMUL, q, NIL); + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + +/* + * code for the beginning of a function; a is an array of + * indices in symtab for the arguments; n is the number + */ +void +bfcode(struct symtab **s, int cnt) +{ + struct symtab *sp2; + NODE *n, *p; + int i; + + if (kflag) { /* PIC code */ + /* Generate extended assembler for PIC prolog */ + p = tempnode(0, CHAR|PTR, 0, 0); + gotnr = regno(p); + p = block(XARG, p, NIL, INT, 0, 0); + p->n_name = "=r"; + p = block(XASM, p, bcon(0), INT, 0, 0); + + p->n_name = "lea (%%pc,_GLOBAL_OFFSET_TABLE_@GOTPC),%0\n"; + p->n_right->n_type = STRTY; + ecomp(p); + } + + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + n = tempnode(0, INCREF(CHAR), 0, 0); + p = block(REG, 0, 0, INCREF(CHAR), 0, 0); + regno(p) = A0; + sttemp = regno(n); + ecomp(buildtree(ASSIGN, n, p)); + } + + if (xtemps == 0) + return; + + /* put arguments in temporaries */ + for (i = 0; i < cnt; i++) { + if (s[i]->stype == STRTY || s[i]->stype == UNIONTY || + cisreg(s[i]->stype) == 0) + continue; + if (cqual(s[i]->stype, s[i]->squal) & VOL) + continue; + sp2 = s[i]; + n = tempnode(0, s[i]->stype, s[i]->sdf, s[i]->sap); + n = buildtree(ASSIGN, n, nametree(sp2)); + s[i]->soffset = regno(n->n_left); + s[i]->sflags |= STNODE; + ecomp(n); + } +} + + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ + if (flag) + return; + + printf("\t.ident \"PCC: %s\"\n", VERSSTR); +} + +void +bjobcode(void) +{ + /* Set correct names for our types */ + astypnames[SHORT] = astypnames[USHORT] = "\t.word"; + astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + * Returns p. + */ +NODE * +funcode(NODE *p) +{ + NODE *r, *l; + + /* Fix function call arguments. On m68k, just add funarg */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + if (r->n_right->n_op != STARG) { + r->n_right = intprom(r->n_right); + r->n_right = block(FUNARG, r->n_right, NIL, + r->n_right->n_type, r->n_right->n_df, + r->n_right->n_ap); + } + } + if (r->n_op != STARG) { + l = talloc(); + *l = *r; + r->n_op = FUNARG; + r->n_left = l; + r->n_left = intprom(r->n_left); + r->n_type = r->n_left->n_type; + } + return p; + +} + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + +/* + * Return return as given by a. + */ +NODE * +builtin_return_address(const struct bitable *bt, NODE *a) +{ + int nframes; + NODE *f; + +cerror((char *)__func__); + nframes = glval(a); + tfree(a); + + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + + while (nframes--) + f = block(UMUL, f, NIL, PTR+VOID, 0, 0); + + f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0); + f = buildtree(UMUL, f, NIL); + + return f; +} + +/* + * Return frame as given by a. + */ +NODE * +builtin_frame_address(const struct bitable *bt, NODE *a) +{ + int nframes; + NODE *f; + +cerror((char *)__func__); + nframes = glval(a); + tfree(a); + + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + + while (nframes--) + f = block(UMUL, f, NIL, PTR+VOID, 0, 0); + + return f; +} + +/* + * Return "canonical frame address". + */ +NODE * +builtin_cfa(const struct bitable *bt, NODE *a) +{ + NODE *f; + +cerror((char *)__func__); + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + return block(PLUS, f, bcon(16), INCREF(PTR+VOID), 0, 0); +} diff --git a/lang/pcc/pcc/arch/m68k/local.c b/lang/pcc/pcc/arch/m68k/local.c new file mode 100644 index 000000000..8a93c5846 --- /dev/null +++ b/lang/pcc/pcc/arch/m68k/local.c @@ -0,0 +1,562 @@ +/* $Id: local.c,v 1.16 2016/01/30 17:26:19 ragge Exp $ */ +/* + * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#undef NIL +#define NIL NULL + +#ifdef LANG_CXX +#define P1ND NODE +#define p1nfree nfree +#define p1fwalk fwalk +#define p1tcopy tcopy +#define p1alloc talloc +#else +#define NODE P1ND +#define nfree p1nfree +#define fwalk p1fwalk +#endif + + +/* this file contains code which is dependent on the target machine */ + +int gotnr; + +/* + * Make a symtab entry for PIC use. + */ +static struct symtab * +picsymtab(char *p, char *s, char *s2) +{ + struct symtab *sp = permalloc(sizeof(struct symtab)); + size_t len = strlen(p) + strlen(s) + strlen(s2) + 1; + + sp->sname = permalloc(len); + strlcpy(sp->sname, p, len); + strlcat(sp->sname, s, len); + strlcat(sp->sname, s2, len); + sp->sap = attr_new(ATTR_SONAME, 1); + sp->sap->sarg(0) = sp->sname; + sp->sclass = EXTERN; + sp->sflags = sp->slevel = 0; + sp->stype = 0xdeadbeef; + return sp; +} + +/* + * Create a reference for an extern variable. + */ +static NODE * +picext(NODE *p) +{ + NODE *q, *r; + struct symtab *sp; + char *name; + + q = tempnode(gotnr, PTR|VOID, 0, 0); + name = getexname(p->n_sp); + +#ifdef notdef + struct attr *ga; + if ((ga = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) && + strcmp(ga->sarg(0), "hidden") == 0) { + /* For hidden vars use GOTOFF */ + sp = picsymtab("", name, "@GOTOFF"); + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + nfree(p); + return q; + } +#endif + + sp = picsymtab("", name, "@GOT"); + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + q = block(UMUL, q, 0, PTR|VOID, 0, 0); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + nfree(p); + return q; +} + +static char * +getsoname(struct symtab *sp) +{ + struct attr *ap; + return (ap = attr_find(sp->sap, ATTR_SONAME)) ? + ap->sarg(0) : sp->sname; + +} + + +static NODE * +picstatic(NODE *p) +{ + NODE *q, *r; + struct symtab *sp; + + q = tempnode(gotnr, PTR|VOID, 0, 0); + if (p->n_sp->slevel > 0) { + char buf[32]; + if ((p->n_sp->sflags & SMASK) == SSTRING) + p->n_sp->sflags |= SASG; + snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset); + sp = picsymtab("", buf, "@GOT"); + } else { + sp = picsymtab("", getsoname(p->n_sp), "@GOT"); + } + + sp->sclass = STATIC; + sp->stype = p->n_sp->stype; + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + q = block(UMUL, q, 0, PTR|VOID, 0, 0); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + nfree(p); + return q; +} + +/* clocal() is called to do local transformations on + * an expression tree preparitory to its being + * written out in intermediate code. + * + * the major essential job is rewriting the + * automatic variables and arguments in terms of + * REG and OREG nodes + * conversion ops which are not necessary are also clobbered here + * in addition, any special features (such as rewriting + * exclusive or) are easily handled here as well + */ +NODE * +clocal(NODE *p) +{ + + register struct symtab *q; + register NODE *r, *l; + register int o; + TWORD t; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + switch( o = p->n_op ){ + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + slval(r, 0); + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case REGISTER: + p->n_op = REG; + slval(p, 0); + p->n_rval = q->soffset; + break; + + case USTATIC: + case STATIC: + if (kflag == 0) + break; + if (blevel > 0 && !statinit) + p = picstatic(p); + break; + + case EXTERN: + case EXTDEF: + if (kflag == 0) + break; + if (blevel > 0 && !statinit) + p = picext(p); + break; + } + break; + + case ADDROF: + if (kflag == 0 || blevel == 0 || statinit) + break; + /* char arrays may end up here */ + l = p->n_left; + if (l->n_op != NAME || + (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE)) + break; + l = p; + p = picstatic(p->n_left); + nfree(l); + if (p->n_op != UMUL) + cerror("ADDROF error"); + l = p; + p = p->n_left; + nfree(l); + break; + + case STASG: /* convert struct assignment to call memcpy */ + l = p->n_left; + if (l->n_op == NAME && ISFTN(l->n_sp->stype)) + break; /* struct return, do nothing */ + /* first construct arg list */ + p->n_left = buildtree(ADDROF, p->n_left, 0); + r = bcon(tsize(STRTY, p->n_df, p->n_ap)/SZCHAR); + p->n_left = buildtree(CM, p->n_left, p->n_right); + p->n_right = r; + p->n_op = CM; + p->n_type = INT; + + r = block(NAME, NIL, NIL, INT, 0, 0); + r->n_sp = lookup(addname("memcpy"), SNORMAL); + if (r->n_sp->sclass == SNULL) { + r->n_sp->sclass = EXTERN; + r->n_sp->stype = INCREF(VOID+PTR)+(FTN-PTR); + } + r->n_type = r->n_sp->stype; + p = buildtree(CALL, r, p); + break; + + case SCONV: + l = p->n_left; + if (l->n_op == ICON && ISPTR(l->n_type)) { + /* Do immediate cast here */ + /* Should be common code */ + q = l->n_sp; + l->n_sp = NULL; + l->n_type = UNSIGNED; + if (concast(l, p->n_type) == 0) + cerror("clocal"); + p = nfree(p); + p->n_sp = q; + } + break; + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + t = p->n_type; + if (ISITY(t)) + t = t - (FIMAG-FLOAT); + p->n_left->n_rval = RETREG(t); + break; + } +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal end: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + return(p); +} + +#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) + +void +myp2tree(NODE *p) +{ + struct symtab *sp; + NODE *l; + + if (cdope(p->n_op) & CALLFLG) { + if (p->n_left->n_op == ADDROF && + p->n_left->n_left->n_op == NAME) { + p->n_left = nfree(p->n_left); + l = p->n_left; + l->n_op = ICON; + if (l->n_sp->sclass != STATIC && + l->n_sp->sclass != USTATIC) + l->n_sp = + picsymtab(l->n_sp->sname, "@PLTPC", ""); + } + } + + if (p->n_op != FCON) + return; + + sp = IALLOC(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->sap = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + sp->sname = NULL; + + locctr(DATA, sp); + defloc(sp); + ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + + p->n_op = NAME; + slval(p, 0); + p->n_sp = sp; + +} + +/* + * Convert ADDROF NAME to ICON? + */ +int +andable(NODE *p) +{ +#ifdef notdef + /* shared libraries cannot have direct referenced static syms */ + if (p->n_sp->sclass == STATIC || p->n_sp->sclass == USTATIC) + return 1; +#endif + return 1; +} + +/* + * Return 1 if a variable of type type is OK to put in register. + */ +int +cisreg(TWORD t) +{ + return 1; +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a storeable node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + p = buildtree(MUL, p, bcon(off/SZCHAR)); + p = buildtree(PLUS, p, bcon(30)); + p = buildtree(AND, p, xbcon(-16, NULL, UNSIGNED)); + p = cast(p, UNSIGNED, 0); + + /* sub the size from sp */ + sp = block(REG, NIL, NIL, UNSIGNED+PTR, 0, 0); + slval(sp, 0); + sp->n_rval = STKREG; + p = (buildtree(MINUSEQ, sp, p)); + ecomp(p); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+UNSIGNED, t->n_df, t->n_ap); + slval(sp, 0); + sp->n_rval = STKREG; + t->n_type = sp->n_type; + p = (buildtree(ASSIGN, t, sp)); /* Emit! */ + ecomp(p); + +} + +/* + * print out a constant node, may be associated with a label. + * Do not free the node after use. + * off is bit offset from the beginning of the aggregate + * fsz is the number of bits this is referring to + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; long double l; int i[3]; } u; + + switch (p->n_type) { + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)((union flt *)p->n_dcon)->fp; +#if defined(HOST_LITTLE_ENDIAN) + /* XXX probably broken on most hosts */ + printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]); +#else + printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]); +#endif + break; + case DOUBLE: + u.d = (double)((union flt *)p->n_dcon)->fp; +#if defined(HOST_LITTLE_ENDIAN) + printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]); +#else + printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]); +#endif + break; + case FLOAT: + u.f = (float)((union flt *)p->n_dcon)->fp; + printf("\t.long\t0x%x\n", u.i[0]); + break; + + case LONGLONG: + case ULONGLONG: + printf("\t.long\t0x%x\n", (int)(off >> 32) & 0xffffffff); + printf("\t.long\t0x%x\n", (int)(off) & 0xffffffff); + break; + default: + return 0; + } + return 1; +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ + return (p == NULL ? "" : p); +} + +/* + * map types which are not defined on the local machine + */ +TWORD +ctype(TWORD type) +{ + switch (BTYPE(type)) { + case LONG: + MODTYPE(type,INT); + break; + + case ULONG: + MODTYPE(type,UNSIGNED); + + } + return (type); +} + +void +calldec(NODE *p, NODE *q) +{ +} + +void +extdec(struct symtab *q) +{ +} + +/* make a common declaration for id, if reasonable */ +void +defzero(struct symtab *sp) +{ + int off, al; + char *name; + + name = getexname(sp); + off = tsize(sp->stype, sp->sdf, sp->sap); + SETOFF(off,SZCHAR); + off /= SZCHAR; + al = talign(sp->stype, sp->sap)/SZCHAR; + + if (sp->sclass == STATIC) { + if (sp->slevel == 0) { + printf("\t.local %s\n", name); + } else + printf("\t.local " LABFMT "\n", sp->soffset); + } + if (sp->slevel == 0) { + printf("\t.comm %s,0%o,%d\n", name, off, al); + } else + printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); +} + +char *nextsect; +static char *alias; +static int constructor; +static int destructor; + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + return 0; +} + +/* + * Called when a identifier has been declared. + */ +void +fixdef(struct symtab *sp) +{ + struct attr *ga; + +#ifdef HAVE_WEAKREF + /* not many as'es have this directive */ + if ((ga = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) { + char *wr = ga->sarg(0); + char *sn = getsoname(sp); + if (wr == NULL) { + if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS))) { + wr = ga->sarg(0); + } + } + if (wr == NULL) + printf("\t.weak %s\n", sn); + else + printf("\t.weakref %s,%s\n", sn, wr); + } else + if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) { + char *an = ga->sarg(0); + char *sn = getsoname(sp); + char *v; + + v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl"; + printf("\t.%s %s\n", v, sn); + printf("\t.set %s,%s\n", sn, an); + } + if (alias != NULL && (sp->sclass != PARAM)) { + char *name = getexname(sp); + printf("\t.globl %s\n", name); + printf("%s = ", name); + printf("%s\n", exname(alias)); + alias = NULL; + } + if ((constructor || destructor) && (sp->sclass != PARAM)) { + NODE *p = p1alloc(); + + p->n_op = NAME; + p->n_sp = + (struct symtab *)(constructor ? "constructor" : "destructor"); + sp->sap = attr_add(sp->sap, gcc_attr_parse(p)); + constructor = destructor = 0; + } +#endif +} + +void +pass1_lastchance(struct interpass *ip) +{ +} diff --git a/lang/pcc/pcc/arch/m68k/local2.c b/lang/pcc/pcc/arch/m68k/local2.c new file mode 100644 index 000000000..813b3f245 --- /dev/null +++ b/lang/pcc/pcc/arch/m68k/local2.c @@ -0,0 +1,815 @@ +/* $Id: local2.c,v 1.17 2016/01/30 17:26:19 ragge Exp $ */ +/* + * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" +# include +# include + +static int stkpos; + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static int regm, regf, fpsub, nfp; + +void +prologue(struct interpass_prolog *ipp) +{ + int i; + + /* + * Subtract both space for automatics and permanent regs. + * XXX - no struct return yet. + */ + + fpsub = p2maxautooff; + if (fpsub >= AUTOINIT/SZCHAR) + fpsub -= AUTOINIT/SZCHAR; + regm = regf = nfp = 0; + for (i = 0; i < MAXREGS; i++) + if (TESTBIT(ipp->ipp_regs, i)) { + if (i <= A7) { + regm |= (1 << i); + fpsub += 4; + } else if (i >= FP0) { + regf |= (1 << (i - FP0)); + fpsub += 12; + nfp += 12; + } else + comperr("bad reg range"); + } + printf(" link.%c %%fp,#%d\n", fpsub > 32768 ? 'l' : 'w', -fpsub); + if (regm) + printf(" movem.l #%d,%d(%%fp)\n", regm, -fpsub + nfp); + if (regf) + printf(" fmovem #%d,%d(%%fp)\n", regf, -fpsub); +} + +void +eoftn(struct interpass_prolog *ipp) +{ + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + if (regm) + printf(" movem.l %d(%%fp),#%d\n", -fpsub + nfp, regm); + if (regf) + printf(" fmovem %d(%%fp),#%d\n", -fpsub, regf); + printf(" unlk %%fp\n rts\n"); +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "eor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s", str); +} + +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(NODE *p) +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + return(SZINT/SZCHAR); + + case LONG: + case ULONG: + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + comperr("fldexpand"); + return 0; +} + +static void +starg(NODE *p) +{ + int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + int subsz = (sz + 3) & ~3; + int fr, tr, cr; + + fr = regno(getlr(p, 'L')); /* from reg (struct pointer) */ + cr = regno(getlr(p, '1')); /* count reg (number of words) */ + tr = regno(getlr(p, '2')); /* to reg (stack) */ + + /* Sub from stack and put in toreg */ + printf(" sub.l #%d,%%sp\n", subsz); + printf(" move.l %%sp,%s\n", rnames[tr]); + + /* Gen an even copy start */ + if (sz & 1) + expand(p, INBREG, " move.b (AL)+,(A2)+\n"); + if (sz & 2) + expand(p, INBREG, " move.w (AL)+,(A2)+\n"); + sz -= (sz & 3); + + /* if more than 4 words, use loop, otherwise output instructions */ + if (sz > 16) { + printf(" move.l #%d,%s\n", (sz/4)-1, rnames[cr]); + expand(p, INBREG, "1: move.l (AL)+,(A2)+\n"); + expand(p, INBREG, " dbra A1,1b\n"); + } else { + if (sz > 12) + expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4; + if (sz > 8) + expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4; + if (sz > 4) + expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4; + if (sz == 4) + expand(p, INBREG, " move.l (AL)+,(A2)+\n"); + } +} + +void +zzzcode(NODE *p, int c) +{ + TWORD t = p->n_type; + char *s; + + switch (c) { + case 'L': + t = p->n_left->n_type; + /* FALLTHROUGH */ + case 'A': + s = (t == CHAR || t == UCHAR ? "b" : + t == SHORT || t == USHORT ? "w" : + t == FLOAT ? "s" : + t == DOUBLE ? "d" : + t == LDOUBLE ? "x" : "l"); + printf("%s", s); + break; + + case 'B': + if (p->n_qual) + printf(" add.l #%d,%%sp\n", (int)p->n_qual); + break; + + case 'C': /* jsr or bsr.l XXX - type of CPU? */ + printf("%s", kflag ? "bsr.l" : "jsr"); + break; + + case 'F': /* Emit float branches */ + switch (p->n_op) { + case GT: s = "fjnle"; break; + case GE: s = "fjnlt"; break; + case LE: s = "fjngt"; break; + case LT: s = "fjnge"; break; + case NE: s = "fjne"; break; + case EQ: s = "fjeq"; break; + default: comperr("ZF"); s = 0; + } + printf("%s " LABFMT "\n", s, p->n_label); + break; + + case 'P': + printf(" lea -%d(%%fp),%%a0\n", stkpos); + break; + + case 'Q': /* struct assign */ + printf(" move.l %d,-(%%sp)\n", + attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); + expand(p, INAREG, " move.l AR,-(%sp)\n"); + expand(p, INAREG, " move.l AL,-(%sp)\n"); + printf(" jsr memcpy\n"); + printf(" add.l #12,%%sp\n"); + break; + + case 'S': /* struct arg */ + starg(p); + break; + + case '2': + if (regno(getlr(p, '2')) != regno(getlr(p, 'L'))) + expand(p, INAREG, " fmove.x AL,A2\n"); + break; + + default: + comperr("zzzcode %c", c); + } +} + +#if 0 +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left, SOREG))) + return(1); + return(0); +} +#endif + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + comperr("flshape"); + return(0); +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + return 0; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +void +adrcon(CONSZ val) +{ + printf("#" CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + long val = getlval(p); + + if (p->n_type <= UCHAR) + val &= 255; + else if (p->n_type <= USHORT) + val &= 65535; + + switch (p->n_op) { + case ICON: + fprintf(fp, "%ld", val); + if (p->n_name[0]) + printf("+%s", p->n_name); + break; + + default: + comperr("illegal conput, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + switch (p->n_op) { + case REG: + printf("%%%s", &rnames[p->n_rval][2]); + break; + case NAME: + case OREG: + setlval(p, getlval(p) + 4); + adrput(stdout, p); + setlval(p, getlval(p) - 4); + break; + + case ICON: + printf("#%d", (int)getlval(p)); + break; + + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *io, NODE *p) +{ + int r; + + /* output an address, with offsets, from p */ + switch (p->n_op) { + case NAME: + if (getlval(p)) + fprintf(io, CONFMT "%s", getlval(p), + *p->n_name ? "+" : ""); + if (p->n_name[0]) + printf("%s", p->n_name); + else + comperr("adrput"); + return; + + case OREG: + r = p->n_rval; + + if (getlval(p)) + fprintf(io, CONFMT "%s", getlval(p), + *p->n_name ? "+" : ""); + if (p->n_name[0]) + printf("%s", p->n_name); + if (R2TEST(r)) { + int r1 = R2UPK1(r); + int r2 = R2UPK2(r); + int sh = R2UPK3(r); + + fprintf(io, "(%s,%s,%d)", + r1 == MAXREGS ? "" : rnames[r1], + r2 == MAXREGS ? "" : rnames[r2], sh); + } else + fprintf(io, "(%s)", rnames[p->n_rval]); + return; + case ICON: + /* addressable value of the constant */ + if (p->n_type == LONGLONG || p->n_type == ULONGLONG) { + fprintf(io, "#" CONFMT, getlval(p) >> 32); + } else { + fputc('#', io); + conput(io, p); + } + return; + + case REG: + if ((p->n_type == LONGLONG || p->n_type == ULONGLONG) && + /* XXX allocated reg may get wrong type here */ + (p->n_rval > A7 && p->n_rval < FP0)) { + fprintf(io, "%%%c%c", rnames[p->n_rval][0], + rnames[p->n_rval][1]); + } else + fprintf(io, "%s", rnames[p->n_rval]); + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +static char * +ccbranches[] = { + "jeq", /* jumpe */ + "jne", /* jumpn */ + "jle", /* jumple */ + "jlt", /* jumpl */ + "jge", /* jumpge */ + "jgt", /* jumpg */ + "jls", /* jumple (jlequ) */ + "jcs", /* jumpl (jlssu) */ + "jcc", /* jumpge (jgequ) */ + "jhi", /* jumpg (jgtru) */ +}; + + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + if (o < EQ || o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); +} + +static void +mkcall(NODE *p, char *name) +{ + p->n_op = CALL; + p->n_right = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type); + p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type); + p->n_left->n_name = name; +} + +static void +mkcall2(NODE *p, char *name) +{ + p->n_op = CALL; + p->n_right = mkunode(FUNARG, p->n_right, 0, p->n_right->n_type); + p->n_left = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type); + p->n_right = mkbinode(CM, p->n_left, p->n_right, INT); + p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type); + p->n_left->n_name = name; +} + + +static void +fixcalls(NODE *p, void *arg) +{ + struct attr *ap; + TWORD lt; + + switch (p->n_op) { + case STCALL: + case USTCALL: + ap = attr_find(p->n_ap, ATTR_P2STRUCT); + if (ap->iarg(0)+p2autooff > stkpos) + stkpos = ap->iarg(0)+p2autooff; + break; + + case DIV: + if (p->n_type == LONGLONG) + mkcall2(p, "__divdi3"); + else if (p->n_type == ULONGLONG) + mkcall2(p, "__udivdi3"); + break; + + case MOD: + if (p->n_type == LONGLONG) + mkcall2(p, "__moddi3"); + else if (p->n_type == ULONGLONG) + mkcall2(p, "__umoddi3"); + break; + + case MUL: + if (p->n_type == LONGLONG || p->n_type == ULONGLONG) + mkcall2(p, "__muldi3"); + break; + + case LS: + if (p->n_type == LONGLONG || p->n_type == ULONGLONG) + mkcall2(p, "__ashldi3"); + break; + + case RS: + if (p->n_type == LONGLONG) + mkcall2(p, "__ashrdi3"); + else if (p->n_type == ULONGLONG) + mkcall2(p, "__lshrdi3"); + break; + + case SCONV: + lt = p->n_left->n_type; + switch (p->n_type) { + case LONGLONG: + if (lt == FLOAT) + mkcall(p, "__fixsfdi"); + else if (lt == DOUBLE) + mkcall(p, "__fixdfdi"); + else if (lt == LDOUBLE) + mkcall(p, "__fixxfdi"); + break; + case ULONGLONG: + if (lt == FLOAT) + mkcall(p, "__fixunssfdi"); + else if (lt == DOUBLE) + mkcall(p, "__fixunsdfdi"); + else if (lt == LDOUBLE) + mkcall(p, "__fixunsxfdi"); + break; + case FLOAT: + if (lt == LONGLONG) + mkcall(p, "__floatdisf"); + else if (lt == ULONGLONG) + mkcall(p, "__floatundisf"); + break; + case DOUBLE: + if (lt == LONGLONG) + mkcall(p, "__floatdidf"); + else if (lt == ULONGLONG) + mkcall(p, "__floatundidf"); + break; + case LDOUBLE: + if (lt == LONGLONG) + mkcall(p, "__floatdixf"); + else if (lt == ULONGLONG) + mkcall(p, "__floatundixf"); + break; + } + break; +#if 0 + case XASM: + p->n_name = adjustname(p->n_name); + break; +#endif + } +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + stkpos = p2autooff; + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, fixcalls, 0); + } + if (stkpos > p2autooff) + p2autooff = stkpos; + if (stkpos > p2maxautooff) + p2maxautooff = stkpos; + if (x2debug) + printip(ipole); +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE *p, void *arg) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2, 0); +} + +void +myoptim(struct interpass *ip) +{ +} + +void +rmove(int s, int d, TWORD t) +{ + + if (s >= D0D1 && s <= D6D7) { + printf(" move.l %s,%s\n", + rnames[s-D0D1], rnames[d-D0D1]); + printf(" move.l %s,%s\n", + rnames[s+1-D0D1], rnames[d+1-D0D1]); + } else if (t >= FLOAT && t <= TDOUBLE) + printf(" fmove.x %s,%s\n", rnames[s], rnames[d]); + else + printf(" move.l %s,%s\n", rnames[s], rnames[d]); +} + +/* + * For class cc, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int cc, int *r) +{ + int a,c; + + a = r[CLASSA]; + c = r[CLASSC]; + + switch (cc) { + case CLASSA: + if (c * 2 + a < 8) + return 1; + break; + case CLASSB: + return r[CLASSB] < 6; + case CLASSC: + if (c > 2) + return 0; + if (c == 2 && a > 0) + return 0; + if (c == 1 && a > 1) + return 0; + if (c == 0 && a > 3) + return 0; + return 1; + } + return 0; +} + +char *rnames[] = { + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", + "d0d1", "d1d2", "d2d3", "d3d4", "d4d5", "d5d6", "d6d7", + "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7", +}; + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t > BTMASK) + return CLASSB; + if (t == LONGLONG || t == ULONGLONG) + return CLASSC; + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return CLASSD; + return CLASSA; +} + +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (t < LONGLONG || t == FLOAT || t > BTMASK) + return 4; + if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) + return 8; + if (t == LDOUBLE) + return 12; + if (t == STRTY || t == UNIONTY) + return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+3) & ~3; + comperr("argsiz"); + return 0; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + size += argsiz(p->n_right); + size += argsiz(p); + op->n_qual = size; /* XXX */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + return SRNOPE; +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ +} + +/* + * Do something target-dependent for xasm arguments. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + int cw = xasmcode(p->n_name); + int ww; + char *w; + + ww = XASMVAL(cw); +again: switch (ww) { + case 'd': /* Just convert to reg */ + case 'a': + p->n_name = tmpstrdup(p->n_name); + w = strchr(p->n_name, XASMVAL(cw)); + *w = 'r'; /* now reg */ + break; + case 'o': /* offsetable reg */ + if (p->n_left->n_op == UMUL || p->n_left->n_op == OREG || + p->n_left->n_op == NAME) { + return 1; + } + if (ww == XASMVAL(cw)) + ww = XASMVAL1(cw); + else + ww = XASMVAL2(cw); + goto again; + } + return 0; +} + +/* + * Handle special characters following % in gcc extended assembler. + */ +int +targarg(char *w, void *arg) +{ + switch (w[1]) { + case '.': /* Remove dot if not needed */ + printf("."); + break; + default: + return 0; + } + return 1; +} diff --git a/lang/pcc/pcc/arch/m68k/macdefs.h b/lang/pcc/pcc/arch/m68k/macdefs.h new file mode 100644 index 000000000..d1f7ac685 --- /dev/null +++ b/lang/pcc/pcc/arch/m68k/macdefs.h @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2011 Janne Johansson + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = i ? (val<<8)|lastcon : val + +#define ARGINIT 64 /* # bits above fp where arguments start */ +#define AUTOINIT 0 /* # bits below fp where automatics start */ + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZBOOL 8 +#define SZSHORT 16 +#define SZINT 32 +#define SZLONG 32 +#define SZPOINT(t) 32 +#define SZLONGLONG 64 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 128 + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALBOOL 8 +#define ALSHORT 16 +#define ALINT 32 +#define ALLONG 32 +#define ALPOINT 32 +#define ALLONGLONG 64 +#define ALFLOAT 32 +#define ALDOUBLE 64 +#define ALLDOUBLE 32 /* ???? */ +/* #undef ALSTRUCT m68k struct alignment is member defined */ +#define ALSTACK 32 +#define ALMAX 64 + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT (-0x7fffffff-1) +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffffU +#define MIN_LONG MIN_INT +#define MAX_LONG MAX_INT +#define MAX_ULONG MAX_UNSIGNED +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +/* Default char is signed */ +#undef CHAR_UNSIGNED +#define BOOL_TYPE UCHAR /* what used to store _Bool */ + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#define LABFMT ".L%d" /* format for printing labels */ +#define STABLBL ".LL%d" /* format for stab (debugging) labels */ +#ifdef LANG_F77 +#define BLANKCOMMON "_BLNK_" +#define MSKIREG (M(TYSHORT)|M(TYLONG)) +#define TYIREG TYLONG +#define FSZLENG FSZLONG +#define AUTOREG EBP +#define ARGREG EBP +#define ARGOFFSET 8 +#endif + +#define BACKAUTO /* stack grows negatively for automatics */ +#define BACKTEMP /* stack grows negatively for temporaries */ + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_BE /* big-endian */ + +#undef FINDMOPS /* XXX FIXME */ + +#define CC_DIV_0 /* division by zero is safe in the compiler */ + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&03) +#define wdal(k) (BYTEOFF(k)==0) + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) +#define genfcall(a,b) gencall(a,b) + +/* How many integer registers are needed? (used for stack allocation) */ +#define szty(t) ((t) == LDOUBLE ? 3 : \ + (t) == DOUBLE || DEUNSIGN(t) == LONGLONG ? 2 : 1) + +/* + * All registers are given a sequential number to + * identify it which must match rnames[] in local2.c. + * + * The classes used on m68k are: + * A - 32-bit data registers + * B - 32-bit address registers + * C - 64-bit combined registers + * D - 80-bit floating point registers + */ +#define D0 0 +#define D1 1 +#define D2 2 +#define D3 3 +#define D4 4 +#define D5 5 +#define D6 6 +#define D7 7 + +/* no support yet for using A registers for data calculations */ +#define A0 8 +#define A1 9 +#define A2 10 +#define A3 11 +#define A4 12 +#define A5 13 +#define A6 14 /* frame pointer? Isnt it A4 on amigaos.. */ +#define A7 15 /* Stack pointer */ + +#define D0D1 16 +#define D1D2 17 +#define D2D3 18 +#define D3D4 19 +#define D4D5 20 +#define D5D6 21 +#define D6D7 22 + +#define FP0 23 +#define FP1 24 +#define FP2 25 +#define FP3 26 +#define FP4 27 +#define FP5 28 +#define FP6 29 +#define FP7 30 + +#define MAXREGS 31 /* 31 registers */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SBREG|TEMPREG, SBREG|TEMPREG, SBREG|PERMREG, SBREG|PERMREG, \ + SBREG|PERMREG, SBREG|PERMREG, 0, 0, /* fp and sp are ignored here */ \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SDREG|TEMPREG, SDREG|TEMPREG, SDREG|PERMREG, SDREG|PERMREG, \ + SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, + + +/* no overlapping registers at all */ +#define ROVERLAP \ + /* 8 data registers */ \ + { D0D1, -1},\ + { D1D2, D0D1, -1},\ + { D2D3, D1D2,-1},\ + { D3D4, D2D3,-1},\ + { D4D5, D3D4,-1},\ + { D5D6, D4D5,-1},\ + { D6D7, D5D6,-1},\ + { D6D7, -1},\ + /* 8 adress registers */ \ + { -1}, \ + { -1}, \ + { -1}, \ + { -1}, \ + { -1}, \ + { -1}, \ + { -1}, \ + { -1}, \ + { D0, D1, D1D2, -1}, \ + { D1, D2, D0D1, D2D3, -1}, \ + { D2, D3, D1D2, D3D4, -1}, \ + { D3, D4, D2D3, D4D5, -1}, \ + { D4, D5, D3D4, D5D6, -1}, \ + { D5, D6, D4D5, D6D7, -1}, \ + { D6, D7, D5D6, -1}, \ + { -1}, \ + { -1}, \ + { -1}, \ + { -1}, \ + { -1}, \ + { -1}, \ + { -1}, \ + { -1}, + + +/* Return a register class based on the type of the node */ +#define PCLASS(p) (p->n_type == FLOAT || p->n_type == DOUBLE || \ + p->n_type == LDOUBLE ? SDREG : p->n_type == LONGLONG || \ + p->n_type == ULONGLONG ? SCREG : p->n_type > BTMASK ? SBREG : SAREG) + +#define NUMCLASS 4 /* highest number of reg classes used */ + +int COLORMAP(int c, int *r); +#define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 23 ? CLASSC : CLASSD) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 12) /* A1 */ +#define ENCRA2(x) ((x) << 18) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ + +#define RETREG(x) ((x) == FLOAT || (x) == DOUBLE || (x) == LDOUBLE ? FP0 : \ + (x) == LONGLONG || (x) == ULONGLONG ? D0D1 : (x) > BTMASK ? A0 : D0) + +#define FPREG A6 /* frame pointer */ +#define STKREG A7 /* stack pointer */ + +#define HAVE_WEAKREF +#define TARGET_FLT_EVAL_METHOD 2 /* all as long double */ + +/* + * Extended assembler macros. + */ +int targarg(char *w, void *arg); +#define XASM_TARGARG(w, ary) (w[1] == 'b' ? w++, 0 : targarg(w, ary)) + diff --git a/lang/pcc/pcc/arch/m68k/order.c b/lang/pcc/pcc/arch/m68k/order.c new file mode 100644 index 000000000..92722ae0b --- /dev/null +++ b/lang/pcc/pcc/arch/m68k/order.c @@ -0,0 +1,180 @@ +/* $Id: order.c,v 1.5 2016/01/30 17:26:19 ragge Exp $ */ +/* + * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +#include + +int canaddr(NODE *); + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + if (off > MAX_SHORT || off < MIN_SHORT) + return 1; /* max signed 16-bit offset */ + return(0); /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + * Be careful about register classes, this is a place where classes change. + * Especially on m68k we must be careful about class changes; + * Pointers can only have a scalar added to it if PLUS, but when + * MINUS may be either only pointers or left pointer and right scalar. + * + * So far we only handle the trivial OREGs here. + */ +void +offstar(NODE *p, int shape) +{ + NODE *q; + + if (x2debug) { + printf("offstar(%p)\n", p); + fwalk(p, e2print, 0); + } + + if (isreg(p)) + return; /* Matched (%a0) */ + + q = p->n_right; + if ((p->n_op == PLUS || p->n_op == MINUS) && q->n_op == ICON && + notoff(0, 0, getlval(q), 0) == 0 && !isreg(p->n_left)) { + (void)geninsn(p->n_left, INBREG); + return; + } + (void)geninsn(p, INBREG); +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + * For simple OREGs conversion should already be done. + */ +void +myormake(NODE *q) +{ +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Turns currently anything into OREG on x86 */ + if (shape & SOREG) + return SROREG; + return SRNOPE; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + case STASG: + { + static struct rspecial s[] = { + { NEVER, D0 }, { NEVER, D1 }, + { NEVER, A0 }, { NEVER, A1 }, + /* { NRES, A0 }, */ { 0 } }; + return s; + } + } + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; +} + +/* + * set registers in calling conventions live. + */ +int * +livecall(NODE *p) +{ + static int r[] = { A0, -1 }; + + if (p->n_op == STCALL) + return r; /* only if struct return */ + return &r[1]; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/m68k/table.c b/lang/pcc/pcc/arch/m68k/table.c new file mode 100644 index 000000000..860be6eab --- /dev/null +++ b/lang/pcc/pcc/arch/m68k/table.c @@ -0,0 +1,1007 @@ +/* $Id: table.c,v 1.13 2015/10/27 14:48:50 ragge Exp $ */ +/* + * Copyright (c) 2014 Anders Magnusson (ragge@ludd.ltu.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +#define TLL TLONGLONG|TULONGLONG +#define TAREG TINT|TSHORT|TCHAR|TUNSIGNED|TUSHORT|TUCHAR +#define SABREG SAREG|SBREG +#define TFP TFLOAT|TDOUBLE|TLDOUBLE + +# define ANYSIGNED TINT|TSHORT|TCHAR +# define ANYUSIGNED TUNSIGNED|TUSHORT|TUCHAR +# define ANYFIXED ANYSIGNED|ANYUSIGNED +# define TUWORD TUNSIGNED +# define TSWORD TINT +# define TWORD TUWORD|TSWORD +#define TANYINT TLL|ANYFIXED +#define SHINT SAREG /* Any integer */ +#define ININT INAREG +#define SHFL SCREG /* shape for long double */ +#define INFL INCREG /* shape for long double */ + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* begin with all these casts */ + +/* pointer to pointer (same reg class) */ +{ PCONV, INBREG, + SBREG, TPOINT, + SBREG, TANY, + 0, RLEFT, + "", }, + +/* (u)int -> pointer */ +{ PCONV, INBREG, + SAREG, TWORD, + SBREG, TANY, + NBREG, RESC1, + " move.l AL,A1\n", }, + +/* pointer to int/unsigned */ +{ SCONV, INAREG, + SBREG, TPOINT, + SAREG, TWORD, + NAREG, RESC1, + " move.l AL,A1\n", }, + +/* (u)char -> (u)char */ +{ SCONV, INAREG, + SAREG, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + 0, RLEFT, + "", }, + +/* char -> short/ushort */ +{ SCONV, INAREG|INBREG, + SABREG, TCHAR, + SABREG, TSHORT|TUSHORT, + 0, RLEFT, + " ext.w AL\n", }, + +/* uchar -> short/ushort */ +{ SCONV, INAREG|INBREG, + SABREG, TUCHAR, + SABREG, TSHORT|TUSHORT, + 0, RLEFT, + " and.l #255,AL\n", }, + +/* char -> (u)int */ +{ SCONV, INAREG, + SAREG, TCHAR, + SAREG, TINT|TUNSIGNED, + 0, RLEFT, + " extb.l AL\n", }, + +/* uchar -> (u)int */ +{ SCONV, INAREG, + SAREG, TUCHAR, + SAREG, TINT|TUNSIGNED, + 0, RLEFT, + " and.l #255,AL\n", }, + +/* char -> (u)longlong */ +{ SCONV, INCREG, + SAREG|SNAME|SOREG, TCHAR, + SCREG, TLL, + NCREG, RESC1, + " move.b AL,U1\n extb.l U1\n" + " smi A1\n extb.l A1\n", }, + +/* uchar -> (u)longlong */ +{ SCONV, INCREG, + SAREG|SNAME|SOREG, TUCHAR, + SCREG, TLL, + NCREG, RESC1, + " move.b AL,U1\n and.l #255,U1\n clr.l A1\n", }, + +/* char -> float/(l)double */ +{ SCONV, INDREG, + SAREG, TCHAR, + SDREG, TFP, + NDREG, RESC1, + " fmove.ZL AL,A1\n", }, + +/* (u)char -> float/(l)double */ +{ SCONV, INDREG, + SAREG, TUCHAR, + SDREG, TFP, + NAREG|NDREG, RESC2, + " clr.l A1\n move.b AL,A1\n fmove.w A1,A2\n", }, + +/* (u)short -> (u)char */ +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG, TCHAR|TUCHAR, + 0, RLEFT, + "", }, + +/* (u)short -> (u)short */ +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RLEFT, + "", }, + +/* short -> (u)int */ +{ SCONV, INAREG|INBREG, + SABREG, TSHORT, + SABREG, TINT|TUNSIGNED, + 0, RLEFT, + " ext.l AL\n", }, + +/* ushort -> (u)int */ +{ SCONV, INAREG|INBREG, + SABREG, TUSHORT, + SABREG, TINT|TUNSIGNED, + 0, RLEFT, + " and.l #65535,AL\n", }, + +/* short -> (u)longlong */ +{ SCONV, INCREG, + SAREG, TSHORT, + SCREG, TLL, + NCREG, RESC1, + " move AL,U1\n ext.l U1\n" + " smi A1\n extb.l A1\n", }, + +/* ushort -> (u)longlong */ +{ SCONV, INCREG, + SAREG|SNAME|SOREG, TUSHORT, + SCREG, TLL, + NCREG, RESC1, + " move.l AL,U1\n and.l #65535,U1\n clr.l A1\n", }, + +/* short -> float/(l)double */ +{ SCONV, INDREG, + SAREG|SNAME|SOREG, TSHORT, + SDREG, TFP, + NDREG|NDSL, RESC1, + " fmove.w AL,A1\n", }, + +/* ushort -> float/(l)double */ +{ SCONV, INDREG, + SAREG|SNAME|SOREG, TUSHORT, + SAREG|SDREG, TFP, + NAREG|NDREG|NDSL, RESC2, + " move.w AL,A1\n and.l #65535,A1\n" + " fmove.l A1,A2\n", }, + +/* (u)int -> (u)char */ +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TCHAR|TUCHAR, + 0, RLEFT, + " and.l #255,AL\n", }, + +/* (u)int -> (u)short */ +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " and.l #65535,AL\n", }, + +/* (u)int -> (u)int - nothing */ +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TWORD, + 0, RLEFT, + "", }, + +/* int -> (u)longlong */ +{ SCONV, INCREG, + SAREG|SOREG|SNAME, TINT, + SCREG, TLL, + NCREG, RESC1, + " move.l AL,U1\n smi A1\n extb.l A1\n", }, + +/* (u)int -> (u)longlong */ +{ SCONV, INCREG, + SAREG|SOREG|SNAME, TUNSIGNED, + SCREG, TLL, + NCREG, RESC1, + " move.l AL,U1\n clr.l A1\n", }, + +/* int -> float/(l)double */ +{ SCONV, INDREG, + SAREG|SNAME|SOREG, TINT, + SDREG, TFP, + NDREG|NDSL, RESC1, + " fmove.l AL,A1\n", }, + +/* uint -> double */ +{ SCONV, INDREG, + SAREG, TUNSIGNED, + SDREG, TFLOAT|TDOUBLE, + NDREG|NDSL, RESC1, + " fmove.l AL,A1\n" + " tst.l AL\n" + " jge 1f\n" + " fadd.d #0x41f0000000000000,A1\n" + "1:\n", }, + +/* (u)longlong -> (u)char/(u)short/(u)int */ +{ SCONV, INAREG, + SCREG|SOREG|SNAME, TLL, + SAREG, TAREG, + NAREG, RESC1, + " movl UL,A1\n", }, + +/* (u)longlong to (u)longlong */ +{ SCONV, INCREG, + SCREG, TLL, + SCREG, TLL, + 0, RLEFT, + "", }, + +/* float/(l)double -> int/short/char (in reg) */ +{ SCONV, INAREG, + SDREG, TFP, + SAREG, TINT|TSHORT|TCHAR, + NAREG, RESC1, + " fmove.ZA AL,A1\n", }, + +/* float -> unsigned */ +{ SCONV, INAREG, + SDREG, TFLOAT, + SAREG, TUNSIGNED, + NAREG|NDREG|NDSL, RESC1, + "Z2 fcmp.s #0x4f000000,A2\n" + " fjge 2f\n" + " fintrz.x A2,A2\n" + " fmove.l A2,A1\n" + " jra 3f\n" + "2: fsub.s #0x4f000000,A2\n" + " fintrz.x A2,A2\n" + " fmove.l A2,A1\n" + " add.l #-2147483648,A1\n3:\n", }, + +/* float -> (l)double */ +{ SCONV, INDREG, + SDREG, TFLOAT, + SDREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + "", }, /* in fp regs -> do nothing */ + +/* double -> ldouble */ +{ SCONV, INDREG, + SDREG, TDOUBLE, + SDREG, TLDOUBLE, + 0, RLEFT, + "", }, /* in fp regs -> do nothing */ + +/* double -> uchar */ +{ SCONV, INAREG, + SDREG, TDOUBLE, + SAREG, TUCHAR, + NAREG|NDREG|NDSL, RESC1, + " fintrz.x AL,A2\n fmove.w A2,A1\n", }, + +/* double -> ushort */ +{ SCONV, INAREG, + SDREG, TDOUBLE, + SAREG, TUSHORT, + NAREG|NDREG|NDSL, RESC1, + " fintrz.x AL,A2\n fmove.l A2,A1\n", }, + +/* double -> unsigned */ +{ SCONV, INAREG, + SDREG, TDOUBLE, + SAREG, TUNSIGNED, + NAREG|NDREG|NDSL, RESC1, + "Z2 fcmp.d #0x41e0000000000000,A2\n" + " fjge 2f\n" + " fintrz.x A2,A2\n" + " fmove.l A2,A1\n" + " jra 3f\n" + "2: fsub.d #0x41e0000000000000,A2\n" + " fintrz.x A2,A2\n" + " fmove.l A2,A1\n" + " add.l #-2147483648,A1\n3:\n", }, + +/* (l)double -> float */ +{ SCONV, INDREG, + SDREG, TDOUBLE|TLDOUBLE, + SDREG, TFLOAT, + NAREG, RLEFT, + " fmove.s AL,A1\n fmove.s A1,AL\n", }, + +/* ldouble -> double */ +{ SCONV, INDREG, + SDREG, TLDOUBLE, + SDREG, TDOUBLE, + NTEMP*2, RLEFT, + " fmove.d AL,A1\n fmove.d A1,AL\n", }, + +/* assignment */ +{ ASSIGN, FOREFF, + SCREG|SNAME|SOREG, TLL, + SCREG|SNAME|SOREG, TLL, + 0, 0, + " move.l AR,AL\n" + " move.l UR,UL\n", }, + +{ ASSIGN, INCREG, + SCREG|SNAME|SOREG, TLL, + SCREG, TLL, + 0, RDEST, + " move.l AR,AL\n" + " move.l UR,UL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TAREG, + SAREG|SNAME|SOREG, TAREG, + 0, 0, + " move.ZA AR,AL\n", }, + +{ ASSIGN, FOREFF, + SBREG|SNAME|SOREG, TPOINT, + SBREG|SNAME|SOREG, TPOINT, + 0, 0, + " move.l AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TAREG, + SAREG, TAREG, + 0, RDEST, + " move.ZA AR,AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG|SNAME|SOREG, TPOINT, + SBREG, TPOINT, + 0, RDEST, + " move.l AR,AL\n", }, + +{ ASSIGN, FOREFF|INDREG, + SNAME|SOREG, TFP, + SDREG, TFP, + 0, RDEST, + " fmove.ZA AR,AL\n", }, + +{ ASSIGN, FOREFF|INDREG, + SDREG, TFP, + SNAME|SOREG, TFP, + 0, RDEST, + " fmove.ZA AR,AL\n", }, + +{ ASSIGN, FOREFF|INDREG, + SDREG, TFP, + SDREG, TFP, + 0, RDEST, + " fmove.x AR,AL\n", }, + +/* structure stuff */ +{ STASG, INBREG|FOREFF, + SOREG|SNAME, TANY, + SBREG, TPTRTO|TANY, + NSPECIAL, RDEST, + "ZQ", }, +/* + * Simple ops (add, sub, and, or, xor) + */ +/* Address registers may be added to (or subtracted from) */ +{ PLUS, FOREFF, + SBREG|SNAME|SOREG|SCON, TWORD|TPOINT, + SAREG, TWORD, + 0, 0, + " add.l AR,AL\n", }, + +{ PLUS, FOREFF|INBREG, + SBREG, TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD, + 0, RLEFT|RESCC, + " add.l AR,AL\n", }, + +{ PLUS, FOREFF|INDREG, + SDREG, TFP, + SNAME|SOREG|SCON, TFP, + 0, RLEFT|RESCC, + " fadd.ZA AR,AL\n", }, + +{ PLUS, FOREFF|INDREG, + SDREG, TFP, + SDREG, TFP, + 0, RLEFT|RESCC, + " fadd.x AR,AL\n", }, + +{ PLUS, FOREFF|INCREG|RESCC, + SCREG, TLL, + SCREG, TLL, + 0, RLEFT|RESCC, + " add.l UR,UL\n addx.l AR,AL\n", }, + +{ MINUS, FOREFF, + SBREG|SNAME|SOREG|SCON, TWORD|TPOINT, + SBREG, TWORD, + 0, 0, + " sub.l AR,AL\n", }, + +{ MINUS, INAREG, + SBREG, TPOINT, + SBREG, TPOINT, + NAREG, RESC1, + " move.l AL,A1\n sub.l AR,A1\n", }, + +{ MINUS, FOREFF|INBREG, + SBREG, TWORD|TPOINT, + SABREG|SNAME|SOREG|SCON, TWORD, + 0, RLEFT|RESCC, + " sub.l AR,AL\n", }, + +{ MINUS, FOREFF|INDREG, + SDREG, TFP, + SNAME|SOREG|SCON, TFP, + 0, RLEFT|RESCC, + " fsub.ZA AR,AL\n", }, + +{ MINUS, FOREFF|INDREG, + SDREG, TFP, + SDREG, TFP, + 0, RLEFT|RESCC, + " fsub.x AR,AL\n", }, + +{ MINUS, FOREFF|INCREG|RESCC, + SCREG, TLL, + SCREG, TLL, + 0, RLEFT|RESCC, + " sub.l UR,UL\n subx.l AR,AL\n", }, + +/* two pointers give a scalar */ +{ MINUS, INAREG|FORCC, + SBREG|SNAME|SOREG|SCON, TPOINT, + SBREG|SNAME|SOREG|SCON, TPOINT, + NAREG, RESC1|RESCC, + " move.l AL,A1\n sub.l AR,A1\n", }, + +/* Hack to allow for opsimp later down */ +/* Fortunately xor is not that common */ +{ ER, FOREFF|INAREG, + SAREG, TAREG, + SNAME|SOREG|SCON, TAREG, + NAREG, RLEFT|RESCC, + " move.ZA AR,A1\n eor.ZA A1,AL\n", }, + +{ ER, FOREFF|INCREG|FORCC, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG, TLL, + 0, RLEFT|RESCC, + " eor.l AR,AL\n eor.l UR,UL\n", }, + +{ AND, FOREFF|INCREG|FORCC, + SCREG, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + 0, RLEFT|RESCC, + " and.l AR,AL\n and.l UR,UL\n", }, + +{ OR, FOREFF|INCREG|FORCC, + SCREG, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + 0, RLEFT|RESCC, + " or.l AR,AL\n or.l UR,UL\n", }, + +{ OPSIMP, FOREFF|INAREG, + SAREG, TAREG, + SAREG|SNAME|SOREG|SCON, TAREG, + 0, RLEFT|RESCC, + " Oz.ZA AR,AL\n", }, + +{ OPSIMP, FOREFF, + SAREG|SNAME|SOREG, TAREG, + SAREG, TAREG, + 0, RLEFT|RESCC, + " Oz.ZA AR,AL\n", }, + +/* + * Negate a word. + */ + +{ UMINUS, FOREFF|INCREG|FORCC, + SCREG, TLL, + SCREG, TLL, + 0, RLEFT|RESCC, + " neg.l UL\n negx.l AL\n", }, + +{ UMINUS, FOREFF|INAREG|FORCC, + SAREG, TAREG, + SAREG, TAREG, + 0, RLEFT|RESCC, + " neg.ZA AL\n", }, + +{ UMINUS, INDREG|FORCC, + SDREG, TFP, + SDREG, TFP, + NDREG, RESC1|RESCC, + " fmovecr #0xf,A1\n fsub.x AL,A1\n", }, + +{ UMINUS, INDREG|FORCC, + SNAME|SOREG, TFP, + SDREG, TFP, + NDREG, RESC1|RESCC, + " fmovecr #0xf,A1\n fsub.ZA AL,A1\n", }, + +{ COMPL, FOREFF|INAREG|FORCC, + SAREG, TAREG, + SAREG, TAREG, + 0, RLEFT|RESCC, + " not.ZA AL\n", }, + +{ COMPL, FOREFF|INCREG, + SCREG, TLL, + SANY, TANY, + 0, RLEFT, + " not.l AL\n not.l UL\n", }, + +/* + * Shift operators. + */ +{ LS, INAREG|FOREFF, + SAREG, TAREG, + SAREG, TAREG, + 0, RLEFT, + " lsl.ZA AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG, TUNSIGNED|TUSHORT|TUCHAR, + SAREG, TAREG, + 0, RLEFT, + " lsr.ZA AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG, TINT|TSHORT|TCHAR, + SAREG, TAREG, + 0, RLEFT, + " asr.ZA AR,AL\n", }, + +/* + * Leaf movements + */ +{ OPLTYPE, INCREG, + SANY, TANY, + SCREG|SCON|SOREG|SNAME, TLL, + NCREG|NCSL, RESC1, + " move.l AL,A1\n move.l UL,U1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TAREG, + NAREG|NASL, RESC1, + " move.ZA AL,A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG|SCON|SOREG|SNAME, TPOINT, + NBREG|NBSL, RESC1, + " move.l AL,A1\n", }, + +{ OPLTYPE, INDREG, + SANY, TANY, + SNAME|SOREG, TFP, + NDREG|NDSL, RESC1, + " fmove.ZA AL,A1\n", }, + +{ OPLTYPE, INDREG, + SANY, TANY, + SDREG, TFP, + NDREG|NDSL, RESC1, + " fmove.x AL,A1\n", }, + +/* + * Indirection operators. + */ +{ UMUL, INCREG, + SANY, TPOINT, + SOREG, TLL, + NCREG, RESC1, + " move.l AL,A1\n move.l UL,U1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG|NASL, RESC1, + " move.l AL,A1\n", }, + +{ UMUL, INBREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NBREG|NBSL, RESC1, + " move.l AL,A1\n", }, + +{ UMUL, INDREG, + SANY, TPOINT|TFP, + SOREG, TFP, + NDREG|NDSL, RESC1, + " fmove.ZA AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " move.w AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " move.b AL,A1\n", }, + + +/* + * DIV/MOD/MUL + */ +{ DIV, INAREG, + SAREG|SNAME|SOREG, TINT, + SAREG, TINT, + 0, RLEFT, + " divs.l AR,AL\n", }, + +{ DIV, INAREG, + SAREG|SNAME|SOREG, TUNSIGNED, + SAREG, TUNSIGNED, + 0, RLEFT, + " divu.l AR,AL\n", }, + +{ DIV, INDREG, + SDREG, TDOUBLE|TLDOUBLE, + SNAME|SOREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + " fdiv.ZA AR,AL\n", }, + +{ DIV, INDREG, + SDREG, TFP, + SDREG, TFP, + 0, RLEFT, + " fdiv.x AR,AL\n", }, + +{ DIV, INDREG, + SDREG, TFLOAT, + SNAME|SOREG, TFLOAT, + 0, RLEFT, + " fsgldiv.ZA AR,AL\n", }, + +{ MOD, INAREG, + SAREG, TINT, + SAREG|SNAME|SOREG, TINT, + NAREG*2, RESC1, + "mov.l AL,A2\n divsl.l AR,A1:A2\n", }, + +{ MOD, INAREG, + SAREG, TUNSIGNED, + SAREG|SNAME|SOREG, TUNSIGNED, + NAREG*2, RESC1, + "mov.l AL,A2\n divul.l AR,A1:A2\n", }, + +{ MUL, INAREG, + SAREG|SNAME|SOREG, TWORD, + SAREG, TWORD, + 0, RLEFT, + " muls.l AR,AL\n", }, + +{ MUL, INDREG, + SDREG, TDOUBLE|TLDOUBLE, + SNAME|SOREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + " fmul.ZA AR,AL\n", }, + +{ MUL, INDREG, + SDREG, TFP, + SDREG, TFP, + 0, RLEFT, + " fmul.x AR,AL\n", }, + +{ MUL, INDREG, + SDREG, TFLOAT, + SNAME|SOREG, TFLOAT, + 0, RLEFT, + " fsglmul.s AR,AL\n", }, + +/* + * Function call nodes. + * Too many of them. + */ +/* FOREFF both direct and indirect */ +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " ZC CL\n", }, + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " ZC CL\nZB", }, + +{ UCALL, FOREFF, + SBREG, TANY, + SANY, TANY, + 0, 0, + " jsr (AL)\n", }, + +{ CALL, FOREFF, + SBREG, TANY, + SANY, TANY, + 0, 0, + " jsr (AL)\nZB", }, + +/* small scalar both direct and indirect */ +{ UCALL, INAREG, + SCON, TANY, + SAREG, TAREG, + NAREG|NASL, RESC1, + " ZC CL\n", }, + +{ CALL, INAREG, + SCON, TANY, + SAREG, TAREG, + NAREG|NASL, RESC1, + " ZC CL\nZB", }, + +{ UCALL, INAREG, + SBREG, TANY, + SAREG, TAREG, + NAREG|NASL, RESC1, + " jsr (AL)\n", }, + +{ CALL, INAREG, + SBREG, TANY, + SAREG, TAREG, + NAREG|NASL, RESC1, + " jsr (AL)\nZB", }, + +/* long long both direct and indirect */ +{ UCALL, INCREG, + SCON, TANY, + SCREG, TLL, + NCREG|NCSL, RESC1, + " ZC CL\n", }, + +{ CALL, INCREG, + SCON, TANY, + SCREG, TLL, + NCREG|NCSL, RESC1, + " ZC CL\nZB", }, + +{ UCALL, INCREG, + SBREG, TANY, + SCREG, TLL, + NCREG|NCSL, RESC1, + " jsr (AL)\n", }, + +{ CALL, INCREG, + SBREG, TANY, + SCREG, TLL, + NCREG|NCSL, RESC1, + " jsr (AL)\nZB", }, + +/* floats both direct and indirect */ +{ UCALL, INDREG, + SCON, TANY, + SDREG, TFP, + NDREG|NDSL, RESC1, + " ZC CL\n", }, + +{ CALL, INDREG, + SCON, TANY, + SDREG, TFP, + NDREG|NDSL, RESC1, + " ZC CL\nZB", }, + +{ UCALL, INDREG, + SBREG, TANY, + SDREG, TFP, + NDREG|NDSL, RESC1, + " jsr (AL)\n", }, + +{ CALL, INDREG, + SBREG, TANY, + SDREG, TFP, + NDREG|NDSL, RESC1, + " jsr (AL)\nZB", }, + +/* pointers both direct and indirect */ +{ UCALL, INBREG, + SCON, TANY, + SBREG, TWORD|TPOINT, + NBREG|NBSL, RESC1, + " ZC CL\n", }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, TWORD|TPOINT, + NBREG|NBSL, RESC1, + " ZC CL\nZB", }, + +{ UCALL, INBREG, + SBREG, TANY, + SBREG, TWORD|TPOINT, + NBREG|NBSL, RESC1, + " jsr (AL)\n", }, + +{ CALL, INBREG, + SBREG, TANY, + SBREG, TWORD|TPOINT, + NBREG|NBSL, RESC1, + " jsr (AL)\nZB", }, + + +/* struct return both direct and indirect */ +{ USTCALL, INBREG|FOREFF, + SCON, TANY, + SBREG, TWORD|TPOINT, + NBREG|NBSL, RESC1, + "ZP ZC CL\n", }, + +{ STCALL, INBREG|FOREFF, + SCON, TANY, + SBREG, TWORD|TPOINT, + NBREG|NBSL, RESC1, + "ZP ZC CL\nZB", }, + +{ USTCALL, INBREG|FOREFF, + SBREG, TANY, + SBREG, TWORD|TPOINT, + NBREG|NBSL, RESC1, + "ZP jsr (AL)\n", }, + +{ STCALL, INBREG|FOREFF, + SBREG, TANY, + SBREG, TWORD|TPOINT, + NBREG|NBSL, RESC1, + "ZP jsr (AL)\nZB", }, + + +/* + * Arguments to functions. + */ +{ FUNARG, FOREFF, + SAREG|SOREG|SNAME|SCON, TINT|TUNSIGNED, + SANY, TANY, + 0, RNULL, + " move.l AL,-(%sp)\n", }, + +{ FUNARG, FOREFF, + SCREG|SOREG|SNAME|SCON, TLL, + SANY, TANY, + 0, RNULL, + " move.l UL,-(%sp)\n move.l AL,-(%sp)\n", }, + +{ FUNARG, FOREFF, + SCON, TPOINT, + SANY, TANY, + 0, RNULL, + " pea CL\n", }, + +{ FUNARG, FOREFF, + SCON|SABREG|SNAME, TWORD|TPOINT, + SANY, TWORD|TPOINT, + 0, RNULL, + " move.l AL,-(%sp)\n", }, + +{ FUNARG, FOREFF, + SOREG, TWORD|TPOINT, + SANY, TWORD|TPOINT, + 0, RNULL, + " move.l AL,-(%sp)\n", }, + +{ FUNARG, FOREFF, + SDREG, TFP, + SANY, TFP, + 0, RNULL, + " fmove.ZA AL,-(%sp)\n", }, + +{ STARG, FOREFF, + SBREG, TPTRTO|TSTRUCT, + SANY, TSTRUCT, + NAREG|NBREG, RNULL, + "ZS", }, + +/* + * Logical/branching operators + */ + +/* Comparisions, take care of everything */ +#if 0 +{ OPLOG, FORCC, + SHLL|SOREG|SNAME, TLL, + SHLL, TLL, + 0, 0, + "ZD", }, +#endif + +{ OPLOG, INCREG|FORCC, + SCREG, TLL, + SCREG, TLL, + 0, RESCC|RLEFT, /* trash left nodes */ + " sub.l UR,UL\n subx.l AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG, TWORD, + SCON|SAREG|SOREG|SNAME, TWORD, + 0, RESCC, + " cmp.l AR,AL\n", }, + +{ OPLOG, FORCC, + SBREG, TPOINT, + SCON|SBREG|SOREG|SNAME, TPOINT, + 0, RESCC, + " cmp.l AR,AL\n", }, + +/* jumps below emitted in zzzcode */ +{ OPLOG, FORCC, + SDREG, TFP, + SCON|SOREG|SNAME, TFP, + 0, 0, + " fcmp.ZL AR,AL\n ZF", }, + +{ OPLOG, FORCC, + SDREG, TFP, + SDREG, TFP, + 0, 0, + " fcmp.x AR,AL\n ZF", }, + + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jmp LL\n", }, + +#if defined(GCC_COMPAT) || defined(LANG_F77) +{ GOTO, FOREFF, + SBREG, TANY, + SANY, TANY, + 0, RNOP, + " jmp (AL)\n", }, +#endif + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +/* { INIT, DF(INIT), }, */ + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/mips/TODO b/lang/pcc/pcc/arch/mips/TODO new file mode 100644 index 000000000..07072de72 --- /dev/null +++ b/lang/pcc/pcc/arch/mips/TODO @@ -0,0 +1,2 @@ +* Fix floating-point arguments in registers +* Fix structure arguments in registers diff --git a/lang/pcc/pcc/arch/mips/code.c b/lang/pcc/pcc/arch/mips/code.c new file mode 100644 index 000000000..c77aecc2f --- /dev/null +++ b/lang/pcc/pcc/arch/mips/code.c @@ -0,0 +1,738 @@ +/* $Id: code.c,v 1.27 2016/01/06 16:11:24 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +#include +#include "pass1.h" + +#ifndef LANG_CXX +#undef NIL +#define NIL NULL +#define NODE P1ND +#define nfree p1nfree +#define ccopy p1tcopy +#define tfree p1tfree +#endif + +/* + * Print out assembler segment name. + */ +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + case DATA: + case LDATA: name = ".data"; break; + case STRNG: + case RDATA: name = ".section .rodata"; break; + case UDATA: break; + case PICLDATA: + case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; + case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; + case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; + case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; + case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; + case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; + case NMSEG: + printf("\t.section %s,\"a%c\",@progbits\n", name, + cftnsp ? 'x' : 'w'); + return; + } + printf("\t%s\n", name); +} + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + char *n; + + if (ISFTN(sp->stype)) + return; /* XXX until fixed */ + + n = getexname(sp); + + if (sp->sclass == EXTDEF) + printf(" .globl %s\n", n); + if (sp->slevel == 0) { +#ifdef USE_GAS + printf("\t.type %s,@%s\n", n, + ISFTN(sp->stype) ? "function" : "object"); + if (!ISFTN(sp->stype)) + printf("\t.size %s," CONFMT "\n", n, + tsize(sp->stype, sp->sdf, sp->sap)); +#endif + printf("%s:\n", n); + } else + printf(LABFMT ":\n", sp->soffset); +} + + +/* + * cause the alignment to become a multiple of n + */ +void +defalign(int n) +{ + n = ispow2(n / SZCHAR); + if (n == -1) + cerror("defalign: n != 2^i"); + printf("\t.p2align %d\n", n); +} + +static int rvnr; + +/* + * code for the end of a function + * deals with struct return here + */ +void +efcode(void) +{ + NODE *p, *q; + int tempnr; + int ty; + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + + ty = cftnsp->stype - FTN; + + q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); + q->n_rval = V0; + p = tempnode(0, INCREF(ty), 0, cftnsp->sap); + tempnr = regno(p); + p = buildtree(ASSIGN, p, q); + ecomp(p); + + q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap); + q = buildtree(UMUL, q, NIL); + + p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); + p = buildtree(UMUL, p, NIL); + + p = buildtree(ASSIGN, p, q); + ecomp(p); + + q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); + p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); + p->n_rval = V0; + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + +/* Put a symbol in a temporary + * used by bfcode() and its helpers */ +static void +putintemp(struct symtab *sym) +{ + NODE *p; + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + p = buildtree(ASSIGN, p, nametree(sym)); + sym->soffset = regno(p->n_left); + sym->sflags |= STNODE; + ecomp(p); +} + +/* setup the hidden pointer to struct return parameter + * used by bfcode() */ +static void +param_retptr(void) +{ + NODE *p, *q; + + p = tempnode(0, PTR+STRTY, 0, cftnsp->sap); + rvnr = regno(p); + q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); + q->n_rval = A0; + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + +/* setup struct parameter + * push the registers out to memory + * used by bfcode() */ +static void +param_struct(struct symtab *sym, int *regp) +{ + int reg = *regp; + NODE *p, *q; + int navail; + int sz; + int off; + int num; + int i; + + navail = nargregs - (reg - A0); + sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT; + off = ARGINIT/SZINT + (reg - A0); + num = sz > navail ? navail : sz; + for (i = 0; i < num; i++) { + q = block(REG, NIL, NIL, INT, 0, 0); + q->n_rval = reg++; + p = block(REG, NIL, NIL, INT, 0, 0); + p->n_rval = FP; + p = block(PLUS, p, bcon(4*off++), INT, 0, 0); + p = block(UMUL, p, NIL, INT, 0, 0); + p = buildtree(ASSIGN, p, q); + ecomp(p); + } + + *regp = reg; +} + +/* setup a 64-bit parameter (double/ldouble/longlong) + * used by bfcode() */ +static void +param_64bit(struct symtab *sym, int *regp, int dotemps) +{ + int reg = *regp; + NODE *p, *q; + int navail; + + /* alignment */ + ++reg; + reg &= ~1; + + navail = nargregs - (reg - A0); + + if (navail < 2) { + /* would have appeared half in registers/half + * on the stack, but alignment ensures it + * appears on the stack */ + if (dotemps) + putintemp(sym); + *regp = reg; + return; + } + + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); + q->n_rval = A0A1 + (reg - A0); + if (dotemps) { + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + sym->soffset = regno(p); + sym->sflags |= STNODE; + } else { + p = nametree(sym); + } + p = buildtree(ASSIGN, p, q); + ecomp(p); + *regp = reg + 2; +} + +/* setup a 32-bit param on the stack + * used by bfcode() */ +static void +param_32bit(struct symtab *sym, int *regp, int dotemps) +{ + NODE *p, *q; + + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); + q->n_rval = (*regp)++; + if (dotemps) { + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + sym->soffset = regno(p); + sym->sflags |= STNODE; + } else { + p = nametree(sym); + } + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + +/* + * XXX This is a hack. We cannot have (l)doubles in more than one + * register class. So we bounce them in and out of temps to + * move them in and out of the right registers. + */ +static void +param_double(struct symtab *sym, int *regp, int dotemps) +{ + int reg = *regp; + NODE *p, *q, *t; + int navail; + int tmpnr; + + /* alignment */ + ++reg; + reg &= ~1; + + navail = nargregs - (reg - A0); + + if (navail < 2) { + /* would have appeared half in registers/half + * on the stack, but alignment ensures it + * appears on the stack */ + if (dotemps) + putintemp(sym); + *regp = reg; + return; + } + + t = tempnode(0, LONGLONG, 0, 0); + tmpnr = regno(t); + q = block(REG, NIL, NIL, LONGLONG, 0, 0); + q->n_rval = A0A1 + (reg - A0); + p = buildtree(ASSIGN, t, q); + ecomp(p); + + if (dotemps) { + sym->soffset = tmpnr; + sym->sflags |= STNODE; + } else { + q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); + p = nametree(sym); + p = buildtree(ASSIGN, p, q); + ecomp(p); + } + *regp = reg + 2; +} + +/* + * XXX This is a hack. We cannot have floats in more than one + * register class. So we bounce them in and out of temps to + * move them in and out of the right registers. + */ +static void +param_float(struct symtab *sym, int *regp, int dotemps) +{ + NODE *p, *q, *t; + int tmpnr; + + t = tempnode(0, INT, 0, 0); + tmpnr = regno(t); + q = block(REG, NIL, NIL, INT, 0, 0); + q->n_rval = (*regp)++; + p = buildtree(ASSIGN, t, q); + ecomp(p); + + if (dotemps) { + sym->soffset = tmpnr; + sym->sflags |= STNODE; + } else { + q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); + p = nametree(sym); + p = buildtree(ASSIGN, p, q); + ecomp(p); + } +} + +/* + * code for the beginning of a function; a is an array of + * indices in symtab for the arguments; n is the number + */ +void +bfcode(struct symtab **sp, int cnt) +{ + union arglist *usym; + int lastreg = A0 + nargregs - 1; + int saveallargs = 0; + int i, reg; + + /* + * Detect if this function has ellipses and save all + * argument register onto stack. + */ + usym = cftnsp->sdf->dfun; + while (usym && usym->type != TNULL) { + if (usym->type == TELLIPSIS) { + saveallargs = 1; + break; + } + ++usym; + } + + reg = A0; + + /* assign hidden return structure to temporary */ + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + param_retptr(); + ++reg; + } + + /* recalculate the arg offset and create TEMP moves */ + for (i = 0; i < cnt; i++) { + + if ((reg > lastreg) && !xtemps) + break; + else if (reg > lastreg) + putintemp(sp[i]); + else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) + param_struct(sp[i], ®); + else if (DEUNSIGN(sp[i]->stype) == LONGLONG) + param_64bit(sp[i], ®, xtemps && !saveallargs); + else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) + param_double(sp[i], ®, xtemps && !saveallargs); + else if (sp[i]->stype == FLOAT) + param_float(sp[i], ®, xtemps && !saveallargs); + else + param_32bit(sp[i], ®, xtemps && !saveallargs); + } + + /* if saveallargs, save the rest of the args onto the stack */ + if (!saveallargs) + return; + while (reg <= lastreg) { + NODE *p, *q; + int off = ARGINIT/SZINT + (reg - A0); + q = block(REG, NIL, NIL, INT, 0, 0); + q->n_rval = reg++; + p = block(REG, NIL, NIL, INT, 0, 0); + p->n_rval = FP; + p = block(PLUS, p, bcon(4*off), INT, 0, 0); + p = block(UMUL, p, NIL, INT, 0, 0); + p = buildtree(ASSIGN, p, q); + ecomp(p); + } + +} + + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ +} + +void +bjobcode(void) +{ + printf("\t.section .mdebug.abi32\n"); + printf("\t.previous\n"); + + /* only if -fpic or -fPIC */ + if (kflag > 0) + printf("\t.abicalls\n"); +} + +#ifdef notdef +/* + * Print character t at position i in one string, until t == -1. + * Locctr & label is already defined. + */ +void +bycode(int t, int i) +{ + static int lastoctal = 0; + + /* put byte i+1 in a string */ + + if (t < 0) { + if (i != 0) + puts("\\000\""); + } else { + if (i == 0) + printf("\t.ascii \""); + if (t == 0) + return; + else if (t == '\\' || t == '"') { + lastoctal = 0; + putchar('\\'); + putchar(t); + } else if (t == 011) { + printf("\\t"); + } else if (t == 012) { + printf("\\n"); + } else if (t < 040 || t >= 0177) { + lastoctal++; + printf("\\%o",t); + } else if (lastoctal && '0' <= t && t <= '9') { + lastoctal = 0; + printf("\"\n\t.ascii \"%c", t); + } else { + lastoctal = 0; + putchar(t); + } + } +} +#endif + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + + +/* setup call stack with a structure */ +/* called from moveargs() */ +static NODE * +movearg_struct(NODE *p, NODE *parent, int *regp) +{ + int reg = *regp; + NODE *l, *q, *t, *r; + int tmpnr; + int navail; + int off; + int num; + int sz; + int ty; + int i; + + navail = nargregs - (reg - A0); + sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT; + num = sz > navail ? navail : sz; + + l = p->n_left; + nfree(p); + ty = l->n_type; + t = tempnode(0, l->n_type, l->n_df, l->n_ap); + tmpnr = regno(t); + l = buildtree(ASSIGN, t, l); + + if (p != parent) { + q = parent->n_left; + } else + q = NULL; + + /* copy structure into registers */ + for (i = 0; i < num; i++) { + t = tempnode(tmpnr, ty, 0, 0); + t = block(SCONV, t, NIL, PTR+INT, 0, 0); + t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); + t = buildtree(UMUL, t, NIL); + + r = block(REG, NIL, NIL, INT, 0, 0); + r->n_rval = reg++; + + r = buildtree(ASSIGN, r, t); + if (q == NULL) + q = r; + else + q = block(CM, q, r, INT, 0, 0); + } + off = ARGINIT/SZINT + nargregs; + for (i = num; i < sz; i++) { + t = tempnode(tmpnr, ty, 0, 0); + t = block(SCONV, t, NIL, PTR+INT, 0, 0); + t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); + t = buildtree(UMUL, t, NIL); + + r = block(REG, NIL, NIL, INT, 0, 0); + r->n_rval = FP; + r = block(PLUS, r, bcon(4*off++), INT, 0, 0); + r = block(UMUL, r, NIL, INT, 0, 0); + + r = buildtree(ASSIGN, r, t); + if (q == NULL) + q = r; + else + q = block(CM, q, r, INT, 0, 0); + } + + if (parent->n_op == CM) { + parent->n_left = q; + q = l; + } else { + q = block(CM, q, l, INT, 0, 0); + } + + *regp = reg; + return q; +} + +/* setup call stack with 64-bit argument */ +/* called from moveargs() */ +static NODE * +movearg_64bit(NODE *p, int *regp) +{ + int reg = *regp; + NODE *q; + int lastarg; + + /* alignment */ + ++reg; + reg &= ~1; + + lastarg = A0 + nargregs - 1; + if (reg > lastarg) { + *regp = reg; + return block(FUNARG, p, NIL, p->n_type, p->n_df, p->n_ap); + } + + q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); + q->n_rval = A0A1 + (reg - A0); + q = buildtree(ASSIGN, q, p); + + *regp = reg + 2; + return q; +} + +/* setup call stack with 32-bit argument */ +/* called from moveargs() */ +static NODE * +movearg_32bit(NODE *p, int *regp) +{ + int reg = *regp; + NODE *q; + + q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); + q->n_rval = reg++; + q = buildtree(ASSIGN, q, p); + + *regp = reg; + return q; +} + +static NODE * +moveargs(NODE *p, int *regp) +{ + NODE *r, **rp; + int lastreg; + int reg; + + if (p->n_op == CM) { + p->n_left = moveargs(p->n_left, regp); + r = p->n_right; + rp = &p->n_right; + } else { + r = p; + rp = &p; + } + + lastreg = A0 + nargregs - 1; + reg = *regp; + + if (reg > lastreg && r->n_op != STARG) + *rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap); + else if (r->n_op == STARG) { + *rp = movearg_struct(r, p, regp); + } else if (DEUNSIGN(r->n_type) == LONGLONG) { + *rp = movearg_64bit(r, regp); + } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { + /* XXX bounce in and out of temporary to change to longlong */ + NODE *t1 = tempnode(0, LONGLONG, 0, 0); + int tmpnr = regno(t1); + NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); + t1 = movearg_64bit(t1, regp); + r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap); + if (p->n_op == CM) { + p->n_left = buildtree(CM, p->n_left, t1); + p->n_right = r; + } else { + p = buildtree(CM, t1, r); + } + } else if (r->n_type == FLOAT) { + /* XXX bounce in and out of temporary to change to int */ + NODE *t1 = tempnode(0, INT, 0, 0); + int tmpnr = regno(t1); + NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); + t1 = movearg_32bit(t1, regp); + r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap); + if (p->n_op == CM) { + p->n_left = buildtree(CM, p->n_left, t1); + p->n_right = r; + } else { + p = buildtree(CM, t1, r); + } + } else { + *rp = movearg_32bit(r, regp); + } + + return p; +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + */ +NODE * +funcode(NODE *p) +{ + int regnum = A0; + NODE *l, *r, *t, *q; + int ty; + + l = p->n_left; + r = p->n_right; + + /* + * if returning a structure, make the first argument + * a hidden pointer to return structure. + */ + ty = DECREF(l->n_type); + if (ty == STRTY+FTN || ty == UNIONTY+FTN) { + ty = DECREF(l->n_type) - FTN; + q = tempnode(0, ty, l->n_df, l->n_ap); + q = buildtree(ADDROF, q, NIL); + if (r->n_op != CM) { + p->n_right = block(CM, q, r, INCREF(ty), + l->n_df, l->n_ap); + } else { + for (t = r; t->n_left->n_op == CM; t = t->n_left) + ; + t->n_left = block(CM, q, t->n_left, INCREF(ty), + l->n_df, l->n_ap); + } + } + + p->n_right = moveargs(p->n_right, ®num); + + return p; +} + +NODE * +builtin_cfa(const struct bitable *bt, NODE *a) +{ + uerror("missing builtin_cfa"); + return bcon(0); +} + +NODE * +builtin_frame_address(const struct bitable *bt, NODE *a) +{ + uerror("missing builtin_frame_address"); + return bcon(0); +} + +NODE * +builtin_return_address(const struct bitable *bt, NODE *a) +{ + uerror("missing builtin_return_address"); + return bcon(0); +} + diff --git a/lang/pcc/pcc/arch/mips/local.c b/lang/pcc/pcc/arch/mips/local.c new file mode 100644 index 000000000..b7e2f5788 --- /dev/null +++ b/lang/pcc/pcc/arch/mips/local.c @@ -0,0 +1,796 @@ +/* $Id: local.c,v 1.38 2016/03/05 15:56:14 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +#include "pass1.h" + +#ifndef LANG_CXX +#define NODE P1ND +#define ccopy p1tcopy +#define tcopy p1tcopy +#define tfree p1tfree +#define nfree p1nfree +#define fwalk p1fwalk +#define talloc p1alloc +#endif + +#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) + +/* this is called to do local transformations on + * an expression tree preparitory to its being + * written out in intermediate code. + */ +NODE * +clocal(NODE *p) +{ + struct symtab *q; + NODE *r, *l; + int o; + int m; + TWORD ty; + int tmpnr, isptrvoid = 0; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal in: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + + switch (o = p->n_op) { + + case UCALL: + case CALL: + case STCALL: + case USTCALL: + if (p->n_type == VOID) + break; + /* + * if the function returns void*, ecode() invokes + * delvoid() to convert it to uchar*. + * We just let this happen on the ASSIGN to the temp, + * and cast the pointer back to void* on access + * from the temp. + */ + if (p->n_type == PTR+VOID) + isptrvoid = 1; + r = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(r); + r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap); + + p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); + if (isptrvoid) { + p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0); + } + p = buildtree(COMOP, r, p); + break; + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + slval(r, 0); + r->n_rval = FP; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case STATIC: + if (q->slevel == 0) + break; + slval(p, 0); + p->n_sp = q; + break; + + case REGISTER: + p->n_op = REG; + slval(p, 0); + p->n_rval = q->soffset; + break; + + } + break; + + case FUNARG: + /* Args smaller than int are given as int */ + if (p->n_type != CHAR && p->n_type != UCHAR && + p->n_type != SHORT && p->n_type != USHORT) + break; + p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); + p->n_type = INT; + p->n_ap = 0; + p->n_rval = SZINT; + break; + + case CBRANCH: + l = p->n_left; + + /* + * Remove unnecessary conversion ops. + */ + if (clogop(l->n_op) && l->n_left->n_op == SCONV) { + if (coptype(l->n_op) != BITYPE) + break; + if (l->n_right->n_op == ICON) { + r = l->n_left->n_left; + if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) + break; + /* Type must be correct */ + ty = r->n_type; + nfree(l->n_left); + l->n_left = r; + l->n_type = ty; + l->n_right->n_type = ty; + } +#if 0 + else if (l->n_right->n_op == SCONV && + l->n_left->n_type == l->n_right->n_type) { + r = l->n_left->n_left; + nfree(l->n_left); + l->n_left = r; + r = l->n_right->n_left; + nfree(l->n_right); + l->n_right = r; + } +#endif + } + break; + + case PCONV: + /* Remove redundant PCONV's. Be careful */ + l = p->n_left; + if (l->n_op == ICON) { + slval(l, (unsigned)glval(l)); + goto delp; + } + if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { + /* float etc? */ + p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); + break; + } + /* if left is SCONV, cannot remove */ + if (l->n_op == SCONV) + break; + + /* avoid ADDROF TEMP */ + if (l->n_op == ADDROF && l->n_left->n_op == TEMP) + break; + + /* if conversion to another pointer type, just remove */ + if (p->n_type > BTMASK && l->n_type > BTMASK) + goto delp; + break; + + delp: l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_ap = p->n_ap; + nfree(p); + p = l; + break; + + case SCONV: + l = p->n_left; + + if (p->n_type == l->n_type) { + nfree(p); + p = l; + break; + } + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + tsize(p->n_type, p->n_df, p->n_ap) == + tsize(l->n_type, l->n_df, l->n_ap)) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + p = l; + break; + } + } + } + + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && + coptype(l->n_op) == BITYPE) { + l->n_type = p->n_type; + nfree(p); + p = l; + } + + if (DEUNSIGN(p->n_type) == SHORT && + DEUNSIGN(l->n_type) == SHORT) { + nfree(p); + p = l; + } + + /* convert float/double to int before to (u)char/(u)short */ + if ((DEUNSIGN(p->n_type) == CHAR || + DEUNSIGN(p->n_type) == SHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left->n_type = INT; + break; + } + + /* convert (u)char/(u)short to int before float/double */ + if ((p->n_type == FLOAT || p->n_type == DOUBLE || + p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR || + DEUNSIGN(l->n_type) == SHORT)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left->n_type = INT; + break; + } + + o = l->n_op; + m = p->n_type; + + if (o == ICON) { + CONSZ val = glval(l); + + if (!ISPTR(m)) /* Pointers don't need to be conv'd */ + switch (m) { + case BOOL: + val = nncon(l) ? (val != 0) : 1; + slval(l, val); + l->n_sp = NULL; + break; + case CHAR: + slval(l, (char)val); + break; + case UCHAR: + slval(l, val & 0377); + break; + case SHORT: + slval(l, (short)val); + break; + case USHORT: + slval(l, val & 0177777); + break; + case ULONG: + case UNSIGNED: + slval(l, val & 0xffffffff); + break; + case LONG: + case INT: + slval(l, (int)val); + break; + case LONGLONG: + slval(l, (long long)val); + break; + case ULONGLONG: + slval(l, val); + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = fltallo(); + FCAST(l->n_dcon)->fp = val; + break; + default: + cerror("unknown type %d", m); + } + l->n_type = m; + nfree(p); + p = l; + } else if (o == FCON) { + CONSZ lv; + if (p->n_type == BOOL) + lv = !FLOAT_ISZERO(FCAST(l->n_dcon)); + else { + FLOAT_FP2INT(lv, FCAST(l->n_dcon), m); + } + slval(l, lv); + l->n_sp = NULL; + l->n_op = ICON; + l->n_type = m; + l->n_ap = 0; + nfree(p); + p = clocal(l); + } + break; + + case MOD: + case DIV: + if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) + break; + if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) + break; + /* make it an int division by inserting conversions */ + p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); + p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); + p = block(SCONV, p, NIL, p->n_type, 0, 0); + p->n_left->n_type = INT; + break; + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + p->n_left->n_rval = RETREG(p->n_type); + break; + } + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal out: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + + return(p); +} + +void +myp2tree(NODE *p) +{ + struct symtab *sp; + + if (p->n_op != FCON) + return; + + /* Write float constants to memory */ + + sp = IALLOC(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->sap = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + + defloc(sp); + ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + + p->n_op = NAME; + slval(p, 0); + p->n_sp = sp; + +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * is an automatic variable of type t OK for a register variable + */ +int +cisreg(TWORD t) +{ + if (t == INT || t == UNSIGNED || t == LONG || t == ULONG) + return(1); + return 0; /* XXX - fix reg assignment in pftn.c */ +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a NAME node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + int nbytes = off / SZCHAR; + + p = buildtree(MUL, p, bcon(nbytes)); + p = buildtree(PLUS, p, bcon(7)); + p = buildtree(AND, p, bcon(~7)); + + /* subtract the size from sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + slval(sp, 0); + sp->n_rval = SP; + ecomp(buildtree(MINUSEQ, sp, p)); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); + sp->n_rval = SP; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ +} + +/* + * print out a constant node + * mat be associated with a label + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; int i[2]; } u; + struct symtab *q; + TWORD t; +#ifndef USE_GAS + int i, j; +#endif + + t = p->n_type; + if (t > BTMASK) + p->n_type = t = INT; /* pointer */ + + if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) + uerror("element not constant"); + + switch (t) { + case LONGLONG: + case ULONGLONG: +#ifdef USE_GAS + printf("\t.dword %lld\n", (long long)glval(p)); +#else + i = glval(p) >> 32; + j = glval(p) & 0xffffffff; + p->n_type = INT; + if (bigendian) { + slval(p, j); + ninval(off, 32, p); + slval(p, i); + ninval(off+32, 32, p); + } else { + slval(p, i); + ninval(off, 32, p); + slval(p, j); + ninval(off+32, 32, p); + } +#endif + break; + case INT: + case UNSIGNED: + printf("\t.word " CONFMT, (CONSZ)glval(p)); + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0)) { + printf("+" LABFMT, q->soffset); + } else + printf("+%s", getexname(q)); + } + printf("\n"); + break; + case SHORT: + case USHORT: + astypnames[SHORT] = astypnames[USHORT] = "\t.half"; + return 0; + case LDOUBLE: + case DOUBLE: + u.d = (double)FCAST(p->n_dcon)->fp; + if (bigendian) { + printf("\t.word\t%d\n", u.i[0]); + printf("\t.word\t%d\n", u.i[1]); + } else { + printf("\t.word\t%d\n", u.i[1]); + printf("\t.word\t%d\n", u.i[0]); + } + break; + case FLOAT: + u.f = (float)FCAST(p->n_dcon)->fp; + printf("\t.word\t0x%x\n", u.i[0]); + break; + default: + return 0; + } + return 1; +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ + if (p == NULL) + return ""; + return p; +} + +/* + * map types which are not defined on the local machine + */ +TWORD +ctype(TWORD type) +{ + switch (BTYPE(type)) { + case LONG: + MODTYPE(type,INT); + break; + + case ULONG: + MODTYPE(type,UNSIGNED); + + } + return (type); +} + +void +calldec(NODE *p, NODE *q) +{ +} + +void +extdec(struct symtab *q) +{ +} + +/* make a common declaration for id, if reasonable */ +void +defzero(struct symtab *sp) +{ + int off; + + off = tsize(sp->stype, sp->sdf, sp->sap); + off = (off+(SZCHAR-1))/SZCHAR; + printf(" .%scomm ", sp->sclass == STATIC ? "l" : ""); + if (sp->slevel == 0) + printf("%s,0%o\n", getexname(sp), off); + else + printf(LABFMT ",0%o\n", sp->soffset, off); +} + + +#ifdef notdef +/* make a common declaration for id, if reasonable */ +void +commdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + + printf(" .comm %s,%d\n", exname(q->soname), off); +} + +/* make a local common declaration for id, if reasonable */ +void +lcommdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + if (q->slevel == 0) + printf("\t.lcomm %s,%d\n", exname(q->soname), off); + else + printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off); +} + +/* + * print a (non-prog) label. + */ +void +deflab1(int label) +{ + printf(LABFMT ":\n", label); +} + +/* ro-text, rw-data, ro-data, ro-strings */ +static char *loctbl[] = { "text", "data", "rdata", "rdata" }; + +void +setloc1(int locc) +{ + if (locc == lastloc && locc != STRNG) + return; + if (locc == RDATA && lastloc == STRNG) + return; + + if (locc != lastloc) { + lastloc = locc; + printf("\t.%s\n", loctbl[locc]); + } + + if (locc == STRNG) + printf("\t.align 2\n"); +} +#endif + +/* + * va_start(ap, last) implementation. + * + * f is the NAME node for this builtin function. + * a is the argument list containing: + * CM + * ap last + * + * It turns out that this is easy on MIPS. Just write the + * argument registers to the stack in va_arg_start() and + * use the traditional method of walking the stackframe. + */ +NODE * +mips_builtin_stdarg_start(const struct bitable *bt, NODE *a) +{ + NODE *p, *q; + int sz = 1; + + /* check num args and type */ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || + !ISPTR(a->n_left->n_type)) + goto bad; + + /* must first deal with argument size; use int size */ + p = a->n_right; + if (p->n_type < INT) { + /* round up to word */ + sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap); + } + + p = buildtree(ADDROF, p, NIL); /* address of last arg */ + p = optim(buildtree(PLUS, p, bcon(sz))); + q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); + q = buildtree(CAST, q, p); + p = q->n_right; + nfree(q->n_left); + nfree(q); + p = buildtree(ASSIGN, a->n_left, p); + nfree(a); + + return p; + +bad: + uerror("bad argument to __builtin_stdarg_start"); + return bcon(0); +} + +NODE * +mips_builtin_va_arg(const struct bitable *bt, NODE *a) +{ + NODE *p, *q, *r; + int sz, tmpnr; + + /* check num args and type */ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || + !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE) + goto bad; + + r = a->n_right; + + /* get type size */ + sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR; + if (sz < SZINT/SZCHAR) { + werror("%s%s promoted to int when passed through ...", + r->n_type & 1 ? "unsigned " : "", + DEUNSIGN(r->n_type) == SHORT ? "short" : "char"); + sz = SZINT/SZCHAR; + } + + /* alignment */ + p = tcopy(a->n_left); + if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) { + p = buildtree(PLUS, p, bcon(7)); + p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap); + } + + /* create a copy to a temp node */ + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(q); + p = buildtree(ASSIGN, q, p); + + q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap); + q = buildtree(PLUS, q, bcon(sz)); + q = buildtree(ASSIGN, a->n_left, q); + + q = buildtree(COMOP, p, q); + + nfree(a->n_right); + nfree(a); + + p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap); + p = buildtree(UMUL, p, NIL); + p = buildtree(COMOP, q, p); + + return p; + +bad: + uerror("bad argument to __builtin_va_arg"); + return bcon(0); +} + +NODE * +mips_builtin_va_end(const struct bitable *bt, NODE *a) +{ + tfree(a); + return bcon(0); +} + +NODE * +mips_builtin_va_copy(const struct bitable *bt, NODE *a) +{ + NODE *f; + + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM) + goto bad; + f = buildtree(ASSIGN, a->n_left, a->n_right); + nfree(a); + return f; + +bad: + uerror("bad argument to __buildtin_va_copy"); + return bcon(0); +} + +static int constructor; +static int destructor; + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + + if (strcmp(str, "tls") == 0) { + uerror("thread-local storage not supported for this target"); + return 1; + } + if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { + constructor = 1; + return 1; + } + if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { + destructor = 1; + return 1; + } + + return 0; +} + +/* + * Called when a identifier has been declared, to give target last word. + */ +void +fixdef(struct symtab *sp) +{ + if ((constructor || destructor) && (sp->sclass != PARAM)) { + printf("\t.section .%ctors,\"aw\",@progbits\n", + constructor ? 'c' : 'd'); + printf("\t.p2align 2\n"); + printf("\t.long %s\n", exname(sp->sname)); + printf("\t.previous\n"); + constructor = destructor = 0; + } +} + +void +pass1_lastchance(struct interpass *ip) +{ +} diff --git a/lang/pcc/pcc/arch/mips/local2.c b/lang/pcc/pcc/arch/mips/local2.c new file mode 100644 index 000000000..f3c8d6f75 --- /dev/null +++ b/lang/pcc/pcc/arch/mips/local2.c @@ -0,0 +1,1339 @@ +/* $Id: local2.c,v 1.31 2016/01/06 16:11:24 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +#include +#include +#include +#include + +#include "pass1.h" +#include "pass2.h" + +#ifdef TARGET_BIG_ENDIAN +int bigendian = 1; +#else +int bigendian = 0; +#endif + +int nargregs = MIPS_O32_NARGREGS; + +static int argsiz(NODE *p); + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static int regoff[32]; +static TWORD ftype; + +/* + * calculate stack size and offsets + */ +static int +offcalc(struct interpass_prolog * ipp) +{ + int i, j, addto; + + addto = p2maxautooff; + + for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) { + if (i & 1) { + addto += SZINT / SZCHAR; + regoff[j] = addto; + } + } + + /* round to 8-byte boundary */ + addto += 7; + addto &= ~7; + + return addto; +} + +/* + * Print out the prolog assembler. + */ +void +prologue(struct interpass_prolog * ipp) +{ + int addto; + int i, j; + + ftype = ipp->ipp_type; + printf("\t.align 2\n"); + if (ipp->ipp_vis) + printf("\t.globl %s\n", ipp->ipp_name); + printf("\t.ent %s\n", ipp->ipp_name); + printf("%s:\n", ipp->ipp_name); + + addto = offcalc(ipp); + + /* emit PIC only if -fpic or -fPIC set */ + if (kflag > 0) { + printf("\t.frame %s,%d,%s\n", + rnames[FP], ARGINIT/SZCHAR, rnames[RA]); + printf("\t.set noreorder\n"); + printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n"); + printf("\t.set reorder\n"); + } + + printf("\t.frame %s,%d,%s\n", rnames[FP], ARGINIT/SZCHAR, rnames[RA]); + printf("\t.set noreorder\n"); + printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n"); + printf("\t.set reorder\n"); + + printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], ARGINIT/SZCHAR); + /* emit PIC only if -fpic or -fPIC set */ + if (kflag > 0) + printf("\t.cprestore 8\t# pseudo-op to store GOT ptr at 8(sp)\n"); + + printf("\tsw %s,4(%s)\n", rnames[RA], rnames[SP]); + printf("\tsw %s,(%s)\n", rnames[FP], rnames[SP]); + printf("\tmove %s,%s\n", rnames[FP], rnames[SP]); + +#ifdef notyet + /* profiling */ + if (pflag) { + printf("\t.set noat\n"); + printf("\tmove %s,%s\t# save current return address\n", + rnames[AT], rnames[RA]); + printf("\tsubu %s,%s,8\t# _mcount pops 2 words from stack\n", + rnames[SP], rnames[SP]); + printf("\tjal %s\n", exname("_mcount")); + printf("\tnop\n"); + printf("\t.set at\n"); + } +#endif + + if (addto) + printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], addto); + + for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) + if (i & 1) + printf("\tsw %s,-%d(%s) # save permanent\n", + rnames[j], regoff[j], rnames[FP]); + +} + +void +eoftn(struct interpass_prolog * ipp) +{ + int i, j; + + (void) offcalc(ipp); + + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + /* return from function code */ + for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) { + if (i & 1) + printf("\tlw %s,-%d(%s)\n\tnop\n", + rnames[j], regoff[j], rnames[FP]); + } + + printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[FP], ARGINIT/SZCHAR); + printf("\tlw %s,%d(%s)\n", rnames[RA], 4-ARGINIT/SZCHAR, rnames[SP]); + printf("\tlw %s,%d(%s)\n", rnames[FP], 0-ARGINIT/SZCHAR, rnames[SP]); + + printf("\tjr %s\n", rnames[RA]); + printf("\tnop\n"); + +#ifdef USE_GAS + printf("\t.end %s\n", ipp->ipp_name); + printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name); +#endif +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case EQ: + str = "beqz"; /* pseudo-op */ + break; + case NE: + str = "bnez"; /* pseudo-op */ + break; + case ULE: + case LE: + str = "blez"; + break; + case ULT: + case LT: + str = "bltz"; + break; + case UGE: + case GE: + str = "bgez"; + break; + case UGT: + case GT: + str = "bgtz"; + break; + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + + printf("%s%c", str, f); +} + +char * +rnames[] = { +#ifdef USE_GAS + /* gnu assembler */ + "$zero", "$at", "$2", "$3", "$4", "$5", "$6", "$7", + "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", + "$24", "$25", + "$kt0", "$kt1", "$gp", "$sp", "$fp", "$ra", + "$2!!$3!!", + "$4!!$5!!", "$5!!$6!!", "$6!!$7!!", "$7!!$8!!", + "$8!!$9!!", "$9!!$10!", "$10!$11!", "$11!$12!", + "$12!$13!", "$13!$14!", "$14!$15!", "$15!$24!", "$24!$25!", + "$16!$17!", "$17!$18!", "$18!$19!", "$19!$20!", + "$20!$21!", "$21!$22!", "$22!$23!", +#else + /* mips assembler */ + "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", + "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", + "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", + "$t8", "$t9", + "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", + "$v0!$v1!", + "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$t0!", + "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t4!", + "$t4!$t5!", "$t5!$t6!", "$t6!$t7!", "$t7!$t8!", "$t8!$t9!", + "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!", + "$s4!$s5!", "$s5!$s6!", "$s6!$s7!", +#endif + "$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", +}; + +char * +rnames_n32[] = { + /* mips assembler */ + "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", + "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3", + "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", + "$t8", "$t9", + "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", + "$v0!$v1!", + "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$a4!", + "$a4!$a5!", "$a5!$a6!", "$a6!$a7!", "$a7!$t0!", + "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t8!", "$t8!$t9!", + "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!", + "$s4!$s5!", "$s5!$s6!", "$s6!$s7!", + "$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", +}; + +int +tlen(NODE *p) +{ + switch (p->n_type) { + case CHAR: + case UCHAR: + return (1); + + case SHORT: + case USHORT: + return (SZSHORT / SZCHAR); + + case DOUBLE: + return (SZDOUBLE / SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return (SZINT / SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG / SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type) / SZCHAR; + } +} + + +/* + * Push a structure on stack as argument. + */ +static void +starg(NODE *p) +{ + int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + //assert(p->n_rval == A1); + printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], sz); + /* A0 = dest, A1 = src, A2 = len */ + printf("\tmove %s,%s\n", rnames[A0], rnames[SP]); + printf("\tli %s,%d\t# structure size\n", rnames[A2], sz); + printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); + printf("\tjal %s\t# structure copy\n", exname("memcpy")); + printf("\tnop\n"); + printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); +} + +/* + * Structure assignment. + */ +static void +stasg(NODE *p) +{ + assert(p->n_right->n_rval == A1); + /* A0 = dest, A1 = src, A2 = len */ + printf("\tli %s,%d\t# structure size\n", rnames[A2], + attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); + if (p->n_left->n_op == OREG) { + printf("\taddiu %s,%s," CONFMT "\t# dest address\n", + rnames[A0], rnames[p->n_left->n_rval], + getlval(p->n_left)); + } else if (p->n_left->n_op == NAME) { + printf("\tla %s,", rnames[A0]); + adrput(stdout, p->n_left); + printf("\n"); + } + printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); + printf("\tjal %s\t# structure copy\n", exname("memcpy")); + printf("\tnop\n"); + printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); +} + +static void +shiftop(NODE *p) +{ + NODE *r = p->n_right; + TWORD ty = p->n_type; + + if (p->n_op == LS && r->n_op == ICON && getlval(r) < 32) { + expand(p, INBREG, "\tsrl A1,AL,"); + printf(CONFMT "\t# 64-bit left-shift\n", 32 - getlval(r)); + expand(p, INBREG, "\tsll U1,UL,AR\n"); + expand(p, INBREG, "\tor U1,U1,A1\n"); + expand(p, INBREG, "\tsll A1,AL,AR\n"); + } else if (p->n_op == LS && r->n_op == ICON && getlval(r) < 64) { + expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n"); + expand(p, INBREG, "\tsll U1,AL,"); + printf(CONFMT "\n", getlval(r) - 32); + } else if (p->n_op == LS && r->n_op == ICON) { + expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n"); + expand(p, INBREG, "\tli U1,0\n"); + } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 32) { + expand(p, INBREG, "\tsll U1,UL,"); + printf(CONFMT "\t# 64-bit right-shift\n", 32 - getlval(r)); + expand(p, INBREG, "\tsrl A1,AL,AR\n"); + expand(p, INBREG, "\tor A1,A1,U1\n"); + if (ty == LONGLONG) + expand(p, INBREG, "\tsra U1,UL,AR\n"); + else + expand(p, INBREG, "\tsrl U1,UL,AR\n"); + } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 64) { + if (ty == LONGLONG) { + expand(p, INBREG, "\tsra U1,UL,31\t# 64-bit right-shift\n"); + expand(p, INBREG, "\tsra A1,UL,"); + }else { + expand(p, INBREG, "\tli U1,0\t# 64-bit right-shift\n"); + expand(p, INBREG, "\tsrl A1,UL,"); + } + printf(CONFMT "\n", getlval(r) - 32); + } else if (p->n_op == LS && r->n_op == ICON) { + expand(p, INBREG, "\tli A1,0\t# 64-bit right-shift\n"); + expand(p, INBREG, "\tli U1,0\n"); + } else { + comperr("shiftop"); + } +} + +/* + * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines + */ +static void +fpemulop(NODE *p) +{ + NODE *l = p->n_left; + char *ch = NULL; + + if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3"; + else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3"; + else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3"; + + else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3"; + else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3"; + else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3"; + + else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3"; + else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3"; + else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3"; + + else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3"; + else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3"; + else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3"; + + else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2"; + else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2"; + else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2"; + + else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2"; + else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2"; + else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2"; + + else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2"; + else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2"; + else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2"; + + else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2"; + else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2"; + else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2"; + + else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2"; + else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2"; + else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2"; + + else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2"; + else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2"; + else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2"; + + else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2"; + else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2"; + else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2"; + + else if (p->n_op == SCONV && p->n_type == FLOAT) { + if (l->n_type == DOUBLE) ch = "truncdfsf2"; + else if (l->n_type == LDOUBLE) ch = "trunctfsf2"; + else if (l->n_type == ULONGLONG) ch = "floatdisf"; /**/ + else if (l->n_type == LONGLONG) ch = "floatdisf"; + else if (l->n_type == LONG) ch = "floatsisf"; + else if (l->n_type == ULONG) ch = "floatunsisf"; + else if (l->n_type == INT) ch = "floatsisf"; + else if (l->n_type == UNSIGNED) ch = "floatunsisf"; + } else if (p->n_op == SCONV && p->n_type == DOUBLE) { + if (l->n_type == FLOAT) ch = "extendsfdf2"; + else if (l->n_type == LDOUBLE) ch = "trunctfdf2"; + else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; + else if (l->n_type == LONGLONG) ch = "floatdidf"; + else if (l->n_type == LONG) ch = "floatsidf"; + else if (l->n_type == ULONG) ch = "floatunsidf"; + else if (l->n_type == INT) ch = "floatsidf"; + else if (l->n_type == UNSIGNED) ch = "floatunsidf"; + } else if (p->n_op == SCONV && p->n_type == LDOUBLE) { + if (l->n_type == FLOAT) ch = "extendsftf2"; + else if (l->n_type == DOUBLE) ch = "extenddfdf2"; + else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; + else if (l->n_type == LONGLONG) ch = "floatdidf"; + else if (l->n_type == LONG) ch = "floatsidf"; + else if (l->n_type == ULONG) ch = "floatunssidf"; + else if (l->n_type == INT) ch = "floatsidf"; + else if (l->n_type == UNSIGNED) ch = "floatunsidf"; + } else if (p->n_op == SCONV && p->n_type == ULONGLONG) { + if (l->n_type == FLOAT) ch = "fixunssfdi"; + else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; + else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; + } else if (p->n_op == SCONV && p->n_type == LONGLONG) { + if (l->n_type == FLOAT) ch = "fixsfdi"; + else if (l->n_type == DOUBLE) ch = "fixdfdi"; + else if (l->n_type == LDOUBLE) ch = "fixdfdi"; + } else if (p->n_op == SCONV && p->n_type == LONG) { + if (l->n_type == FLOAT) ch = "fixsfsi"; + else if (l->n_type == DOUBLE) ch = "fixdfsi"; + else if (l->n_type == LDOUBLE) ch = "fixdfsi"; + } else if (p->n_op == SCONV && p->n_type == ULONG) { + if (l->n_type == FLOAT) ch = "fixunssfsi"; + else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; + else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; + } else if (p->n_op == SCONV && p->n_type == INT) { + if (l->n_type == FLOAT) ch = "fixsfsi"; + else if (l->n_type == DOUBLE) ch = "fixdfsi"; + else if (l->n_type == LDOUBLE) ch = "fixdfsi"; + } else if (p->n_op == SCONV && p->n_type == UNSIGNED) { + if (l->n_type == FLOAT) ch = "fixunssfsi"; + else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; + else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; + } + + if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op); + + if (p->n_op == SCONV) { + if (l->n_type == FLOAT) { + printf("\tmfc1 %s,", rnames[A0]); + adrput(stdout, l); + printf("\n\tnop\n"); + } else if (l->n_type == DOUBLE || l->n_type == LDOUBLE) { + printf("\tmfc1 %s,", rnames[A1]); + upput(l, 0); + printf("\n\tnop\n"); + printf("\tmfc1 %s,", rnames[A0]); + adrput(stdout, l); + printf("\n\tnop\n"); + } + } else { + comperr("ZF: incomplete softfloat - put args in registers"); + } + + printf("\tjal __%s\t# softfloat operation\n", exname(ch)); + printf("\tnop\n"); + + if (p->n_op >= EQ && p->n_op <= GT) + printf("\tcmp %s,0\n", rnames[V0]); +} + +/* + * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines + */ +static void +emulop(NODE *p) +{ + char *ch = NULL; + + if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3"; + else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG || + DEUNSIGN(p->n_type) == INT)) + ch = "ashlsi3"; + + else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3"; + else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT)) + ch = "lshrsi3"; + + else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3"; + else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT)) + ch = "ashrsi3"; + + else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3"; + else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT)) + ch = "divsi3"; + + else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3"; + else if (p->n_op == DIV && (p->n_type == ULONG || + p->n_type == UNSIGNED)) + ch = "udivsi3"; + + else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3"; + else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT)) + ch = "modsi3"; + + else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3"; + else if (p->n_op == MOD && (p->n_type == ULONG || + p->n_type == UNSIGNED)) + ch = "umodsi3"; + + else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3"; + else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT)) + ch = "mulsi3"; + + else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2"; + else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2"; + + else ch = 0, comperr("ZE"); + printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); + printf("\tjal __%s\t# emulated operation\n", exname(ch)); + printf("\tnop\n"); + printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); +} + +/* + * Emit code to compare two longlong numbers. + */ +static void +twollcomp(NODE *p) +{ + int o = p->n_op; + int s = getlab2(); + int e = p->n_label; + int cb1, cb2; + + if (o >= ULE) + o -= (ULE-LE); + switch (o) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 4, cb2 += 4; + expand(p, 0, "\tsub A1,UL,UR\t# compare 64-bit values (upper)\n"); + if (cb1) { + printf("\t"); + hopcode(' ', cb1); + expand(p, 0, "A1"); + printf("," LABFMT "\n", s); + printf("\tnop\n"); + } + if (cb2) { + printf("\t"); + hopcode(' ', cb2); + expand(p, 0, "A1"); + printf("," LABFMT "\n", e); + printf("\tnop\n"); + } + expand(p, 0, "\tsub A1,AL,AR\t# (and lower)\n"); + printf("\t"); + hopcode(' ', o); + expand(p, 0, "A1"); + printf("," LABFMT "\n", e); + printf("\tnop\n"); + deflab(s); +} + +static void +fpcmpops(NODE *p) +{ + NODE *l = p->n_left; + + switch (p->n_op) { + case EQ: + if (l->n_type == FLOAT) + expand(p, 0, "\tc.eq.s AL,AR\n"); + else + expand(p, 0, "\tc.eq.d AL,AR\n"); + expand(p, 0, "\tnop\n\tbc1t LC\n"); + break; + case NE: + if (l->n_type == FLOAT) + expand(p, 0, "\tc.eq.s AL,AR\n"); + else + expand(p, 0, "\tc.eq.d AL,AR\n"); + expand(p, 0, "\tnop\n\tbc1f LC\n"); + break; + case LT: + if (l->n_type == FLOAT) + expand(p, 0, "\tc.lt.s AL,AR\n"); + else + expand(p, 0, "\tc.lt.d AL,AR\n"); + expand(p, 0, "\tnop\n\tbc1t LC\n"); + break; + case GE: + if (l->n_type == FLOAT) + expand(p, 0, "\tc.lt.s AL,AR\n"); + else + expand(p, 0, "\tc.lt.d AL,AR\n"); + expand(p, 0, "\tnop\n\tbc1f LC\n"); + break; + case LE: + if (l->n_type == FLOAT) + expand(p, 0, "\tc.le.s AL,AR\n"); + else + expand(p, 0, "\tc.le.d AL,AR\n"); + expand(p, 0, "\tnop\n\tbc1t LC\n"); + break; + case GT: + if (l->n_type == FLOAT) + expand(p, 0, "\tc.le.s AL,AR\n"); + else + expand(p, 0, "\tc.le.d AL,AR\n"); + expand(p, 0, "\tnop\n\tbc1f LC\n"); + break; + } + printf("\tnop\n\tnop\n"); +} + +void +zzzcode(NODE * p, int c) +{ + int sz; + + switch (c) { + + case 'C': /* remove arguments from stack after subroutine call */ + sz = p->n_qual > 16 ? p->n_qual : 16; + printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[SP], sz); + break; + + case 'D': /* long long comparison */ + twollcomp(p); + break; + + case 'E': /* emit emulated ops */ + emulop(p); + break; + + case 'F': /* emit emulate floating point ops */ + fpemulop(p); + break; + + case 'G': /* emit hardware floating-point compare op */ + fpcmpops(p); + break; + + case 'H': /* structure argument */ + starg(p); + break; + + case 'I': /* high part of init constant */ + if (p->n_name[0] != '\0') + comperr("named highword"); + printf(CONFMT, (getlval(p) >> 32) & 0xffffffff); + break; + + case 'O': /* 64-bit left and right shift operators */ + shiftop(p); + break; + + case 'Q': /* emit struct assign */ + stasg(p); + break; + + default: + comperr("zzzcode %c", c); + } +} + +/* ARGSUSED */ +int +rewfld(NODE * p) +{ + return (1); +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + CONSZ val; + + if (p->n_op == ASSIGN) + p = p->n_left; + switch (**cp) { + case 'S': + printf("%d", UPKFSZ(p->n_rval)); + break; + case 'H': + printf("%d", UPKFOFF(p->n_rval)); + break; + case 'M': + case 'N': + val = (CONSZ)1 << UPKFSZ(p->n_rval); + --val; + val <<= UPKFOFF(p->n_rval); + printf("0x%llx", (**cp == 'M' ? val : ~val) & 0xffffffff); + break; + default: + comperr("fldexpand"); + } + return 1; +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE * p) +{ + int o = p->n_op; + + if (o == OREG || o == REG || o == NAME) + return SRDIR; /* Direct match */ + if (o == UMUL && shumul(p->n_left, SOREG)) + return SROREG; /* Convert into oreg */ + return SRREG; /* put it into a register */ +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE * p) +{ + return 0; +#if 0 + int r; + + if (p->n_op == STARG) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return (0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return (0); + return (1); +#endif +} + +void +adrcon(CONSZ val) +{ + printf(CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + int val = getlval(p); + + switch (p->n_op) { + case ICON: + if (p->n_name[0] != '\0') { + fprintf(fp, "%s", p->n_name); + if (getlval(p)) + fprintf(fp, "+%d", val); + } else + fprintf(fp, "%d", val); + return; + + default: + comperr("illegal conput"); + } +} + +/* ARGSUSED */ +void +insput(NODE * p) +{ + comperr("insput"); +} + +/* + * Print lower or upper name of 64-bit register. + */ +static void +print_reg64name(FILE *fp, int rval, int hi) +{ + int off = 4 * (hi != 0); + char *regname = rnames[rval]; + + fprintf(fp, "%c%c", + regname[off], + regname[off + 1]); + if (regname[off + 2] != '!') + fputc(regname[off + 2], fp); + if (regname[off + 3] != '!') + fputc(regname[off + 3], fp); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE * p, int size) +{ + + size /= SZCHAR; + switch (p->n_op) { + case REG: + if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) + print_reg64name(stdout, p->n_rval, 1); + else + printf("%s", rnames[p->n_rval]); + break; + + case NAME: + case OREG: + setlval(p, getlval(p) + size); + adrput(stdout, p); + setlval(p, getlval(p) - size); + break; + case ICON: + printf(CONFMT, getlval(p) >> 32); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE * io, NODE * p) +{ + /* output an address, with offsets, from p */ + + if (p->n_op == FLD) + p = p->n_left; + + switch (p->n_op) { + + case NAME: + if (p->n_name[0] != '\0') + fputs(p->n_name, io); + if (getlval(p) != 0) + fprintf(io, "+" CONFMT, getlval(p)); + return; + + case OREG: + if (getlval(p)) + fprintf(io, "%d", (int) getlval(p)); + fprintf(io, "(%s)", rnames[p->n_rval]); + return; + + case ICON: + /* addressable value of the constant */ + conput(io, p); + return; + + case REG: + if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) + print_reg64name(io, p->n_rval, 0); + else + fputs(rnames[p->n_rval], io); + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ +} + +void +myreader(struct interpass * ipole) +{ +} + +#if 0 +/* + * Calculate the stack size for arguments + */ +static int stacksize; + +static void +calcstacksize(NODE *p, void *arg) +{ + int sz; + + printf("op=%d\n", p->n_op); + + if (p->n_op != CALL && p->n_op != STCALL) + return; + + sz = argsiz(p->n_right); + if (sz > stacksize) + stacksize = sz; + +#ifdef PCC_DEBUG + if (x2debug) + printf("stacksize: %d\n", stacksize); +#endif +} +#endif + +/* + * If we're big endian, then all OREG loads of a type + * larger than the destination, must have the + * offset changed to point to the correct bytes in memory. + */ +static void +offchg(NODE *p, void *arg) +{ + NODE *l; + + if (p->n_op != SCONV) + return; + + l = p->n_left; + + if (l->n_op != OREG) + return; + + switch (l->n_type) { + case SHORT: + case USHORT: + if (DEUNSIGN(p->n_type) == CHAR) + setlval(l, getlval(l) + 1); + break; + case LONG: + case ULONG: + case INT: + case UNSIGNED: + if (DEUNSIGN(p->n_type) == CHAR) + setlval(l, getlval(l + 3)); + else if (DEUNSIGN(p->n_type) == SHORT) + setlval(l, getlval(l + 2)); + break; + case LONGLONG: + case ULONGLONG: + if (DEUNSIGN(p->n_type) == CHAR) + setlval(l, getlval(l + 7)); + else if (DEUNSIGN(p->n_type) == SHORT) + setlval(l, getlval(l + 6)); + else if (DEUNSIGN(p->n_type) == INT || + DEUNSIGN(p->n_type) == LONG) + setlval(l, getlval(l + 4)); + break; + default: + comperr("offchg: unknown type"); + break; + } +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE * p, void *arg) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR | SHORT) || p->n_type == (PTR | USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE * p) +{ + walkf(p, pconv2, 0); +} + +void +myoptim(struct interpass * ipole) +{ + struct interpass *ip; + +#ifdef PCC_DEBUG + if (x2debug) + printf("myoptim:\n"); +#endif + +#if 0 + stacksize = 0; +#endif + + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + if (bigendian) + walkf(ip->ip_node, offchg, 0); +#if 0 + walkf(ip->ip_node, calcstacksize, 0); +#endif + } +} + +/* + * Move data between registers. While basic registers aren't a problem, + * we have to handle the special case of overlapping composite registers. + */ +void +rmove(int s, int d, TWORD t) +{ + switch (t) { + case LONGLONG: + case ULONGLONG: + if (s == d+1) { + /* dh = sl, copy low word first */ + printf("\tmove "); + print_reg64name(stdout, d, 0); + printf(","); + print_reg64name(stdout, s, 0); + printf("\t# 64-bit rmove\n"); + printf("\tmove "); + print_reg64name(stdout, d, 1); + printf(","); + print_reg64name(stdout, s, 1); + printf("\n"); + } else { + /* copy high word first */ + printf("\tmove "); + print_reg64name(stdout, d, 1); + printf(","); + print_reg64name(stdout, s, 1); + printf(" # 64-bit rmove\n"); + printf("\tmove "); + print_reg64name(stdout, d, 0); + printf(","); + print_reg64name(stdout, s, 0); + printf("\n"); + } + break; + case FLOAT: + case DOUBLE: + case LDOUBLE: + if (t == FLOAT) + printf("\tmov.s "); + else + printf("\tmov.d "); + print_reg64name(stdout, d, 0); + printf(","); + print_reg64name(stdout, s, 0); + printf("\t# float/double rmove\n"); + break; + default: + printf("\tmove %s,%s\t# default rmove\n", rnames[d], rnames[s]); + } +} + + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + * + * On MIPS, we have: + * + * 32 32-bit registers (8 reserved) + * 26 64-bit pseudo registers (1 unavailable) + * 16 floating-point register pairs + */ +int +COLORMAP(int c, int *r) +{ + int num = 0; + + switch (c) { + case CLASSA: + num += r[CLASSA]; + num += 2*r[CLASSB]; + return num < 24; + case CLASSB: + num += 2*r[CLASSB]; + num += r[CLASSA]; + return num < 25; + case CLASSC: + num += r[CLASSC]; + return num < 6; + } + comperr("COLORMAP"); + return 0; /* XXX gcc */ +} + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t == LONGLONG || t == ULONGLONG) + return CLASSB; + if (t >= FLOAT && t <= LDOUBLE) + return CLASSC; + return CLASSA; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + int sz; + +#ifdef PCC_DEBUG + if (x2debug) + printf("lastcall:\n"); +#endif + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + + sz = argsiz(p->n_right); + + if ((sz > 4*nargregs) && (sz & 7) != 0) { + printf("\tsubu %s,%s,4\t# align stack\n", + rnames[SP], rnames[SP]); + sz += 4; + assert((sz & 7) == 0); + } + + p->n_qual = sz; /* XXX */ +} + +static int +argsiz(NODE *p) +{ + TWORD t; + int size = 0; + int sz = 0; + + if (p->n_op == CM) { + size = argsiz(p->n_left); + p = p->n_right; + } + + t = p->n_type; + if (t < LONGLONG || t > BTMASK) + sz = 4; + else if (DEUNSIGN(t) == LONGLONG) + sz = 8; + else if (t == DOUBLE || t == LDOUBLE) + sz = 8; + else if (t == FLOAT) + sz = 4; + else if (t == STRTY || t == UNIONTY) + sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + + if (p->n_type == STRTY || p->n_type == UNIONTY) { + return (size + sz); + } + + /* alignment */ + if (sz == 8 && (size & 7) != 0) + sz += 4; + +// printf("size=%d, sz=%d -> %d\n", size, sz, size + sz); + return (size + sz); +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + int o = p->n_op; + + if (o != ICON || p->n_name[0] != 0) + return SRNOPE; + + switch(shape) { + case SPCON: + if ((getlval(p) & ~0xffff) == 0) + return SRDIR; + break; + } + + return SRNOPE; +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ + if (strcasecmp(str, "big-endian") == 0) { + bigendian = 1; + } else if (strcasecmp(str, "little-endian") == 0) { + bigendian = 0; + } else { + fprintf(stderr, "unknown m option '%s'\n", str); + exit(1); + } + +#if 0 + else if (strcasecmp(str, "ips2")) { + } else if (strcasecmp(str, "ips2")) { + } else if (strcasecmp(str, "ips3")) { + } else if (strcasecmp(str, "ips4")) { + } else if (strcasecmp(str, "hard-float")) { + } else if (strcasecmp(str, "soft-float")) { + } else if (strcasecmp(str, "abi=32")) { + nargregs = MIPS_O32_NARGREGS; + } else if (strcasecmp(str, "abi=n32")) { + nargregs = MIPS_N32_NARGREGS; + } else if (strcasecmp(str, "abi=64")) { + nargregs = MIPS_N32_NARGREGS; + } +#endif +} +/* + * Do something target-dependent for xasm arguments. + * Supposed to find target-specific constraints and rewrite them. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + return 0; +} diff --git a/lang/pcc/pcc/arch/mips/macdefs.h b/lang/pcc/pcc/arch/mips/macdefs.h new file mode 100644 index 000000000..7bf9577c6 --- /dev/null +++ b/lang/pcc/pcc/arch/mips/macdefs.h @@ -0,0 +1,359 @@ +/* $Id: macdefs.h,v 1.23 2016/03/05 15:53:04 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +/* + * Machine-dependent defines for both passes. + */ + +#if defined(os_netbsd) || defined(os_litebsd) +#define USE_GAS +#endif + +/* + * Convert (multi-)character constant to integer. + * Assume: If only one value; store at left side (char size), otherwise + * treat it as an integer. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +#define ARGINIT (16*8) /* # bits above fp where arguments start */ +#define AUTOINIT (0) /* # bits below fp where automatics start */ + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZBOOL 32 +#define SZINT 32 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 64 +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 64 +#define SZPOINT(t) 32 + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALBOOL 32 +#define ALINT 32 +#define ALFLOAT 32 +#define ALDOUBLE 64 +#define ALLDOUBLE 64 +#define ALLONG 32 +#define ALLONGLONG 64 +#define ALSHORT 16 +#define ALPOINT 32 +#define ALSTRUCT 64 +#define ALSTACK 32 + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT (-0x7fffffff-1) +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffffU +#define MIN_LONG MIN_INT +#define MAX_LONG MAX_INT +#define MAX_ULONG MAX_UNSIGNED +#define MIN_LONGLONG (-0x7fffffffffffffffLL-1) +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +#undef CHAR_UNSIGNED +#define BOOL_TYPE INT + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#ifdef USE_GAS +#define LABFMT "$L%d" /* format for printing labels */ +#define STABLBL "$LL%d" /* format for stab (debugging) labels */ +#else +#define LABFMT "L%d" /* format for printing labels */ +#define STABLBL "LL%d" /* format for stab (debugging) labels */ +#endif + +#define BACKAUTO /* stack grows negatively for automatics */ +#define BACKTEMP /* stack grows negatively for temporaries */ + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_LE +#define MYALIGN + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&03) + +#define szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \ + DEUNSIGN(t) == LONGLONG) ? 2 : 1) + +/* + * Register names. These must match rnames[] and rstatus[] in local2.c. + */ +#define ZERO 0 +#define AT 1 +#define V0 2 +#define V1 3 +#define A0 4 +#define A1 5 +#define A2 6 +#define A3 7 +#define A4 8 +#define A5 9 +#define A6 10 +#define A7 11 +#if defined(MIPS_N32) || defined(MIPS_N64) +#define T0 12 +#define T1 13 +#define T2 14 +#define T3 15 +#else +#define T0 8 +#define T1 9 +#define T2 10 +#define T3 11 +#endif +#define T4 12 +#define T5 13 +#define T6 14 +#define T7 15 +#define S0 16 +#define S1 17 +#define S2 18 +#define S3 19 +#define S4 20 +#define S5 21 +#define S6 22 +#define S7 23 +#define T8 24 +#define T9 25 +#define K0 26 +#define K1 27 +#define GP 28 +#define SP 29 +#define FP 30 +#define RA 31 + +#define V0V1 32 +#define A0A1 33 +#define A1A2 34 +#define A2A3 35 + +/* we just use o32 naming here, but it works ok for n32/n64 */ +#define A3T0 36 +#define T0T1 37 +#define T1T2 38 +#define T2T3 39 +#define T3T4 40 +#define T4T5 41 +#define T5T6 42 +#define T6T7 43 +#define T7T8 44 + +#define T8T9 45 +#define S0S1 46 +#define S1S2 47 +#define S2S3 48 +#define S3S4 49 +#define S4S5 50 +#define S5S6 51 +#define S6S7 52 + +#define F0 53 +#define F2 54 +#define F4 55 +#define F6 56 +#define F8 57 +#define F10 58 +#define F12 59 +#define F14 60 +#define F16 61 +#define F18 62 +#define F20 63 +/* and the rest for later */ +#define F22 64 +#define F24 65 +#define F26 66 +#define F28 67 +#define F30 68 + +#define MAXREGS 64 +#define NUMCLASS 3 + +#define RETREG(x) (DEUNSIGN(x) == LONGLONG ? V0V1 : \ + (x) == DOUBLE || (x) == LDOUBLE || (x) == FLOAT ? \ + F0 : V0) +#define FPREG FP /* frame pointer */ + +#define MIPS_N32_NARGREGS 8 +#define MIPS_O32_NARGREGS 4 + +#define RSTATUS \ + 0, 0, \ + SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, \ + 0, 0, \ + 0, 0, 0, 0, \ + \ + SBREG|TEMPREG, \ + SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ + SBREG|TEMPREG, \ + SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ + SBREG|TEMPREG, SBREG|TEMPREG, \ + SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ + SBREG, SBREG, SBREG, SBREG, \ + SBREG, SBREG, SBREG, \ + SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, \ + +#define ROVERLAP \ + { -1 }, /* $zero */ \ + { -1 }, /* $at */ \ + { V0V1, -1 }, /* $v0 */ \ + { V0V1, -1 }, /* $v1 */ \ + { A0A1, -1 }, /* $a0 */ \ + { A0A1, A1A2, -1 }, /* $a1 */ \ + { A1A2, A2A3, -1 }, /* $a2 */ \ + { A2A3, A3T0, -1 }, /* $a3 */ \ + { A3T0, T0T1, -1 }, /* $t0 */ \ + { T0T1, T1T2, -1 }, /* $t1 */ \ + { T1T2, T2T3, -1 }, /* $t2 */ \ + { T2T3, T3T4, -1 }, /* $t3 */ \ + { T3T4, T4T5, -1 }, /* $t4 */ \ + { T4T5, T5T6, -1 }, /* $t5 */ \ + { T6T7, T7T8, -1 }, /* $t6 */ \ + { T7T8, T8T9, -1 }, /* $t7 */ \ + \ + { S0S1, -1 }, /* $s0 */ \ + { S0S1, S1S2, -1 }, /* $s1 */ \ + { S1S2, S2S3, -1 }, /* $s2 */ \ + { S2S3, S3S4, -1 }, /* $s3 */ \ + { S3S4, S4S5, -1 }, /* $s4 */ \ + { S4S5, S5S6, -1 }, /* $s5 */ \ + { S5S6, S6S7, -1 }, /* $s6 */ \ + { S6S7, -1 }, /* $s7 */ \ + \ + { T7T8, T8T9, -1 }, /* $t8 */ \ + { T8T9, -1 }, /* $t9 */ \ + \ + { -1 }, /* $k0 */ \ + { -1 }, /* $k1 */ \ + { -1 }, /* $gp */ \ + { -1 }, /* $sp */ \ + { -1 }, /* $fp */ \ + { -1 }, /* $ra */ \ + \ + { V0, V1, -1 }, /* $v0:$v1 */ \ + \ + { A0, A1, A1A2, -1 }, /* $a0:$a1 */ \ + { A1, A2, A0A1, A2A3, -1 }, /* $a1:$a2 */ \ + { A2, A3, A1A2, A3T0, -1 }, /* $a2:$a3 */ \ + { A3, T0, A2A3, T0T1, -1 }, /* $a3:$t0 */ \ + { T0, T1, A3T0, T1T2, -1 }, /* $t0:$t1 */ \ + { T1, T2, T0T1, T2T3, -1 }, /* $t1:$t2 */ \ + { T2, T3, T1T2, T3T4, -1 }, /* $t2:$t3 */ \ + { T3, T4, T2T3, T4T5, -1 }, /* $t3:$t4 */ \ + { T4, T5, T3T4, T5T6, -1 }, /* $t4:$t5 */ \ + { T5, T6, T4T5, T6T7, -1 }, /* $t5:$t6 */ \ + { T6, T7, T5T6, T7T8, -1 }, /* $t6:$t7 */ \ + { T7, T8, T6T7, T8T9, -1 }, /* $t7:$t8 */ \ + { T8, T9, T7T8, -1 }, /* $t8:$t9 */ \ + \ + { S0, S1, S1S2, -1 }, /* $s0:$s1 */ \ + { S1, S2, S0S1, S2S3, -1 }, \ + { S2, S3, S1S2, S3S4, -1 }, \ + { S3, S4, S2S3, S4S5, -1 }, \ + { S4, S5, S3S4, S5S6, -1 }, \ + { S5, S6, S4S5, S6S7, -1 }, \ + { S6, S7, S5S6, -1 }, \ + \ + { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, \ + +#define GCLASS(x) (x < 32 ? CLASSA : (x < 52 ? CLASSB : CLASSC)) +#define PCLASS(p) (1 << gclass((p)->n_type)) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ + +int COLORMAP(int c, int *r); + +extern int bigendian; +extern int nargregs; + +#define SPCON (MAXSPECIAL+1) /* positive constant */ + +#define TARGET_STDARGS +#define TARGET_BUILTINS \ + { "__builtin_stdarg_start", mips_builtin_stdarg_start, \ + 0, 2, 0, VOID }, \ + { "__builtin_va_start", mips_builtin_stdarg_start, \ + 0, 2, 0, VOID }, \ + { "__builtin_va_arg", mips_builtin_va_arg, BTNORVAL|BTNOPROTO, \ + 2, 0, 0 }, \ + { "__builtin_va_end", mips_builtin_va_end, 0, 1, 0, VOID }, \ + { "__builtin_va_copy", mips_builtin_va_copy, 0, 2, 0, VOID }, + +#ifdef LANG_CXX +#define P1ND struct node +#else +#define P1ND struct p1node +#endif +struct node; +struct bitable; +P1ND *mips_builtin_stdarg_start(const struct bitable *, P1ND *a); +P1ND *mips_builtin_va_arg(const struct bitable *, P1ND *a); +P1ND *mips_builtin_va_end(const struct bitable *, P1ND *a); +P1ND *mips_builtin_va_copy(const struct bitable *, P1ND *a); +#undef P1ND diff --git a/lang/pcc/pcc/arch/mips/order.c b/lang/pcc/pcc/arch/mips/order.c new file mode 100644 index 000000000..24f635126 --- /dev/null +++ b/lang/pcc/pcc/arch/mips/order.c @@ -0,0 +1,259 @@ +/* $Id: order.c,v 1.12 2008/11/30 21:00:24 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + */ + +#include "pass2.h" + +/* + * is it legal to make an OREG or NAME entry which has an offset of off, + * (from a register of r), if the resulting thing had type t + */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + /* + * although the hardware doesn't permit offsets greater + * than +/- 32K, the assembler fixes it for us. + */ + return 0; /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + */ +void +offstar(NODE * p, int shape) +{ + if (x2debug) + printf("offstar(%p)\n", p); + + if (p->n_op == PLUS || p->n_op == MINUS) { + if (p->n_right->n_op == ICON) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + } + (void)geninsn(p, INAREG); +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + */ +void +myormake(NODE * q) +{ + if (x2debug) + printf("myormake(%p)\n", q); +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ + if (x2debug) + printf("shumul(%p)\n", p); + + /* Always turn it into OREG */ + if (shape & SOREG) + return SROREG; + return SRNOPE; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE * p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE * p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return (0); +} + +/* setup for unary operator */ +int +setuni(NODE * p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + * - left is the register that left node wants. + * - right is the register that right node wants. + * - res is in which register the result will end up. + * - mask is registers that will be clobbered. + */ +struct rspecial * +nspecial(struct optab * q) +{ + switch (q->op) { + + case SCONV: + if (q->lshape == SBREG && q->rshape == SCREG) { + static struct rspecial s[] = { + { NLEFT, A0A1 }, + { NRES, F0 }, + { 0 } + }; + return s; + } else if (q->lshape == SCREG && q->rshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, F0 }, + { NRES, A0A1 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG && q->rshape == SCREG) { + static struct rspecial s[] = { + { NLEFT, A0 }, + { NRES, F0 }, + { 0 } + }; + return s; + } + break; + + case MOD: + case DIV: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, A0A1 }, + { NRIGHT, A2A3 }, + { NRES, V0V1 }, + { 0 }, + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, A0 }, + { NRIGHT, A1 }, + { NRES, V0 }, + { 0 }, + }; + return s; + } + + case RS: + case LS: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, A0A1 }, + { NRIGHT, A2 }, + { NRES, V0V1 }, + { 0 }, + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, A0 }, + { NRIGHT, A1 }, + { NRES, V0 }, + { 0 }, + }; + return s; + } + break; + + case STARG: + { + static struct rspecial s[] = { + { NEVER, A0 }, + { NLEFT, A1 }, + { NEVER, A2 }, + { 0 } + }; + return s; + } + + case STASG: + { + static struct rspecial s[] = { + { NEVER, A0 }, + { NRIGHT, A1 }, + { NEVER, A2 }, + { 0 } + }; + return s; + } + } + + comperr("nspecial entry %d: %s", q - table, q->cstring); + + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE * p) +{ + return 0; /* nothing differs */ +} + +/* + * Set registers "live" at function calls (like arguments in registers). + * This is for liveness analysis of registers. + */ +int * +livecall(NODE *p) +{ + static int r[1] = { -1 }; /* Terminate with -1 */ + + return &r[0]; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/mips/table.c b/lang/pcc/pcc/arch/mips/table.c new file mode 100644 index 000000000..94c55b695 --- /dev/null +++ b/lang/pcc/pcc/arch/mips/table.c @@ -0,0 +1,1326 @@ +/* $Id: table.c,v 1.18 2016/01/05 12:23:22 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and + * Simon Olsson (simols-1@student.ltu.se) 2005. + * + * It appears that the target machine was big endian. The original + * code contained many endian aspects which are now handled in + * machine-independent code. + * + * On MIPS, the assembler does an amazing amount of work for us. + * We don't have to worry about PIC, nor about finding the address + * of SNAMES. Whenever possible, we defer the work to the assembler. + */ + +#include "pass2.h" + +#define TUWORD TUNSIGNED|TULONG +#define TSWORD TINT|TLONG +#define TWORD TUWORD|TSWORD + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are usually not necessary */ +{ PCONV, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + " # convert between word and pointer", }, + +/* + * Conversions of integral types (register-register) + * + * For each deunsigned type, they look something like this: + * + * signed -> bigger signed - nothing to do + * unsigned -> bigger - nothing to do + * + * signed -> bigger unsigned - clear the top bits (of source type) + * signed -> smaller signed - sign-extend the bits (to dest type) + * signed -> smaller unsigned - clear the top bits (of dest type) + * unsigned -> smaller signed - sign-extend top bits (to dest type) + * unsigned -> smaller unsigned - clear the top bits (of dest type) + * + */ + +/* convert between int and ptr */ +{ SCONV, INAREG, + SAREG, TPOINT|TWORD, + SAREG, TWORD|TPOINT, + 0, RLEFT, + "", }, + +/* convert between LL and uLL */ +{ SCONV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TULONGLONG|TLONGLONG, + 0, RLEFT, + "", }, + +/* (u)char to (u)char/(u)short/(u)int */ +{ SCONV, INAREG, + SAREG, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR|TWORD|TSHORT|TUSHORT, + 0, RLEFT, + "", }, + +/* (u)short to (u)int */ +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG, TWORD|TSHORT|TUSHORT, + 0, RLEFT, + "", }, + +/* (u)int to (u)int */ +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TWORD, + 0, RLEFT, + "", }, + +/* (u)int/(u)short to char */ +{ SCONV, INAREG, + SAREG, TWORD|TSHORT|TUSHORT, + SAREG, TCHAR, + NAREG|NASL, RESC1, + " sll A1,AL,24\n" + " sra A1,A1,24\n", }, + +/* (u)int/(u)short to uchar */ +{ SCONV, INAREG, + SAREG, TWORD|TSHORT|TUSHORT, + SAREG, TUCHAR, + NAREG|NASL, RESC1, + " andi A1,AL,255\n", }, + +/* (u)int to short */ +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TSHORT, + NAREG|NASL, RESC1, + " sll A1,AL,16\n" + " sra A1,A1,16\n", }, + +/* (u)int to ushort */ +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TUSHORT, + NAREG|NASL, RESC1, + " andi A1,AL,65535\n", }, + +/* longlong casts below */ +{ SCONV, INBREG, + SAREG, TSWORD|TSHORT|TCHAR, + SBREG, TLONGLONG, + NBREG, RESC1, + " move A1,AL # convert int/short/char to longlong\n" + " sra U1,AL,31\n", }, + +{ SCONV, INBREG, + SAREG, TSWORD|TSHORT|TCHAR, + SBREG, TULONGLONG, + NBREG, RESC1, + " move A1,AL # convert int/short/char to ulonglong\n" + " move U1,$zero\n", }, + +{ SCONV, INBREG, + SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, + SBREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " move A1,AL # convert (u)int/(u)short/(u)char to ulonglong\n" + " move U1,$zero\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TWORD, + NAREG, RESC1, + " move A1,AL # convert (u)longlong to int\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TSHORT, + NAREG, RESC1, + " sll A1,AL,16 # convert (u)longlong to short\n" + " sra A1,A1,16\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TCHAR, + NAREG, RESC1, + " sll A1,AL,24 # convert (u)longlong to char\n" + " sra A1,A1,24\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TUSHORT, + NAREG, RESC1, + " andi A1,AL,65535 # convert (u)longlong to ushort\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TUCHAR, + NAREG, RESC1, + " andi A1,AL,255 # convert (u)longlong to uchar\n", }, + +{ SCONV, INCREG, + SCREG, TFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " cvt.d.s A1,AL # convert float to (l)double\n", }, + +{ SCONV, INCREG, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TFLOAT, + NCREG, RESC1, + " cvt.s.d A1,AL # convert (l)double to float\n", }, + +{ SCONV, INCREG, + SAREG, TWORD, + SCREG, TFLOAT, + NCREG, RESC1, + " mtc1 AL,A1 # convert (u)int to float\n" + " nop\n" + " cvt.s.w A1,A1\n", }, + +{ SCONV, INCREG, + SOREG, TWORD, + SCREG, TFLOAT, + NCREG, RESC1, + " l.s A1,AL # convert (u)int to float\n" + " nop\n" + " cvt.s.w A1,A1\n", }, + +{ SCONV, INCREG, + SAREG, TWORD, + SCREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " mtc1 AL,A1 # convert (u)int to (l)double\n" + " nop\n" + " cvt.d.w A1,A1\n", }, + +{ SCONV, INCREG, + SOREG, TWORD, + SCREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " l.d A1,AL # convert (u)int to (l)double\n" + " nop\n" + " cvt.d.w A1,A1\n", }, + +{ SCONV, INAREG, + SCREG, TFLOAT, + SAREG, TWORD, + NCREG|NAREG, RESC1, + " cvt.w.s A2,AL # convert float to (u)int\n" + " mfc1 A1,A2\n" + " nop\n", }, + +{ SCONV, FOREFF, + SCREG, TFLOAT, + SOREG, TWORD, + NCREG, RDEST, + " cvt.w.s A1,AL # convert float to (u)int\n" + " s.s A1,AR\n" + " nop\n", }, + +{ SCONV, INAREG, + SCREG, TDOUBLE|TLDOUBLE, + SAREG, TWORD, + NCREG|NAREG, RESC1, + " cvt.w.d A2,AL # convert (l)double to (u)int\n" + " mfc1 A1,A2\n" + " nop\n", }, + +{ SCONV, INCREG, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + " # convert between double and ldouble\n", }, + +{ SCONV, INCREG, + SBREG, TLONGLONG|TULONGLONG, + SCREG, TFLOAT, + NSPECIAL|NCREG, RESC1, + "ZF", }, + +{ SCONV, INCREG, + SBREG, TLONGLONG|TULONGLONG, + SCREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NCREG, RESC1, + "ZF", }, + +{ SCONV, INBREG, + SCREG, TDOUBLE|TLDOUBLE, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INBREG, + SCREG, TFLOAT, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +/* + * Multiplication and division + */ + +{ MUL, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + NAREG|NASR|NASL, RESC1, + " multu AL,AR # unsigned multiply\n" + " nop\n" + " nop\n" + " mflo A1\n" }, + +/* this previous will match on unsigned/unsigned multiplication first */ +{ MUL, INAREG, + SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, + SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, + NAREG|NASR|NASL, RESC1, + " mult AL,AR # signed multiply\n" + " nop\n" + " nop\n" + " mflo A1\n", }, + +{ MUL, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 2*NBREG, RESC1, + " multu AL,AR\n" + " mfhi U1\n" + " mflo A1\n" + " mult AL,UR\n" + " mflo A2\n" + " nop\n" + " nop\n" + " addu A2,U1,A2\n" + " mult UL,AR\n" + " mflo U2\n" + " nop\n" + " nop\n" + " addu U1,A2,U2\n", }, + +{ MUL, INCREG, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " mul.s A1,AL,AR # floating-point multiply\n", }, + +{ MUL, INCREG, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " mul.d A1,AL,AR # double-floating-point multiply\n", }, + +{ DIV, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + NAREG|NASR|NASL, RESC1, + " divu AL,AR # unsigned division\n" + " mflo A1\n" + " nop\n" + " nop\n", }, + +/* the previous rule will match unsigned/unsigned first */ +{ DIV, INAREG, + SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, + SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, + NAREG|NASR|NASL, RESC1, + " div AL,AR # signed division\n" + " mflo A1\n" + " nop\n" + " nop\n", }, + +{ DIV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ DIV, INCREG, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " div.s A1,AL,AR # floating-point division\n", }, + +{ DIV, INCREG, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " div.d A1,AL,AR # double-floating-point division\n", }, + +{ MOD, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + NAREG, RESC1, + " divu AL,AR # signed modulo\n" + " mfhi A1\n" + " nop\n" + " nop\n", }, + +/* the previous rule will match unsigned%unsigned first */ +{ MOD, INAREG, + SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, + SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, + NAREG, RESC1, + " div AL,AR # signed modulo\n" + " mfhi A1\n" + " nop\n" + " nop\n", }, + +{ MOD, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +/* + * Templates for unsigned values needs to come before OPSIMP + */ + +{ PLUS, INBREG, + SBREG, TULONGLONG|TLONGLONG, + SBREG, TULONGLONG|TLONGLONG, + 2*NBREG, RESC1, + " addu A1,AL,AR # 64-bit addition\n" + " sltu A2,A1,AR\n" + " addu U1,UL,UR\n" + " addu U1,U1,A2\n", }, + +{ PLUS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SSCON, TANY, + NAREG|NASL, RESC1, + " addi A1,AL,AR\n", }, + +{ PLUS, INAREG, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SSCON, TANY, + NAREG|NASL, RESC1, + " addiu A1,AL,AR\n", }, + +{ PLUS, INAREG, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TUSHORT|TUCHAR, + NAREG|NASL, RESC1, + " addu A1,AL,AR\n", }, + +{ PLUS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NAREG|NASL, RESC1, + " add A1,AL,AR\n", }, + +{ PLUS, INCREG, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG|NCSL, RESC1, + " add.s A1,AL,AR\n", }, + +{ PLUS, INCREG, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG|NCSL, RESC1, + " add.d A1,AL,AR\n", }, + +{ MINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 2*NBREG, RESC1, + " sltu A2,AL,AR # 64-bit subtraction\n" + " subu A1,AL,AR\n" + " subu U1,UL,UR\n" + " subu U1,U1,A2\n", }, + +{ MINUS, INAREG, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SSCON, TANY, + NAREG|NASL, RESC1, + " subu A1,AL,AR\n", }, + +{ MINUS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SSCON, TANY, + NAREG|NASL, RESC1, + " sub A1,AL,AR\n", }, + +{ MINUS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + NAREG|NASL, RESC1, + " sub A1,AL,AR\n", }, + +{ MINUS, INCREG, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG|NCSL, RESC1, + " sub.s A1,AL,AR\n", }, + +{ MINUS, INCREG, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG|NCSL, RESC1, + " sub.d A1,AL,AR\n", }, + +{ UMINUS, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TANY, + NAREG|NASL, RESC1, + " neg A1,AL\n", }, + +{ UMINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SANY, TANY, + NBREG|NAREG|NBSL, RESC2, + " subu A1,$zero,AL\n" + " subu U1,$zero,UL\n" + " sltu A2,$zero,A1\n" + " subu U1,U1,A2\n", }, + +{ UMINUS, INCREG, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG|NCSL, RESC1, + " neg.s A1,AL\n", }, + +{ UMINUS, INCREG, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG|NCSL, RESC1, + " neg.d A1,AL\n", }, + +/* Simple 'op rd, rs, rt' or 'op rt, rs, imm' operations */ + +{ OPSIMP, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSR|NBSL, RESC1, + " O A1,AL,AR\n" + " O U1,UL,UR\n", }, + +{ OPSIMP, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, + NAREG|NASR|NASL, RESC1, + " O A1,AL,AR\n", }, + +{ OPSIMP, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, + SPCON, TANY, + NAREG|NASL, RESC1, + " Oi A1,AL,AR\n", }, + +/* + * Shift instructions + */ + +{ RS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " sra A1,AL,AR # shift right by constant\n", }, + +{ RS, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " srl A1,AL,AR # shift right by constant\n", }, + +{ LS, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " sll A1,AL,AR # shift left by constant\n", }, + +{ RS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " srav A1,AL,AR # shift right by register\n", }, + +{ RS, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " srlv A1,AL,AR # shift right by register\n", }, + +{ LS, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " sllv A1,AL,AR # shift left by register\n", }, + +{ RS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NBREG, RESC1, + "ZO", }, + +{ LS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NBREG, RESC1, + "ZO", }, + +{ RS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ LS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +/* + * Rule for unary one's complement + */ + +{ COMPL, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TANY, + NAREG|NASL, RESC1, + " nor A1,$zero,AL # complement\n", }, + +{ COMPL, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SANY, TANY, + NBREG|NBSL, RESC1, + " nor A1,$zero,AL # complement\n" + " nor U1,$zero,UL\n", }, + +/* + * The next rules takes care of assignments. "=". + */ + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " sw AR,AL # store (u)int/(u)long\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RDEST, + " sh AR,AL # store (u)short\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG|SNAME, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + 0, RDEST, + " sb AR,AL # store (u)char\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG|SNAME, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RDEST, + " sw UR,UL # store (u)longlong\n" + " nop\n" + " sw AR,AL\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RDEST, + " move UL,UR # register move\n" + " move AL,AR\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TANY, + SAREG, TANY, + 0, RDEST, + " move AL,AR # register move\n", }, + +{ ASSIGN, FOREFF|INCREG, + SCREG, TFLOAT, + SCREG, TFLOAT, + 0, RDEST, + " mov.s AL,AR # register move\n", }, + +{ ASSIGN, FOREFF|INCREG, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " mov.d AL,AR # register move\n", }, + +{ ASSIGN, FOREFF|INCREG, + SNAME|SOREG, TFLOAT, + SCREG, TFLOAT, + 0, RDEST, + " s.s AR,AL # store floating-point reg to oreg/sname\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INCREG, + SNAME|SOREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " s.d AR,AL # store double floating-point reg to oreg/sname\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SFLD, TANY, + SOREG|SNAME, TANY, + 3*NAREG, RDEST, + " lw A1,AR # bit-field assignment\n" + " li A3,M\n" + " lw A2,AL\n" + " sll A1,A1,H\n" + " and A1,A1,A3\n" + " nor A3,$zero,A3\n" + " and A2,A2,A3\n" + " or A2,A2,A1\n" + " sw A2,AL\n" + "F lw AD,AR\n" + "F nop\n" + "F sll AD,AD,32-S\n" + "F sra AD,AD,32-S\n", }, + +/* XXX we can optimise this away */ +{ ASSIGN, FOREFF|INAREG, + SFLD, TANY, + SCON, TANY, + 3*NAREG, RDEST, + " li A1,AR # bit-field assignment\n" + " lw A2,AL\n" + " li A3,M\n" + " sll A1,A1,H\n" + " and A1,A1,A3\n" + " nor A3,$zero,A3\n" + " and A2,A2,A3\n" + " or A2,A2,A1\n" + " sw A2,AL\n" + "F li AD,AR\n" + "F sll AD,AD,32-S\n" + "F sra AD,AD,32-S\n", }, + +{ ASSIGN, FOREFF|INAREG, + SFLD, TANY, + SAREG, TANY, + 3*NAREG, RDEST, + " move A1,AR # bit-field assignment\n" + " lw A2,AL\n" + " li A3,M\n" + " sll A1,A1,H\n" + " and A1,A1,A3\n" + " nor A3,$zero,A3\n" + " and A2,A2,A3\n" + " or A2,A2,A1\n" + " sw A2,AL\n" + "F move AR,AD\n" + "F sll AD,AD,32-S\n" + "F sra AD,AD,32-S\n", }, + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG, TPTRTO|TANY, + NSPECIAL, RDEST, + "ZQ", }, + +/* + * Compare instructions + */ + +{ EQ, FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, RESCC, + " beq AL,AR,LC\n" + " nop\n", }, + +{ NE, FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, RESCC, + " bne AL,AR,LC\n" + " nop\n", }, + +{ OPLOG, FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SZERO, TANY, + 0, RESCC, + " O AL,LC\n" + " nop\n", }, + +{ OPLOG, FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESCC, + " sub A1,AL,AR\n" + " O A1,LC\n" + " nop\n", }, + +{ OPLOG, FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESCC, + " sub A1,AL,AR\n" + " O A1,LC\n" + " nop\n", }, + +{ OPLOG, FORCC, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NAREG, RESCC, + "ZD", }, + +{ OPLOG, FORCC, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RESCC, + "ZG", }, + +/* + * Convert LTYPE to reg. + */ + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TCHAR, + NAREG, RESC1, + " lb A1,AL # load char to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TUCHAR, + NAREG, RESC1, + " lbu A1,AL # load uchar to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TSHORT, + NAREG, RESC1, + " lh A1,AL # load short to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TUSHORT, + NAREG, RESC1, + " lhu A1,AL # load ushort to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG|SNAME, TWORD|TPOINT, + NAREG, RESC1, + " lw A1,AL # load (u)int/(u)long to reg\n" + " nop\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SOREG|SNAME, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " lw U1,UL # load (u)longlong to reg\n" + " nop\n" + " lw A1,AL\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON, TPOINT, + NAREG, RESC1, + " la A1,AL # load constant address to reg\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SZERO, TANY, + NAREG, RESC1, + " move A1,$zero # load 0 to reg\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON, TANY, + NAREG, RESC1, + " li A1,AL # load constant to reg\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SZERO, TANY, + NBREG, RESC1, + " move A1,$zero # load 0 to reg\n" + " move U1,$zero\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SCON, TANY, + NBREG, RESC1, + " li A1,AL # load constant to reg\n" + " li U1,UL\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SANY, TANY, + NAREG, RESC1, + " move A1,AL\n", }, + +{ OPLTYPE, INCREG, + SANY, TANY, + SZERO, TFLOAT, + NCREG, RESC1, + " mtc1 $zero,A1 # load 0 to float reg\n" + " nop\n", }, + +{ OPLTYPE, INCREG, + SANY, TANY, + SZERO, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " mtc1 $zero,A1 # load 0 to (l)double reg\n" + " mtc1 $zero,U1\n" + " nop\n", }, + +{ OPLTYPE, INCREG, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NCREG, RESC1, + " l.s A1,AL # load into floating-point reg\n" + " nop\n", }, + +{ OPLTYPE, INCREG, + SANY, TANY, + OREG|SNAME, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " l.d A1,AL # load into double floating-point reg\n" + " nop\n", }, + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " j LL # goto label\n" + " nop\n" + " nop\n", }, + +/* + * Subroutine calls. + */ + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " subu $sp,$sp,16 # call (args, no result) to scon/sname\n" + " jal CL\n" + " nop\n" + "ZC", }, + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " jal CL # call (no args, no result) to scon/sname\n" + " nop\n", }, + +{ CALL, INAREG, + SCON, TANY, + SAREG, TANY, + NAREG, RESC1, /* should be 0 */ + " subu $sp,$sp,16 # call (args, result in v0) to scon/sname\n" + " jal CL\n" + " nop\n" + "ZC", }, + +{ UCALL, INAREG, + SCON, TANY, + SAREG, TANY, + NAREG, RESC1, /* should be 0 */ + " jal CL # call (no args, result in v0) to scon/sname\n" + " nop\n", + }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, TANY, + NBREG, RESC1, /* should be 0 */ + " subu $sp,$sp,16 # call (args, result in v0:v1) to scon/sname\n" + " jal CL\n" + " nop\n" + "ZC", }, + +{ UCALL, INBREG, + SCON, TANY, + SBREG, TANY, + NBREG, RESC1, /* should be 0 */ + " jal CL # call (no args, result in v0:v1) to scon/sname\n" + " nop\n", + }, + +{ CALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG, RESC1, /* should be 0 */ + " subu $sp,$sp,16 # call (args, result in f0:f1) to scon/sname\n" + " jal CL\n" + " nop\n" + "ZC", }, + +{ UCALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG, RESC1, /* should be 0 */ + " jal CL # call (no args, result in v0:v1) to scon/sname\n" + " nop\n", + }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " subu $sp,$sp,16 # call (args, no result) to reg\n" + " move $25,AL\n" + " jal $25\n" + " nop\n" + "ZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " move $25,AL\n" + " jal $25 # call (no args, no result) to reg\n" + " nop\n", }, + +{ CALL, INAREG, + SAREG, TANY, + SAREG, TANY, + NAREG, RESC1, /* should be 0 */ + " subu $sp,$sp,16 # call (args, result) to reg\n" + " move $25,AL\n" + " jal $25\n" + " nop\n" + "ZC", }, + +{ UCALL, INAREG, + SAREG, TANY, + SAREG, TANY, + NAREG, RESC1, /* should be 0 */ + " move $25,AL\n" + " jal $25 # call (no args, result) to reg\n" + " nop\n", }, + +{ CALL, INBREG, + SAREG, TANY, + SBREG, TANY, + NBREG, RESC1, /* should be 0 */ + " subu $sp,$sp,16 # call (args, result) to reg\n" + " move $25,AL\n" + " jal $25\n" + " nop\n" + "ZC", }, + +{ UCALL, INBREG, + SAREG, TANY, + SBREG, TANY, + NBREG, RESC1, /* should be 0 */ + " move $25,AL\n" + " jal $25 # call (no args, result) to reg\n" + " nop\n", }, + +{ CALL, INCREG, + SAREG, TANY, + SCREG, TANY, + NCREG, RESC1, /* should be 0 */ + " subu $sp,$sp,16 # call (args, result) to reg\n" + " move $25,AL\n" + " jal $25\n" + " nop\n" + "ZC", }, + +{ UCALL, INCREG, + SCREG, TANY, + SCREG, TANY, + NCREG, RESC1, /* should be 0 */ + " move $25,AL\n" + " jal $25 # call (no args, result) to reg\n" + " nop\n", }, + + +/* struct return */ +{ USTCALL, FOREFF, + SCON|SNAME, TANY, + SANY, TANY, + 0, 0, + " jal CL\n" + " nop\n", }, + +{ USTCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " move $25,AL\n" + " jal $25\n" + " nop\n", }, + +{ USTCALL, INAREG, + SCON|SNAME, TANY, + SANY, TANY, + NAREG|NASL, RESC1, + " jal CL\n" + " nop\n", }, + +{ USTCALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, + " move $25,AL\n" + " jal $25\n" + " nop\n", }, + +{ STCALL, FOREFF, + SCON|SNAME, TANY, + SANY, TANY, + 0, 0, + " subu $sp,$sp,16\n" + " jal CL\n" + " nop\n" + "ZC", }, + +{ STCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " subu $sp,$sp,16\n" + " move $25,AL\n" + " jal $25\n" + " nop\n" + "ZC", }, + +{ STCALL, INAREG, + SCON|SNAME, TANY, + SANY, TANY, + NAREG|NASL, RESC1, + " subu $sp,$sp,16\n" + " jal CL\n" + " nop\n" + "ZC", }, + +{ STCALL, INAREG, + SAREG, TANY, + SANY, TANY, + 0, 0, + " subu $sp,$sp,16\n" + " move $25,AL\n" + " jal $25\n" + " nop\n" + "ZC", }, + + +/* + * Function arguments + */ + +#if 0 + +/* intentionally write out the register for (u)short/(u)char */ +{ FUNARG, FOREFF, + SAREG, TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR, + SANY, TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR, + 0, 0, + " subu $sp,$sp,4 # save function arg to stack\n" + " sw AL,($sp)\n" + " #nop\n", }, + +{ FUNARG, FOREFF, + SBREG, TLONGLONG|TULONGLONG, + SANY, TLONGLONG|TULONGLONG, + 0, 0, + " addi $sp,$sp,-8 # save function arg to stack (endian problem here?\n" + " sw UL,4($sp)\n" + " sw AL,($sp)\n" + " #nop\n", }, + +{ FUNARG, FOREFF, + SCREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " addi $sp,$sp,-4 # save function arg to stack\n" + " s.s AL,($sp)\n" + " #nop\n", }, + +{ FUNARG, FOREFF, + SCREG, TDOUBLE|TLDOUBLE, + SANY, TDOUBLE|TLDOUBLE, + 0, 0, + " addi $sp,$sp,-8 # save function arg to stack\n" + " s.d AL,($sp)\n" + " #nop\n", }, + +#endif + +{ STARG, FOREFF, + SAREG, TANY, + SANY, TSTRUCT, + NSPECIAL, 0, + "ZH", }, + +/* + * Indirection operators. + */ +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG, RESC1, + " lw A1,AL # word load\n" + " nop\n", }, + +{ UMUL, INAREG, + SANY, TSHORT|TUSHORT, + SOREG, TSHORT|TUSHORT, + NAREG, RESC1, + " lh A1,AL # (u)short load\n" + " nop\n", }, + +{ UMUL, INAREG, + SANY, TCHAR|TUCHAR, + SOREG, TCHAR|TUCHAR, + NAREG, RESC1, + " lb A1,AL # (u)char load\n" + " nop\n", }, + +{ UMUL, INBREG, + SANY, TLONGLONG|TULONGLONG, + SOREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " lw A1,AL # (u)longlong load - endian problem here?\n" + " nop\n" + " lw U1,UL\n" + " nop\n", }, + +{ UMUL, INCREG, + SANY, TFLOAT, + SOREG, TFLOAT, + NCREG, RESC1, + " l.s A1,AL # float load\n" + " nop\n", }, + +{ UMUL, INCREG, + SANY, TDOUBLE|TLDOUBLE, + SOREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " l.d A1,AL # float load\n" + " nop\n", }, + +#if 0 +{ UMUL, INCREG, + SANY, TDOUBLE|TLDOUBLE, + SAREG, TPOINT, + NCREG, RESC1, + " l.d A1,(AL)\n" + " nop\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SNAME, TPOINT|TWORD, + NAREG, RESC1, + " la A1,AL # sname word load\n" + " lw A1,(A1)\n" + " nop\n", }, + +{ UMUL, INAREG, + SANY, TSHORT|TUSHORT, + SNAME, TSHORT|TUSHORT, + NAREG, RESC1, + " la A1,AL # sname (u)short load\n" + " lh A1,(A1)\n" + " nop\n", }, + +{ UMUL, INAREG, + SANY, TCHAR|TUCHAR, + SNAME, TCHAR|TUCHAR, + NAREG, RESC1, + " la A1,AL # sname (u)char load\n" + " lb A1,(A1)\n" + " nop\n", }, + +{ UMUL, INBREG, + SANY, TLONGLONG|TULONGLONG, + SNAME, TLONGLONG|TULONGLONG, + NBREG|NAREG, RESC1, + " la A2,AL # sname (u)long long load - endian problems here?\n" + " lw A1,(A1)\n" + " nop\n" + " lw U1,4(A1)\n" + " nop\n", }, +#endif + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SAREG, TPOINT|TWORD, + NAREG, RESC1, + " lw A1,(AL) # word load\n" + " nop\n", }, + +#if 0 +{ UMUL, INAREG, + SANY, TSHORT|TUSHORT, + SAREG, TPTRTO|TSHORT|TUSHORT, + NAREG, RESC1, + " lh A1,(AL) # (u)short load\n" + " nop\n", }, + +{ UMUL, INAREG, + SANY, TCHAR|TUCHAR, + SAREG, TPTRTO|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " lb A1,(AL) # (u)char load\n" + " nop\n", }, + +{ UMUL, INBREG, + SANY, TLONGLONG|TULONGLONG, + SAREG, TPTRTO|TLONGLONG|TULONGLONG, + NBREG, RESC1, + " lw A1,(AL) # (u)long long load - endianness problems?\n" + " nop\n" + " lw U1,4(AL)" + " nop\n", }, +#endif + +#define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ FLD, DF(FLD), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/nova/README b/lang/pcc/pcc/arch/nova/README new file mode 100644 index 000000000..d13317433 --- /dev/null +++ b/lang/pcc/pcc/arch/nova/README @@ -0,0 +1,245 @@ +Calling conventions, stack frame and zero page: + +The variables that normally are placed on the stack or in registers in C +are instead allocated in the zero page and saved on a (fictive) stack +when calling functions. Some locations have predefined functions though. +Arrays allocated as automatics are stored on the stack with a pointer +in zero page to its destination. + +0-7 Unused (by us) +10 Stack pointer +11 Frame pointer +12-14 Unused +15 Prolog private word +16 Prolog address, written in crt0 +17 Epilog address, written in crt0 +20-27 (Auto-increment), scratch +30-37 (Auto-decrement), scratch +40-47 Used by HW stack and MMPU +50-77 Permanent, save before use. +100-377 Addresses for subroutines, written by the linker + +The normal registers (AC0-AC3) are all considered scratch registers. + +Register classes are assigned as: + AC0-AC3: AREGs. + AC2-AC3: BREGs. + ...and eventually register pairs/floats as EREGs, double in FREGs. + +In byte code the left half of a word is the first byte (big-endian). +This is bit 0-7 in Nova syntax. +The stack is growing towards lower adresses (as opposed to the Eclipse stack). +Stack pointer points to the last used stack entry, which means: +PUSH: dec sp, store value +POP: fetch val, inc sp + +Note that internally is the first 24 words stored in loc 50-77! +So an offset is subtracted in adrput(). + +Stack layout: + + ! arg1 ! 1 + fp -> ! arg0 ! 0 + ! old pc! -1 + ! old fp! -2 + sp -> ! saved ! -3 + + +Stack references to zero page are converted to NAMEs, using word addresses. +References to the stack itself are using byte offsets. + +Arguments are transferred on the stack. To avoid unneccessary double instructions +they are copied to the zp use area initially. XXX? Need tests here. +Return values in ac0 and ac1. + +A reference to a struct member in assembler, a = b->c; b is in ZP 50 (or on stack) ++ is zeropage-addressing +* is fp-adressing, assume fp in ac3 + +# offset 0 ++ lda 0,@50 # load value from indirect ZP 50 into ac0 +or +* lda 2,,3 # load value from (ac3) into ac2 +* lda 0,,2 # load value from (ac2) into ac0 + +# offset 12 ++ lda 2,50 # load value from ZP 50 into ac2 ++ lda 0,12,2 # load value from (ac2+12) into ac0 +or +* lda 2,,3 # load value from (ac3) into ac2 +* lda 0,12,2 # load value from 12(ac2) into ac0 + +# offset 517 ++ lda %2,50 # load value from ZP 50 into ac2 ++ lda %0,.L42-.,%1 # load offset from .L42 PC-indexed ++ addz %0,%2,skp # add offset to ac2 and skip ++.L42: .word 517 # offset value ++ lda %0,,%2 # load value from (ac2) into ac0 +or + +The prolog/epilog; they are implemented as subroutines. +Both can be omitted if the function do not need it. + + + .word 012 # total words that needs to be saved +func: + mov 3,0 # avoid trashing return address + jsr @prolog # go to prolog + ... + jmp @epilog # jump to epilog + +#ifdef prolog + lda 0,sp + sta 3,@sp + lda 1,fp + sta 1,@sp + sta 0,fp + lda 1,[Css] + sub 1,0 + sta 0,sp +#endif + +... + + lda 2,fp + lda 3,-1,2 + lda 0,-2,2 + sta 0,fp + sta 2,sp + jmp 0,3 + + +# +# decrement from stack, and save permanent registers. +# push retreg +# push fp +# mov sp,fp +# sub $w,sp +# +# prolog: return in ac3, fun in ac0. +prolog: lda 1,sp + sta 0,@sp + lda 0,fp + sta 0,@sp + sta 1,fp + lda 0,-3,3 + sub 0,1 + sta 1,sp + jmp 0,3 + +epilog: lda 3,fp + sta 3,sp + lda 3,@fp + lda 2,@fp + sta 2,fp + jmp 0,3 + + + + + + + +prolog: + lda 2,sp # sp points to the first argument + sta 2,30 # store at auto-dec location + sta 0,@30 # store fun return address + lda 0,fp # fetch old fp + sta 0,@30 # store saved fp + sta 2,fp # save frame pointer + + lda 0,-3,3 # stack size to subtract + neg 0,0,snr # Any words? + jmp 1f # no, get away + lda 1,$51 # fetch zp offset + sub 0,1 # get highest word + sta 1,31 # at auto-dec location + +2: lda 1,@31 # fetch word to copy + sta 1,@30 # on stack + inc 0,0,szr # count words + jmp 1b # more to go + +1: lda 0,30 # finished, get stackptr + sta 0,sp # + jmp 0,3 # get back! + +# epilog, need save frame pointer in ac3 +epilog: + lda 0,-3,3 # get words to save + neg 0,0,snr # any words to save? + jmp 1f # No, get out + + lda 1,$51 # get zp offset + sub 0,1 # Highest word + sta 1,31 # auto-dec loc + + lda 2,fp # get fp + adczl 1,1 # -2 + add 1,2 # 2 now offset + sta 2,30 # auto-dec loc + +2: lda 1,@30 + sta 1,@31 + inc 0,0,szr + jmp 2b + +1: lda 2,fp # fetch current fp + lda 3,-1,2 # return pc + lda 0,-2,2 # fetch old fp + sta 0,fp # restore fp + sta 2,sp # stack pointer restored + jmp 0,3 # Done! + +#if 0 +Assembler syntax and functions. + +The assembler syntax mimics the DG assembler but uses AT&T syntax. +Load and store to addresses is written "lda 0,foo" to load from address foo. +If foo is not in zero page then the assembler will put the lda in the +text area close to the instruction and do an indirect pc-relative load. + +Arithmetic instruction: + subsl# %0,%1,snr skip code may be omitted + subsl# %0,%1 + +Load/store/jmp/jsr/isz/dsz: + lda %1,@disp,2 or + mov *disp(%2),%1 + index may be omitted if 0 (ZP) + disp can only be +-127 words. + + It's allowed to write "mov $32,%0" which will be converted + to an indirect load by the assembler. + + Example of AT&T arguments: + 01234 - Zero-page + L11 - Relative. Will be converted to + indirect + addr if distance too long + (%2) - indexed + 012(%2) - indexed with offset + * in front of any of these will generate indirection +#endif + +lbyte: movr 2,2 # get byte ID into C bit + lda 0,,2 # word into ac0 + mov 2,2,snc # skip if right byte + movs 0,0 # swap bytes + jmp 0,3 # get back + +sbyte: sta 3,@sp + + movr 2,2 # get byte ID into C bit + lda 1,,2 # get word + lda 3,[377] # get mask + and 3,0,snc # clear left input + skip if right byte + movs 1,1 # swap bytes + and 3,1 # clear old bits + add 0,1,snc # swap back if necessary + movs 1,1 # swap + sta 1,2 + + lda 3,sp + isz sp + jmp @0,3 + diff --git a/lang/pcc/pcc/arch/nova/code.c b/lang/pcc/pcc/arch/nova/code.c new file mode 100644 index 000000000..07f3d56d8 --- /dev/null +++ b/lang/pcc/pcc/arch/nova/code.c @@ -0,0 +1,259 @@ +/* $Id: code.c,v 1.11 2014/06/03 20:19:50 ragge Exp $ */ +/* + * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +/* + * cause the alignment to become a multiple of n + * never called for text segment. + */ +void +defalign(int n) +{ + /* alignment are always correct */ +} + +/* + * Print out assembler segment name. + */ +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + case DATA: + case LDATA: name = ".data"; break; + case STRNG: + case RDATA: name = ".section .rodata"; break; + case UDATA: break; + default: + cerror((char *)__func__); + } + printf("\t%s\n", name); +} + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + char *name; + + if ((name = sp->soname) == NULL) + name = exname(sp->sname); + + if (ISFTN(sp->stype)) + return; + if (sp->sclass == EXTDEF) + printf("\t.globl %s\n", name); + if (sp->slevel == 0) + printf("%s:\n", name); + else + printf(LABFMT ":\n", sp->soffset); +} + +/* make a common declaration for id, if reasonable */ +void +defzero(struct symtab *sp) +{ + int off, al; + char *name; + + if ((name = sp->soname) == NULL) + name = exname(sp->sname); + off = tsize(sp->stype, sp->sdf, sp->sap); + SETOFF(off,SZCHAR); + off /= SZCHAR; + al = talign(sp->stype, sp->sap)/SZCHAR; + + if (sp->sclass == STATIC) { + if (sp->slevel == 0) { + printf("\t.local %s\n", name); + } else + printf("\t.local " LABFMT "\n", sp->soffset); + } + if (sp->slevel == 0) { + printf("\t.comm %s,0%o,%d\n", name, off, al); + } else + printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); +} + + +//static int ac3temp; +/* + * code for the end of a function + * deals with struct return here + */ +void +efcode(void) +{ + NODE *p, *q; +// int sz; + +#if 0 + /* restore ac3 */ + p = block(REG, 0, 0, INT, 0, 0); + regno(p) = 3; + q = tempnode(ac3temp, INT, 0, 0); + ecomp(buildtree(ASSIGN, p, q)); +#endif + + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; +cerror("efcode"); + /* address of return struct is in eax */ + /* create a call to memcpy() */ + /* will get the result in eax */ + p = block(REG, NIL, NIL, CHAR+PTR, 0, 0); +// p->n_rval = EAX; + q = block(OREG, NIL, NIL, CHAR+PTR, 0, 0); +// q->n_rval = EBP; + q->n_lval = 8; /* return buffer offset */ + p = block(CM, q, p, INT, 0, 0); +// sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR; +// p = block(CM, p, bcon(sz), INT, 0, 0); + p->n_right->n_name = ""; + p = block(CALL, bcon(0), p, CHAR+PTR, 0, 0); + p->n_left->n_name = "memcpy"; + p = clocal(p); + send_passt(IP_NODE, p); +} + +/* + * code for the beginning of a function; a is an array of + * indices in symtab for the arguments; n is the number + */ +void +bfcode(struct symtab **a, int n) +{ +// NODE *p, *q; + int i; + + for (i = 0; i < n; i++) { + if (a[i]->stype == CHAR) + a[i]->stype = INT; + if (a[i]->stype == UCHAR) + a[i]->stype = UNSIGNED; + } + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; +cerror("bfcode"); + /* Function returns struct, adjust arg offset */ + for (i = 0; i < n; i++) + a[i]->soffset += SZPOINT(INT); +} + + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ +} + +void +bjobcode(void) +{ +} + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + */ +NODE * +funcode(NODE *p) +{ + NODE *r, *l; + + /* Fix function call arguments. On nova, just add funarg */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + if (r->n_right->n_op != STARG) + r->n_right = block(FUNARG, r->n_right, NIL, + r->n_right->n_type, r->n_right->n_df, + r->n_right->n_ap); + } + if (r->n_op != STARG) { + l = talloc(); + *l = *r; + r->n_op = FUNARG; + r->n_left = l; + r->n_type = l->n_type; + } + + return p; +} + +/* + * Return return as given by a. + */ +NODE * +builtin_return_address(const struct bitable *bt, NODE *a) +{ + cerror((char *)__func__); + return 0; +} + +/* + * Return frame as given by a. + */ +NODE * +builtin_frame_address(const struct bitable *bt, NODE *a) +{ + cerror((char *)__func__); + return 0; +} + +/* + * Return "canonical frame address". + */ +NODE * +builtin_cfa(const struct bitable *bt, NODE *a) +{ + cerror((char *)__func__); + return 0; +} + diff --git a/lang/pcc/pcc/arch/nova/local.c b/lang/pcc/pcc/arch/nova/local.c new file mode 100644 index 000000000..0fd593f1e --- /dev/null +++ b/lang/pcc/pcc/arch/nova/local.c @@ -0,0 +1,649 @@ +/* $Id: local.c,v 1.17 2015/08/18 10:15:08 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +/* this file contains code which is dependent on the target machine */ + +NODE * +clocal(NODE *p) +{ + struct symtab *q; + NODE *r, *l; + TWORD t; + int o; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal\n"); + fwalk(p, eprint, 0); + } +#endif + + switch( o = p->n_op ){ + case NAME: + /* handle variables */ + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + switch (q->sclass) { + case PARAM: + case AUTO: + if (0 && q->soffset < MAXZP * SZINT && + q->sclass != PARAM) { + p->n_lval = -(q->soffset/SZCHAR) + ZPOFF*2; + p->n_sp = NULL; + } else { + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + r->n_lval = 0; + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + } + break; + default: + break; + } + break; + + case PMCONV: + case PVCONV: + if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); + nfree(p); + p = (buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right)); + break; + + case PCONV: + t = p->n_type; + if (t == INCREF(CHAR) || t == INCREF(UCHAR) || + t == INCREF(BOOL) || t == INCREF(VOID)) + break; + l = p->n_left; + t = l->n_type; + if (t == INCREF(CHAR) || t == INCREF(UCHAR) || + t == INCREF(BOOL) || t == INCREF(VOID)) + break; + if (p->n_type <= UCHAR || l->n_type <= UCHAR) + break; /* must do runtime ptr conv */ + /* if conversion to another pointer type, just remove */ + if (p->n_type > BTMASK && l->n_type > BTMASK) + goto delp; + if (l->n_op == ICON && l->n_sp == NULL) + goto delp; + break; + + delp: l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_ap = p->n_ap; + p = nfree(p); + break; + } + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal end\n"); + fwalk(p, eprint, 0); + } +#endif + +#if 0 + register struct symtab *q; + register NODE *r, *l; + register int o; + register int m; + TWORD t; + +//printf("in:\n"); +//fwalk(p, eprint, 0); + switch( o = p->n_op ){ + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + r->n_lval = 0; + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case STATIC: + if (q->slevel == 0) + break; + p->n_lval = 0; + p->n_sp = q; + break; + + case REGISTER: + p->n_op = REG; + p->n_lval = 0; + p->n_rval = q->soffset; + break; + + } + break; + + case STCALL: + case CALL: + /* Fix function call arguments. On x86, just add funarg */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + if (r->n_right->n_op != STARG && + r->n_right->n_op != FUNARG) + r->n_right = block(FUNARG, r->n_right, NIL, + r->n_right->n_type, r->n_right->n_df, + r->n_right->n_sue); + } + if (r->n_op != STARG && r->n_op != FUNARG) { + l = talloc(); + *l = *r; + r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type; + } + break; + + case CBRANCH: + l = p->n_left; + + /* + * Remove unnecessary conversion ops. + */ + if (clogop(l->n_op) && l->n_left->n_op == SCONV) { + if (coptype(l->n_op) != BITYPE) + break; + if (l->n_right->n_op == ICON) { + r = l->n_left->n_left; + if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) + break; + /* Type must be correct */ + t = r->n_type; + nfree(l->n_left); + l->n_left = r; + l->n_type = t; + l->n_right->n_type = t; + } + } + break; + + case PCONV: + /* Remove redundant PCONV's. Be careful */ + l = p->n_left; + if (l->n_op == ICON) { + l->n_lval = (unsigned)l->n_lval; + goto delp; + } + if (l->n_type < INT || l->n_type == LONGLONG || + l->n_type == ULONGLONG) { + /* float etc? */ + p->n_left = block(SCONV, l, NIL, + UNSIGNED, 0, 0); + break; + } + /* if left is SCONV, cannot remove */ + if (l->n_op == SCONV) + break; + /* if conversion to another pointer type, just remove */ + if (p->n_type > BTMASK && l->n_type > BTMASK) + goto delp; + break; + + delp: l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_sue = p->n_sue; + nfree(p); + p = l; + break; + + case SCONV: + l = p->n_left; + + if (p->n_type == l->n_type) { + nfree(p); + return l; + } + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + btdims[p->n_type].suesize == btdims[l->n_type].suesize) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + return l; + } + } + } + + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && + coptype(l->n_op) == BITYPE) { + l->n_type = p->n_type; + nfree(p); + return l; + } + + o = l->n_op; + m = p->n_type; + + if (o == ICON) { + CONSZ val = l->n_lval; + + if (!ISPTR(m)) /* Pointers don't need to be conv'd */ + switch (m) { + case CHAR: + l->n_lval = (char)val; + break; + case UCHAR: + l->n_lval = val & 0377; + break; + case SHORT: + l->n_lval = (short)val; + break; + case USHORT: + l->n_lval = val & 0177777; + break; + case ULONG: + case UNSIGNED: + l->n_lval = val & 0xffffffff; + break; + case LONG: + case INT: + l->n_lval = (int)val; + break; + case LONGLONG: + l->n_lval = (long long)val; + break; + case ULONGLONG: + l->n_lval = val; + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = val; + break; + default: + cerror("unknown type %d", m); + } + l->n_type = m; + l->n_sue = 0; + nfree(p); + return l; + } + if (DEUNSIGN(p->n_type) == SHORT && + DEUNSIGN(l->n_type) == SHORT) { + nfree(p); + p = l; + } + if ((p->n_type == CHAR || p->n_type == UCHAR || + p->n_type == SHORT || p->n_type == USHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue); + p->n_left->n_type = INT; + return p; + } + break; + + case MOD: + case DIV: + if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) + break; + if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) + break; + /* make it an int division by inserting conversions */ + p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); + p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); + p = block(SCONV, p, NIL, p->n_type, 0, 0); + p->n_left->n_type = INT; + break; + + case PMCONV: + case PVCONV: + if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); + nfree(p); + return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right)); + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + p->n_left->n_rval = RETREG(p->n_type); + break; + + case LS: + case RS: + /* shift count must be in a char + * unless longlong, where it must be int */ + if (p->n_right->n_op == ICON) + break; /* do not do anything */ + if (p->n_type == LONGLONG || p->n_type == ULONGLONG) { + if (p->n_right->n_type != INT) + p->n_right = block(SCONV, p->n_right, NIL, + INT, 0, 0); + break; + } + if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR) + break; + p->n_right = block(SCONV, p->n_right, NIL, + CHAR, 0, 0); + break; + } +//printf("ut:\n"); +//fwalk(p, eprint, 0); + +#endif + + return(p); +} + +void +myp2tree(NODE *p) +{ + struct symtab *sp; + NODE *l, *r; + int o = p->n_op; + + switch (o) { + case NAME: /* reading from a name must be done with a subroutine */ + if (p->n_type != CHAR && p->n_type != UCHAR) + break; + l = buildtree(ADDROF, ccopy(p), NIL); + r = block(NAME, NIL, NIL, INT, 0, 0); + + r->n_sp = lookup(addname("__nova_rbyte"), SNORMAL); + if (r->n_sp->sclass == SNULL) { + r->n_sp->sclass = EXTERN; + r->n_sp->stype = INCREF(p->n_type)+(FTN-PTR); + } + r->n_type = r->n_sp->stype; + r = clocal(r); + r = optim(buildtree(CALL, r, l)); + *p = *r; + nfree(r); + break; + + case FCON: + sp = tmpalloc(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->sap = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + + defloc(sp); + ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + + p->n_op = NAME; + p->n_lval = 0; + p->n_sp = sp; + } +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * Return 1 if a variable of type type is OK to put in register. + */ +int +cisreg(TWORD t) +{ + return 1; /* try to put anything in a register */ +} + +/* + * return a node, for structure references, which is suitable for + * being added to a pointer of type t, in order to be off bits offset + * into a structure + * t, d, and s are the type, dimension offset, and sizeoffset + * For nova, return the type-specific index number which calculation + * is based on its size. For example, char a[3] would return 3. + * Be careful about only handling first-level pointers, the following + * indirections must be fullword. + */ +NODE * +offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *ap) +{ + register NODE *p; + + if (xdebug) + printf("offcon: OFFSZ %ld type %x dim %p siz %ld\n", + off, t, d, tsize(t, d, ap)); + + p = bcon(off/SZINT); + if (t == INCREF(CHAR) || t == INCREF(UCHAR) || t == INCREF(VOID)) + p->n_lval = off/SZCHAR; /* pointer to char */ + return(p); +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a NAME node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + +cerror("spalloc"); + if ((off % SZINT) == 0) + p = buildtree(MUL, p, bcon(off/SZINT)); + else if ((off % SZSHORT) == 0) { + p = buildtree(MUL, p, bcon(off/SZSHORT)); + p = buildtree(PLUS, p, bcon(1)); + p = buildtree(RS, p, bcon(1)); + } else if ((off % SZCHAR) == 0) { + p = buildtree(MUL, p, bcon(off/SZCHAR)); + p = buildtree(PLUS, p, bcon(3)); + p = buildtree(RS, p, bcon(2)); + } else + cerror("roundsp"); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); + sp->n_lval = 0; + sp->n_rval = STKREG; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + + /* add the size to sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(PLUSEQ, sp, p)); +} + +/* + * print out a constant node + * mat be associated with a label + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ + switch (p->n_type) { + case FLOAT: + case DOUBLE: + case LDOUBLE: + cerror("ninval"); + } + return 1; +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ + if (p == NULL) + return ""; + return p; +} + +/* + * map types which are not defined on the local machine + */ +TWORD +ctype(TWORD type) +{ + switch (BTYPE(type)) { + case LONGLONG: + MODTYPE(type,LONG); + break; + + case ULONGLONG: + MODTYPE(type,ULONG); + break; + case SHORT: + MODTYPE(type,INT); + break; + case USHORT: + MODTYPE(type,UNSIGNED); + break; + } + return (type); +} + +#if 0 +/* curid is a variable which is defined but + * is not initialized (and not a function ); + * This routine returns the storage class for an uninitialized declaration + */ +int +noinit() +{ + return(EXTERN); +} +#endif + +void +calldec(NODE *p, NODE *q) +{ +} + +void +extdec(struct symtab *q) +{ +} + +#if 0 +/* make a common declaration for id, if reasonable */ +void +commdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + printf(" .comm %s,0%o\n", exname(q->soname), off); +} + +/* make a local common declaration for id, if reasonable */ +void +lcommdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + if (q->slevel == 0) + printf(" .lcomm %s,0%o\n", exname(q->soname), off); + else + printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off); +} + +/* + * print a (non-prog) label. + */ +void +deflab1(int label) +{ + printf(LABFMT ":\n", label); +} + +static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata" }; + +void +setloc1(int locc) +{ + if (locc == lastloc) + return; + lastloc = locc; + printf(" .%s\n", loctbl[locc]); +} +#endif + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + return 0; +} + +/* + * Called when a identifier has been declared, to give target last word. + * On Nova we put symbols over the size of an int above 24 bytes in + * offset and leave zeropage for small vars. + */ +void +fixdef(struct symtab *sp) +{ +#if 0 + if (sp->sclass != AUTO) + return; /* not our business */ + if (ISPTR(sp->stype) || sp->stype < LONG) + return; + if (sp->soffset >= (MAXZP * SZINT)) + return; /* already above */ + /* have to move */ + /* XXX remember old autooff for reorg of smaller vars */ + if (autooff < MAXZP * SZINT) + autooff = MAXZP * SZINT; + oalloc(sp, &autooff); +#endif +} + +void +pass1_lastchance(struct interpass *ip) +{ +} diff --git a/lang/pcc/pcc/arch/nova/local2.c b/lang/pcc/pcc/arch/nova/local2.c new file mode 100644 index 000000000..59d20aaf3 --- /dev/null +++ b/lang/pcc/pcc/arch/nova/local2.c @@ -0,0 +1,622 @@ +/* $Id: local2.c,v 1.13 2015/03/28 08:28:46 ragge Exp $ */ +/* + * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" +# include +# include + +void acon(NODE *p); +int argsize(NODE *p); + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +void +prologue(struct interpass_prolog *ipp) +{ + int totstk; + + totstk = p2maxautooff/(SZINT/SZCHAR); + + if (totstk) + printf(" .word 0%o\n", totstk); + printf("%s:\n", ipp->ipp_name); + if (ipp->ipp_vis) + printf(" .globl %s\n", ipp->ipp_name); + printf(" mov 3,0\n"); /* put ret pc in ac0 */ + printf(" jsr @16\n"); /* jump to prolog */ +} + +void +eoftn(struct interpass_prolog *ipp) +{ + + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + printf(" jmp @17\n"); +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str = 0; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + cerror("hopcode OR"); + break; + case ER: + cerror("hopcode xor"); + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s%c", str, f); +} + +#if 0 +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(p) NODE *p; +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} +#endif + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + return 0; +} + +#if 0 +/* + * Assign to a bitfield. + * Clumsy at least, but what to do? + */ +static void +bfasg(NODE *p) +{ + NODE *fn = p->n_left; + int shift = UPKFOFF(fn->n_rval); + int fsz = UPKFSZ(fn->n_rval); + int andval, tch = 0; + + /* get instruction size */ + switch (p->n_type) { + case CHAR: case UCHAR: tch = 'b'; break; + case SHORT: case USHORT: tch = 'w'; break; + case INT: case UNSIGNED: tch = 'l'; break; + default: comperr("bfasg"); + } + + /* put src into a temporary reg */ + printf(" mov%c ", tch); + adrput(stdout, getlr(p, 'R')); + printf(","); + adrput(stdout, getlr(p, '1')); + printf("\n"); + + /* AND away the bits from dest */ + andval = ~(((1 << fsz) - 1) << shift); + printf(" and%c $%d,", tch, andval); + adrput(stdout, fn->n_left); + printf("\n"); + + /* AND away unwanted bits from src */ + andval = ((1 << fsz) - 1); + printf(" and%c $%d,", tch, andval); + adrput(stdout, getlr(p, '1')); + printf("\n"); + + /* SHIFT left src number of bits */ + if (shift) { + printf(" sal%c $%d,", tch, shift); + adrput(stdout, getlr(p, '1')); + printf("\n"); + } + + /* OR in src to dest */ + printf(" or%c ", tch); + adrput(stdout, getlr(p, '1')); + printf(","); + adrput(stdout, fn->n_left); + printf("\n"); +} +#endif + +#if 0 +/* + * Push a structure on stack as argument. + * the scratch registers are already free here + */ +static void +starg(NODE *p) +{ + int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + printf(" subl $%d,%%esp\n", sz); + printf(" pushl $%d\n", sz); + expand(p, 0, " pushl AL\n"); + expand(p, 0, " leal 8(%esp),A1\n"); + expand(p, 0, " pushl A1\n"); + printf(" call memcpy\n"); + printf(" addl $12,%%esp\n"); +} +#endif + +void +zzzcode(NODE *p, int c) +{ + int pr; + + switch (c) { + + case 'C': /* remove from stack after subroutine call */ + pr = p->n_qual; + switch (pr) { + case 1: + printf("\tisz sp\n"); + break; + case 2: + printf("\tisz sp\n\tisz sp\n"); + break; + case 3: + printf("\tisz sp\n\tisz sp\n\tisz sp\n"); + break; + case 4: + printf("\tisz sp\n\tisz sp\n\tisz sp\n\tisz sp\n"); + break; + default: + printf(" lda 2,[0%o]\n", pr); + printf(" lda 3,sp\n"); + printf(" add 2,3\n"); + printf(" sta 3,sp\n"); + break; + } + break; +#if 0 + case 'A': /* print out a skip ending if any numbers in queue */ + if (ldq == NULL) + return; + printf(",skp\n.LP%d: .word 0%o", ldq->lab, ldq->val); + if (ldq->name && *ldq->name) + printf("+%s", ldq->name); + printf("\n"); + ldq = ldq->next; + break; + + case 'B': /* print a label for later load */ + ld = tmpalloc(sizeof(struct ldq)); + ld->val = p->n_lval; + ld->name = p->n_name; + ld->lab = prolnum++; + ld->next = ldq; + ldq = ld; + printf(".LP%d-.", ld->lab); + break; + + case 'C': /* fix reference to external variable via indirection */ + zzzcode(p->n_left, 'B'); + break; + + case 'D': /* fix reference to external variable via indirection */ + zzzcode(p, 'B'); + break; +#endif + + default: + comperr("zzzcode %c", c); + } +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left, SOREG))) + return(1); + return(0); +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + int o = p->n_op; + +cerror("flshape"); + if (o == OREG || o == REG || o == NAME) + return SRDIR; /* Direct match */ + if (o == UMUL && shumul(p->n_left, SOREG)) + return SROREG; /* Convert into oreg */ + return SRREG; /* put it into a register */ +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + return 0; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +void +adrcon(CONSZ val) +{ + printf("[" CONFMT "]", val); +} + +/* + * Conput prints out a constant. + */ +void +conput(FILE *fp, NODE *p) +{ + int val = p->n_lval; + + switch (p->n_op) { + case ICON: + if (p->n_name[0] != '\0') { + fprintf(fp, "%s", p->n_name); + if (val) + fprintf(fp, "+0%o", val); + } else + fprintf(fp, "0%o", val); + return; + + default: + comperr("illegal conput, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ +comperr("upput"); +#if 0 + size /= SZCHAR; + switch (p->n_op) { + case REG: + printf("%%%s", &rnames[p->n_rval][3]); + break; + + case NAME: + case OREG: + p->n_lval += size; + adrput(stdout, p); + p->n_lval -= size; + break; + case ICON: + printf("$" CONFMT, p->n_lval >> 32); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +#endif +} + +void +adrput(FILE *io, NODE *p) +{ + int i; + /* output an address, with offsets, from p */ + +static int looping = 7; +if (looping == 0) { + looping = 1; + printf("adrput %p\n", p); + fwalk(p, e2print, 0); + looping = 0; +} + if (p->n_op == FLD) + p = p->n_left; + + switch (p->n_op) { + case ICON: + /* addressable value of the constant */ + fputc('[', io); + if (p->n_type == INCREF(CHAR) || p->n_type == INCREF(UCHAR)) + printf(".byteptr "); + conput(io, p); + fputc(']', io); + break; + + case NAME: + if (p->n_name[0] != '\0') { + fputs(p->n_name, io); + if (p->n_lval != 0) + fprintf(io, "+" CONFMT, p->n_lval); + } else + fprintf(io, CONFMT, p->n_lval); + break;; + + case OREG: + if (p->n_name[0]) + comperr("name in OREG"); + i = (int)p->n_lval; + if (i < 0) { + putchar('-'); + i = -i; + } + printf("0%o,%s", i, rnames[regno(p)]); + break; + + case REG: + fprintf(io, "%s", rnames[p->n_rval]); + break; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + break; + + } +} + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + comperr("cbgen"); +} + +void +myreader(struct interpass *ipole) +{ + if (x2debug) + printip(ipole); +} + +void +mycanon(NODE *p) +{ +} + +void +myoptim(struct interpass *ip) +{ +} + +void +rmove(int s, int d, TWORD t) +{ + comperr("rmove"); +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + * Return true if we always can find a color. + */ +int +COLORMAP(int c, int *r) +{ + int num = 0; + + switch (c) { + case CLASSA: + num = (r[CLASSA]+r[CLASSB]) < AREGCNT; + break; + case CLASSB: + num = (r[CLASSB]+r[CLASSA]) < BREGCNT; + break; + case CLASSC: + num = r[CLASSC] < CREGCNT; + break; + case CLASSD: + num = r[CLASSD] < DREGCNT; + break; + case CLASSE: + num = r[CLASSE] < EREGCNT; + break; + } + return num; +} + +char *rnames[] = { + "0", "1", "2", "3", "2", "3", "fp", "sp" +}; + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + return ISPTR(t) ? CLASSB : CLASSA; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) { + if (p->n_right->n_op != ASSIGN) + size += szty(p->n_right->n_type); + } + if (p->n_op != ASSIGN) + size += szty(p->n_type); + + op->n_qual = size; /* XXX */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + switch (shape) { + case SLDFPSP: + return regno(p) == FPREG || regno(p) == STKREG; + } + return SRNOPE; +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ +} +/* + * Do something target-dependent for xasm arguments. + * Supposed to find target-specific constraints and rewrite them. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + return 0; +} + +void +storemod(NODE *q, int off, int reg) +{ + NODE *l, *r, *p; + + if (off < MAXZP*2) { + q->n_op = NAME; + q->n_name = ""; + q->n_lval = -off/2 + ZPOFF; + } else { + l = mklnode(REG, 0, reg, INCREF(q->n_type)); + r = mklnode(ICON, off, 0, INT); + p = mkbinode(PLUS, l, r, INCREF(q->n_type)); + q->n_op = UMUL; + q->n_left = p; + } + q->n_rval = q->n_su = 0; +} diff --git a/lang/pcc/pcc/arch/nova/macdefs.h b/lang/pcc/pcc/arch/nova/macdefs.h new file mode 100644 index 000000000..0dcd2050d --- /dev/null +++ b/lang/pcc/pcc/arch/nova/macdefs.h @@ -0,0 +1,179 @@ +/* $Id: macdefs.h,v 1.10 2016/03/05 15:53:04 ragge Exp $ */ +/* + * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Machine-dependent defines for Data General Nova. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|(val); + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZBOOL 8 +#define SZINT 16 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 64 +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 64 +#define SZPOINT(t) 16 /* Actually 15 */ + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALBOOL 8 +#define ALINT 16 +#define ALFLOAT 16 +#define ALDOUBLE 16 +#define ALLDOUBLE 16 +#define ALLONG 16 +#define ALLONGLONG 16 +#define ALSHORT 16 +#define ALPOINT 16 +#define ALSTRUCT 16 +#define ALSTACK 16 + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT MIN_SHORT +#define MAX_INT MAX_SHORT +#define MAX_UNSIGNED MAX_USHORT +#define MIN_LONG 0x80000000L +#define MAX_LONG 0x7fffffffL +#define MAX_ULONG 0xffffffffUL +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +/* Default char is unsigned */ +#define CHAR_UNSIGNED +#define WORD_ADDRESSED +#define BOOL_TYPE UCHAR +#define MYALIGN /* provide private alignment function */ + +/* + * Use large-enough types. + */ +typedef long CONSZ; +typedef unsigned long U_CONSZ; +typedef long OFFSZ; + +#define CONFMT "0%lo" /* format for printing constants */ +#define LABFMT "L%d" /* format for printing labels */ +#define STABLBL "LL%d" /* format for stab (debugging) labels */ + +#define BACKAUTO /* stack grows negatively for automatics */ +#define BACKTEMP /* stack grows negatively for temporaries */ +#define ARGINIT 0 /* first arg at 0 offset */ +#define AUTOINIT 32 /* first var below 32-bit offset */ + + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_BE + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&01) +#define wdal(k) (BYTEOFF(k)==0) + +#define szty(t) ((t) == DOUBLE || (t) == LDOUBLE || \ + (t) == LONGLONG || (t) == ULONGLONG ? 4 : \ + ((t) == LONG || (t) == ULONG || (t) == FLOAT) ? 2 : 1) + +/* + * The Nova has two register classes. Note that the space used in + * zero page is considered stack. + * Register 6 and 7 are FP and SP (in zero page). + * + * The classes used on Nova are: + * A - AC0-AC3 (as non-index registers) : reg 0-3 + * B - AC2-AC3 (as index registers) : reg 4-5 + * FP/SP as 6/7. + */ +#define MAXREGS 8 /* 0-29 */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SBREG|TEMPREG, SBREG|TEMPREG, 0, 0 + +#define ROVERLAP \ + { -1 }, { -1 }, { 4, -1 }, { 5, -1 }, { 2, -1 }, { 3, -1 }, \ + { -1 }, { -1 } + +/* Return a register class based on the type of the node */ +/* Used in tshape, avoid matching fp/sp as reg */ +#define PCLASS(p) (p->n_op == REG && regno(p) > 5 ? 0 : \ + ISPTR(p->n_type) ? SBREG : SAREG) + +#define NUMCLASS 2 /* highest number of reg classes used */ + +int COLORMAP(int c, int *r); +#define GCLASS(x) (x < 4 ? CLASSA : CLASSB) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ +#define RETREG(x) (0) /* ? Sanity */ + +#define FPREG 6 /* frame pointer */ +#define STKREG 7 /* stack pointer */ + +#define MAXZP 030 /* number of locations used as stack */ +#define ZPOFF 050 /* offset of zero page regs */ + +#define MYSTOREMOD +#define MYLONGTEMP(p,w) { \ + if (w->r_class == 0) { \ + w->r_color = freetemp(szty(p->n_type)); \ + w->r_class = FPREG; \ + } \ + if (w->r_color < MAXZP*2) { /* color in bytes */ \ + p->n_op = NAME; \ + p->n_lval = w->r_color/2 + ZPOFF; \ + p->n_name = ""; \ + break; \ + } \ +} + +/* + * special shapes for sp/fp. + */ +#define SLDFPSP (MAXSPECIAL+1) /* load fp or sp */ diff --git a/lang/pcc/pcc/arch/nova/order.c b/lang/pcc/pcc/arch/nova/order.c new file mode 100644 index 000000000..fa35c8fe2 --- /dev/null +++ b/lang/pcc/pcc/arch/nova/order.c @@ -0,0 +1,173 @@ +/* $Id: order.c,v 1.6 2014/06/03 20:19:50 ragge Exp $ */ +/* + * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +#include + +int canaddr(NODE *); + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + if (r != 4 && r != 5) + return 1; /* can only index ac2 and ac3 */ +#if 0 + if (t == CHAR || t == UCHAR) { + if (off < -256 || off > 254) + return 1; + } else +#endif + if (off < -128 || off > 127) + return 1; + return(0); /* YES */ +} + +/* + * Turn a UMUL-referenced node into OREG. + * Be careful about register classes, this is a place where classes change. + */ +void +offstar(NODE *p, int shape) +{ + NODE *r; + + if (x2debug) + printf("offstar(%p)\n", p); + + if (regno(p) == 4 || regno(p) == 5) + return; /* Is already OREG */ + + r = p->n_right; + if ((p->n_op == PLUS || p->n_op == MINUS) && r->n_op == ICON) { + if (!isreg(p->n_left) || + (regno(p->n_left) != 4 && regno(p->n_left) != 5)) + (void)geninsn(p->n_left, INBREG); + return; + } + (void)geninsn(p, INBREG); +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + */ +void +myormake(NODE *q) +{ + if (x2debug) + printf("myormake(%p)\n", q); +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Turns currently anything into OREG on x86 */ + if (shape & SOREG) + return SROREG; + return SRNOPE; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; +} +/* + * Set registers "live" at function calls (like arguments in registers). + * This is for liveness analysis of registers. + */ +int * +livecall(NODE *p) +{ + static int r[1] = { -1 }; /* Terminate with -1 */ + + return &r[0]; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/nova/table.c b/lang/pcc/pcc/arch/nova/table.c new file mode 100644 index 000000000..69fab4270 --- /dev/null +++ b/lang/pcc/pcc/arch/nova/table.c @@ -0,0 +1,1572 @@ +/* $Id: table.c,v 1.3 2014/06/03 20:19:50 ragge Exp $ */ +/* + * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR +# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR +# define ANYFIXED ANYSIGNED|ANYUSIGNED +# define ANYREG (INAREG|INBREG|INCREG) +# define TUWORD TUNSIGNED|TULONG +# define TSWORD TINT|TLONG +# define TWORD TUWORD|TSWORD + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* + * All ASSIGN entries. + */ +/* reg->reg */ +{ ASSIGN, FOREFF|INAREG|INBREG, + SAREG|SBREG, TWORD|TPOINT, + SAREG|SBREG, TWORD|TPOINT, + 0, RDEST, + " mov AR,AL\n", }, +/* reg->mem */ +{ ASSIGN, FOREFF|INAREG|INBREG, + SNAME|SOREG, TWORD|TPOINT, + SAREG|SBREG, TWORD|TPOINT, + 0, RDEST, + " sta AR,AL\n", }, +/* mem->reg */ +{ ASSIGN, FOREFF|INAREG|INBREG, + SAREG|SBREG, TWORD|TPOINT, + SNAME|SOREG, TWORD|TPOINT, + 0, RDEST, + " lda AL,AR\n", }, + +/* + * LEAF type movements. + */ +/* 0 -> reg */ +{ OPLTYPE, INAREG|INBREG, + SANY, TANY, + SZERO, TWORD, + NAREG, RESC1, + " subo A1,A1\n", }, + +/* 1 -> reg */ +{ OPLTYPE, INAREG|INBREG, + SANY, TANY, + SONE, TWORD, + NAREG|NBREG, RESC1, + " subzl A1,A1 # 1\n", }, + +/* constant -> reg */ +{ OPLTYPE, INAREG|INBREG, + SANY, TANY, + SCON, TWORD|TPOINT, + NAREG|NBREG, RESC1, + " lda A1,AR\n", }, + +/* mem -> reg */ +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME|SOREG, TWORD, + NAREG, RESC1, + " lda A1,AR\n", }, + +/* reg -> A-reg */ +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SBREG, TWORD, + NAREG, RESC1, + " mov AR,A1\n", }, + +/* reg -> B-reg */ +{ OPLTYPE, INBREG, + SANY, TANY, + SAREG|SBREG, TWORD, + NBREG, RESC1, + " mov AR,A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SNAME|SOREG, TPOINT, + NBREG, RESC1, + " lda A1,AR\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SLDFPSP, TANY, + NBREG, RESC1, + " lda A1,AR\n", }, + +/* + * Simple ops. + */ +{ PLUS, INBREG|INAREG, + SAREG|SBREG, TWORD|TPOINT, + SONE, TANY, + 0, RLEFT, + " inc AL,AL\n", }, + +{ OPSIMP, INBREG|INAREG|FOREFF, + SAREG|SBREG, TWORD|TPOINT, + SAREG|SBREG, TWORD|TPOINT, + 0, RLEFT, + " O AR,AL\n", }, + +/* + * Indirections + */ +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG|NASL, RESC1, + " lda A1,AL #\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " lda A1,AL #\n", }, + +{ UMUL, INBREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NBREG|NBSL, RESC1, + " lda A1,AL # #\n", }, + +#if 0 + +/* PCONVs are usually not necessary */ +{ PCONV, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + "", }, + +/* + * A bunch conversions of integral<->integral types + * There are lots of them, first in table conversions to itself + * and then conversions from each type to the others. + */ + +/* itself to itself, including pointers */ + +/* convert (u)char to (u)char. */ +{ SCONV, INCH, + SHCH, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR, + 0, RLEFT, + "", }, + +/* convert pointers to int. */ +{ SCONV, ININT, + SHINT, TPOINT|TWORD, + SANY, TWORD, + 0, RLEFT, + "", }, + +/* convert (u)longlong to (u)longlong. */ +{ SCONV, INLL, + SHLL, TLL, + SHLL, TLL, + 0, RLEFT, + "", }, + +/* convert double <-> float. nothing to do here */ +{ SCONV, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + "", }, + +/* convert pointers to pointers. */ +{ SCONV, ININT, + SHINT, TPOINT, + SANY, TPOINT, + 0, RLEFT, + "", }, + +/* char to something */ + +/* convert char to (unsigned) short. */ +{ SCONV, ININT, + SBREG|SOREG|SNAME, TCHAR, + SAREG, TSHORT|TUSHORT, + NASL|NAREG, RESC1, + " movsbw AL,A1\n", }, + +/* convert unsigned char to (u)short. */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TUCHAR, + SAREG, TSHORT|TUSHORT, + NASL|NAREG, RESC1, + " movzbw AL,A1\n", }, + +/* convert signed char to int (or pointer). */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TCHAR, + SAREG, TWORD|TPOINT, + NASL|NAREG, RESC1, + " movsbl AL,A1\n", }, + +/* convert unsigned char to (u)int. */ +{ SCONV, ININT, + SHCH|SOREG|SNAME, TUCHAR, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movzbl AL,A1\n", }, + +/* convert char to (u)long long */ +{ SCONV, INLL, + SHCH|SOREG|SNAME, TCHAR, + SANY, TLL, + NSPECIAL|NAREG|NASL, RESC1, + " movsbl AL,%eax\n cltd\n", }, + +/* convert unsigned char to (u)long long */ +{ SCONV, INLL, + SHCH|SOREG|SNAME, TUCHAR, + SANY, TLL, + NCREG|NCSL, RESC1, + " movzbl AL,A1\n xorl U1,U1\n", }, + +/* convert char (in register) to double XXX - use NTEMP */ +{ SCONV, INFL, + SHCH|SOREG|SNAME, TCHAR, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG, RESC2, + " movsbl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* convert (u)char (in register) to double XXX - use NTEMP */ +{ SCONV, INFL, + SHCH|SOREG|SNAME, TUCHAR, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG, RESC2, + " movzbl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* short to something */ + +/* convert short (in memory) to char */ +{ SCONV, INCH, + SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + " movb AL,A1\n", }, + +/* convert short (in reg) to char. */ +{ SCONV, INCH, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL|NBREG|NBSL, RESC1, + "ZM", }, + +/* convert short to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movswl AL,A1\n", }, + +/* convert unsigned short to (u)int. */ +{ SCONV, ININT, + SAREG|SOREG|SNAME, TUSHORT, + SAREG, TWORD, + NASL|NAREG, RESC1, + " movzwl AL,A1\n", }, + +/* convert short to (u)long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TSHORT, + SHLL, TLL, + NSPECIAL|NCREG|NCSL, RESC1, + " movswl AL,%eax\n cltd\n", }, + +/* convert unsigned short to (u)long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TUSHORT, + SHLL, TLL, + NCREG|NCSL, RESC1, + " movzwl AL,A1\n xorl U1,U1\n", }, + +/* convert short (in memory) to float/double */ +{ SCONV, INFL, + SOREG|SNAME, TSHORT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fild AL\n", }, + +/* convert short (in register) to float/double */ +{ SCONV, INFL, + SAREG, TSHORT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushw AL\n fild (%esp)\n addl $2,%esp\n", }, + +/* convert unsigned short to double XXX - use NTEMP */ +{ SCONV, INFL, + SAREG|SOREG|SNAME, TUSHORT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NAREG|NASL|NDREG|NTEMP, RESC2, + " movzwl AL,A1\n pushl A1\n" + " fildl (%esp)\n addl $4,%esp\n", }, + +/* int to something */ + +/* convert int to char. This is done when register is loaded */ +{ SCONV, INCH, + SAREG, TWORD, + SANY, TCHAR|TUCHAR, + NSPECIAL|NBREG|NBSL, RESC1, + "ZM", }, + +/* convert int to short. Nothing to do */ +{ SCONV, INAREG, + SAREG, TWORD, + SANY, TSHORT|TUSHORT, + 0, RLEFT, + "", }, + +/* convert int to long long */ +{ SCONV, INLL, + SAREG, TWORD|TPOINT, + SCREG, TLONGLONG, + NSPECIAL|NCREG|NCSL, RESC1, + " cltd\n", }, + +/* convert int to unsigned long long */ +{ SCONV, INLL, + SAREG|SOREG|SNAME, TWORD|TPOINT, + SHLL, TULONGLONG, + NCSL|NCREG, RESC1, + " movl AL,A1\n xorl U1,U1\n", }, + +/* convert int (in memory) to double */ +{ SCONV, INFL, + SOREG|SNAME, TWORD, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fildl AL\n", }, + +/* convert int (in register) to double */ +{ SCONV, INFL, + SAREG, TWORD, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushl AL\n fildl (%esp)\n addl $4,%esp\n", }, + +/* long long to something */ + +/* convert (u)long long to (u)char (mem->reg) */ +{ SCONV, INCH, + SOREG|SNAME, TLL, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " movb AL,A1\n", }, + +/* convert (u)long long to (u)char (reg->reg, hopefully nothing) */ +{ SCONV, INCH, + SHLL, TLL, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + "ZS", }, + +/* convert (u)long long to (u)short (mem->reg) */ +{ SCONV, INAREG, + SOREG|SNAME, TLL, + SAREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " movw AL,A1\n", }, + +/* convert (u)long long to (u)short (reg->reg, hopefully nothing) */ +{ SCONV, INAREG, + SHLL|SOREG|SNAME, TLL, + SAREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + "ZS", }, + +/* convert long long to int (mem->reg) */ +{ SCONV, INAREG, + SOREG|SNAME, TLL, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +/* convert long long to int (reg->reg, hopefully nothing) */ +{ SCONV, INAREG, + SHLL|SOREG|SNAME, TLL, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, + "ZS", }, + +/* convert long long (in memory) to floating */ +{ SCONV, INFL, + SOREG|SNAME, TLONGLONG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + " fildq AL\n", }, + +/* convert long long (in register) to floating */ +{ SCONV, INFL, + SHLL, TLONGLONG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + NTEMP|NDREG, RESC1, + " pushl UL\n pushl AL\n" + " fildq (%esp)\n addl $8,%esp\n", }, + +/* convert unsigned long long to floating */ +{ SCONV, INFL, + SCREG, TULONGLONG, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NDREG, RESC1, + "ZJ", }, + +/* float to something */ + +#if 0 /* go via int by adding an extra sconv in clocal() */ +/* convert float/double to (u) char. XXX should use NTEMP here */ +{ SCONV, INCH, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NBREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, + +/* convert float/double to (u) int/short/char. XXX should use NTEMP here */ +{ SCONV, INCH, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NCREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, +#endif + +/* convert float/double to (u)int. XXX should use NTEMP here */ +{ SCONV, INAREG, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SAREG, TWORD, + NAREG, RESC1, + " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, + +/* convert float/double (in register) to (unsigned) long long */ +/* XXX - unsigned is not handled correct */ +{ SCONV, INLL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHLL, TLONGLONG|TULONGLONG, + NCREG, RESC1, + " subl $8,%esp\n fistpq (%esp)\n" + " popl A1\n popl U1\n", }, + +/* slut sconv */ +#endif + +/* + * Subroutine calls. + */ + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " jsr CL\nZC", }, + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " jsr CL\n", }, + +{ CALL, INAREG|FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, + " jsr CL\nZC", }, + +{ UCALL, INAREG|FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, + " jsr CL\n", }, + +#if 0 +{ CALL, INAREG, + SCON, TANY, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INAREG, + SCON, TANY, + SAREG, TWORD|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " call CL\n", }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, TCHAR|TUCHAR, + NBREG, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INBREG, + SCON, TANY, + SBREG, TCHAR|TUCHAR, + NBREG, RESC1, /* should be 0 */ + " call CL\n", }, + +{ CALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INCREG, + SCON, TANY, + SCREG, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call CL\n", }, + +{ CALL, INDREG, + SCON, TANY, + SDREG, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ UCALL, INDREG, + SCON, TANY, + SDREG, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call CL\nZC", }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call *AL\nZC", }, + +{ CALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INBREG, + SAREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INCREG, + SAREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ CALL, INDREG, + SAREG, TANY, + SANY, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +{ UCALL, INDREG, + SAREG, TANY, + SANY, TANY, + NDREG|NDSL, RESC1, /* should be 0 */ + " call *AL\nZC", }, + +/* struct return */ +{ USTCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + "ZP call CL\nZC", }, + +{ USTCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call CL\nZC", }, + +{ USTCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call *AL\nZC", }, + +{ STCALL, FOREFF, + SCON, TANY, + SANY, TANY, + NAREG|NASL, 0, + "ZP call CL\nZC", }, + +{ STCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call CL\nZC", }, + +{ STCALL, INAREG, + SNAME|SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "ZP call *AL\nZC", }, + +/* + * The next rules handle all binop-style operators. + */ +/* Special treatment for long long */ +{ PLUS, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " addl AR,AL\n adcl UR,UL\n", }, + +/* Special treatment for long long XXX - fix commutative check */ +{ PLUS, INLL|FOREFF, + SHLL|SNAME|SOREG, TLL, + SHLL, TLL, + 0, RRIGHT, + " addl AL,AR\n adcl UL,UR\n", }, + +{ PLUS, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " faddl AR\n", }, + +{ PLUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " faddp\n", }, + +{ PLUS, INAREG, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SONE, TANY, + 0, RLEFT, + " incl AL\n", }, + +{ PLUS, INAREG, + SAREG, TWORD|TPOINT, + SCON, TANY, + NAREG|NASL, RESC1, + " leal CR(AL),A1\n", }, + +{ PLUS, INCH, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SONE, TANY, + 0, RLEFT, + " incb AL\n", }, + +{ PLUS, INAREG, + SAREG, TWORD, + SAREG, TWORD, + NAREG|NASL|NASR, RESC1, + " leal (AL,AR),A1\n", }, + + +/* address as register offset, negative */ +{ MINUS, INAREG, + SAREG, TWORD|TPOINT, + SPCON, TANY, + NAREG|NASL, RESC1, + " leal -CR(AL),A1\n", }, + +{ MINUS, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " subl AR,AL\n sbbl UR,UL\n", }, + +{ MINUS, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fsubl AR\n", }, + +{ MINUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fsubZAp\n", }, + +/* Simple r/m->reg ops */ +{ OPSIMP, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RLEFT, + " Ol AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SHINT, TSHORT|TUSHORT, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + 0, RLEFT, + " Ow AR,AL\n", }, + +{ OPSIMP, INCH|FOREFF, + SHCH, TCHAR|TUCHAR, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + 0, RLEFT, + " Ob AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SCON, TWORD|TPOINT, + 0, RLEFT, + " Ol AR,AL\n", }, + +{ OPSIMP, INAREG|FOREFF, + SHINT|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RLEFT, + " Ow AR,AL\n", }, + +{ OPSIMP, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT, + " Ob AR,AL\n", }, + +{ OPSIMP, INLL|FOREFF, + SHLL, TLL, + SHLL|SNAME|SOREG, TLL, + 0, RLEFT, + " Ol AR,AL\n Ol UR,UL\n", }, + + +/* + * The next rules handle all shift operators. + */ +/* (u)longlong left shift is emulated */ +{ LS, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SAREG|SNAME|SOREG|SCON, TINT, /* will be int */ + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sall AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG, TWORD, + SCON, TANY, + 0, RLEFT, + " sall AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shlw AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RLEFT, + " shlw AR,AL\n", }, + +{ LS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " salb AR,AL\n", }, + +{ LS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RLEFT, + " salb AR,AL\n", }, + +/* (u)longlong right shift is emulated */ +{ RS, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SAREG|SNAME|SOREG|SCON, TINT, /* will be int */ + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSWORD, + SCON, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " sarl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUWORD, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUWORD, + SCON, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " shrl AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SCON, TANY, + 0, RLEFT, + " sarw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrw AR,AL\n", }, + +{ RS, INAREG|FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SCON, TANY, + 0, RLEFT, + " shrw AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " sarb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SCON, TANY, + 0, RLEFT, + " sarb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SHCH, TCHAR|TUCHAR, + NSPECIAL, RLEFT, + " shrb AR,AL\n", }, + +{ RS, INCH|FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SCON, TANY, + 0, RLEFT, + " shrb AR,AL\n", }, + +/* + * The next rules takes care of assignments. "=". + */ +{ ASSIGN, FOREFF, + SHLL|SNAME|SOREG, TLL, + SCON, TANY, + 0, 0, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF|INLL, + SHLL, TLL, + SCON, TANY, + 0, RDEST, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SCON, TANY, + 0, 0, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SCON, TANY, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SCON, TANY, + 0, 0, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TSHORT|TUSHORT, + SCON, TANY, + 0, RDEST, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SCON, TANY, + 0, 0, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INCH, + SHCH, TCHAR|TUCHAR, + SCON, TANY, + 0, RDEST, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INLL, + SHLL|SNAME|SOREG, TLL, + SHLL, TLL, + 0, RDEST, + " movl AR,AL\n movl UR,UL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RDEST, + " movl AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RDEST, + " movw AR,AL\n", }, + +{ ASSIGN, FOREFF|INCH, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + SHCH, TCHAR|TUCHAR|TWORD, + 0, RDEST, + " movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SFLD, TANY, + SAREG, TANY, + NAREG, RDEST, + "ZE", }, + +{ ASSIGN, FOREFF, + SFLD, TANY, + SAREG|SNAME|SOREG|SCON, TANY, + NAREG, 0, + "ZE", }, + +{ ASSIGN, INDREG|FOREFF, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + "", }, /* This will always be in the correct register */ + +/* order of table entries is very important here! */ +{ ASSIGN, INFL, + SNAME|SOREG, TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fstt AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TLDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstpt AL\n", }, + +{ ASSIGN, INFL, + SNAME|SOREG, TDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fstl AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TDOUBLE, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstpl AL\n", }, + +{ ASSIGN, INFL, + SNAME|SOREG, TFLOAT, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RDEST, + " fsts AL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TFLOAT, + SHFL, TFLOAT|TDOUBLE|TLDOUBLE, + 0, 0, + " fstps AL\n", }, +/* end very important order */ + +{ ASSIGN, INFL|FOREFF, + SHFL, TLDOUBLE, + SHFL|SOREG|SNAME, TLDOUBLE, + 0, RDEST, + " fldt AR\n", }, + +{ ASSIGN, INFL|FOREFF, + SHFL, TDOUBLE, + SHFL|SOREG|SNAME, TDOUBLE, + 0, RDEST, + " fldl AR\n", }, + +{ ASSIGN, INFL|FOREFF, + SHFL, TFLOAT, + SHFL|SOREG|SNAME, TFLOAT, + 0, RDEST, + " flds AR\n", }, + +/* Do not generate memcpy if return from funcall */ +#if 0 +{ STASG, INAREG|FOREFF, + SOREG|SNAME|SAREG, TPTRTO|TSTRUCT, + SFUNCALL, TPTRTO|TSTRUCT, + 0, RRIGHT, + "", }, +#endif + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG|SOREG|SNAME, TPTRTO|TANY, + NSPECIAL, RRIGHT, + "ZQ", }, + +/* + * DIV/MOD/MUL + */ +/* long long div is emulated */ +{ DIV, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ DIV, INAREG, + SAREG, TSWORD, + SAREG|SNAME|SOREG, TWORD, + NSPECIAL, RDEST, + " cltd\n idivl AR\n", }, + +{ DIV, INAREG, + SAREG, TUWORD|TPOINT, + SAREG|SNAME|SOREG, TUWORD|TPOINT, + NSPECIAL, RDEST, + " xorl %edx,%edx\n divl AR\n", }, + +{ DIV, INAREG, + SAREG, TUSHORT, + SAREG|SNAME|SOREG, TUSHORT, + NSPECIAL, RDEST, + " xorl %edx,%edx\n divw AR\n", }, + +{ DIV, INCH, + SHCH, TUCHAR, + SHCH|SNAME|SOREG, TUCHAR, + NSPECIAL, RDEST, + " xorb %ah,%ah\n divb AR\n", }, + +{ DIV, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fdivl AR\n", }, + +{ DIV, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fdivZAp\n", }, + +/* (u)longlong mod is emulated */ +{ MOD, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ MOD, INAREG, + SAREG, TSWORD, + SAREG|SNAME|SOREG, TSWORD, + NAREG|NSPECIAL, RESC1, + " cltd\n idivl AR\n", }, + +{ MOD, INAREG, + SAREG, TUWORD|TPOINT, + SAREG|SNAME|SOREG, TUWORD|TPOINT, + NAREG|NSPECIAL, RESC1, + " xorl %edx,%edx\n divl AR\n", }, + +{ MOD, INAREG, + SAREG, TUSHORT, + SAREG|SNAME|SOREG, TUSHORT, + NAREG|NSPECIAL, RESC1, + " xorl %edx,%edx\n divw AR\n", }, + +{ MOD, INCH, + SHCH, TUCHAR, + SHCH|SNAME|SOREG, TUCHAR, + NBREG|NSPECIAL, RESC1, + " xorb %ah,%ah\n divb AR\n", }, + +/* (u)longlong mul is emulated */ +{ MUL, INCREG, + SCREG|SNAME|SOREG|SCON, TLL, + SCREG|SNAME|SOREG|SCON, TLL, + NSPECIAL|NCREG|NCSL|NCSR, RESC1, + "ZO", }, + +{ MUL, INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT, + " imull AR,AL\n", }, + +{ MUL, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG|SNAME|SOREG, TSHORT|TUSHORT, + 0, RLEFT, + " imulw AR,AL\n", }, + +{ MUL, INCH, + SHCH, TCHAR|TUCHAR, + SHCH|SNAME|SOREG, TCHAR|TUCHAR, + NSPECIAL, RDEST, + " imulb AR\n", }, + +{ MUL, INFL, + SHFL, TDOUBLE, + SNAME|SOREG, TDOUBLE, + 0, RLEFT, + " fmull AR\n", }, + +{ MUL, INFL, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fmulp\n", }, + +/* + * Indirection operators. + */ +{ UMUL, INLL, + SANY, TANY, + SOREG, TLL, + NCREG|NCSL, RESC1, + " movl UL,U1\n movl AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ UMUL, INCH, + SANY, TANY, + SOREG, TCHAR|TUCHAR, + NBREG|NBSL, RESC1, + " movb AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " movw AL,A1\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TLDOUBLE, + NDREG|NDSL, RESC1, + " fldt AL\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TDOUBLE, + NDREG|NDSL, RESC1, + " fldl AL\n", }, + +{ UMUL, INFL, + SANY, TANY, + SOREG, TFLOAT, + NDREG|NDSL, RESC1, + " flds AL\n", }, + +/* + * Logical/branching operators + */ + +/* Comparisions, take care of everything */ +{ OPLOG, FORCC, + SHLL|SOREG|SNAME, TLL, + SHLL, TLL, + 0, 0, + "ZD", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TWORD|TPOINT, + SCON|SAREG, TWORD|TPOINT, + 0, RESCC, + " cmpl AR,AL\n", }, + +{ OPLOG, FORCC, + SCON|SAREG, TWORD|TPOINT, + SAREG|SOREG|SNAME, TWORD|TPOINT, + 0, RESCC, + " cmpl AR,AL\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + SCON|SAREG, TANY, + 0, RESCC, + " cmpw AR,AL\n", }, + +{ OPLOG, FORCC, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + SCON|SBREG, TANY, + 0, RESCC, + " cmpb AR,AL\n", }, + +{ OPLOG, FORCC, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NSPECIAL, 0, + "ZG", }, + +{ OPLOG, FORCC, + SOREG|SNAME, TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + NSPECIAL, 0, + "ZG", }, + +#if 0 +/* Ppro and later only */ +{ OPLOG, FORCC, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + SDREG, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RESCC, + "ZA fucomip %st,%st(1)\n", }, +#endif + +{ OPLOG, FORCC, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "diediedie!", }, + +/* AND/OR/ER/NOT */ +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TWORD, + SCON|SAREG, TWORD, + 0, RLEFT, + " andl AR,AL\n", }, + +{ AND, INCREG|FOREFF, + SCREG, TLL, + SCREG|SOREG|SNAME, TLL, + 0, RLEFT, + " andl AR,AL\n andl UR,UL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TWORD, + SAREG|SOREG|SNAME, TWORD, + 0, RLEFT, + " andl AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + SCON|SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " andw AR,AL\n", }, + +{ AND, INAREG|FOREFF, + SAREG, TSHORT|TUSHORT, + SAREG|SOREG|SNAME, TSHORT|TUSHORT, + 0, RLEFT, + " andw AR,AL\n", }, + +{ AND, INBREG|FOREFF, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + SCON|SBREG, TCHAR|TUCHAR, + 0, RLEFT, + " andb AR,AL\n", }, + +{ AND, INBREG|FOREFF, + SBREG, TCHAR|TUCHAR, + SBREG|SOREG|SNAME, TCHAR|TUCHAR, + 0, RLEFT, + " andb AR,AL\n", }, +/* AND/OR/ER/NOT */ + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jmp LL\n", }, + +#ifdef GCC_COMPAT +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " jmp *AL\n", }, +#endif + +/* + * Convert LTYPE to reg. + */ +{ OPLTYPE, INLL, + SANY, TANY, + SCREG|SCON|SOREG|SNAME, TLL, + NCREG, RESC1, + " movl UL,U1\n movl AL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TWORD|TPOINT, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, + NBREG, RESC1, + " movb AL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT, + NAREG, RESC1, + " movw AL,A1\n", }, + +{ OPLTYPE, INDREG, + SANY, TLDOUBLE, + SOREG|SNAME, TLDOUBLE, + NDREG, RESC1, + " fldt AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TDOUBLE, + SOREG|SNAME, TDOUBLE, + NDREG, RESC1, + " fldl AL\n", }, + +{ OPLTYPE, INDREG, + SANY, TFLOAT, + SOREG|SNAME, TFLOAT, + NDREG, RESC1, + " flds AL\n", }, + +/* Only used in ?: constructs. The stack already contains correct value */ +{ OPLTYPE, INDREG, + SANY, TFLOAT|TDOUBLE|TLDOUBLE, + SDREG, TFLOAT|TDOUBLE|TLDOUBLE, + NDREG, RESC1, + "", }, + +/* + * Negate a word. + */ + +{ UMINUS, INCREG|FOREFF, + SCREG, TLL, + SCREG, TLL, + 0, RLEFT, + " negl AL\n adcl $0,UL\n negl UL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + " negl AL\n", }, + +{ UMINUS, INAREG|FOREFF, + SAREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RLEFT, + " negw AL\n", }, + +{ UMINUS, INBREG|FOREFF, + SBREG, TCHAR|TUCHAR, + SBREG, TCHAR|TUCHAR, + 0, RLEFT, + " negb AL\n", }, + +{ UMINUS, INFL|FOREFF, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + SHFL, TLDOUBLE|TDOUBLE|TFLOAT, + 0, RLEFT, + " fchs\n", }, + +{ COMPL, INCREG, + SCREG, TLL, + SANY, TANY, + 0, RLEFT, + " notl AL\n notl UL\n", }, + +{ COMPL, INAREG, + SAREG, TWORD, + SANY, TANY, + 0, RLEFT, + " notl AL\n", }, + +{ COMPL, INAREG, + SAREG, TSHORT|TUSHORT, + SANY, TANY, + 0, RLEFT, + " notw AL\n", }, + +{ COMPL, INBREG, + SBREG, TCHAR|TUCHAR, + SANY, TANY, + 0, RLEFT, + " notb AL\n", }, + +/* + * Arguments to functions. + */ +{ FUNARG, FOREFF, + SCON|SCREG|SNAME|SOREG, TLL, + SANY, TLL, + 0, RNULL, + " pushl UL\n pushl AL\n", }, +#endif + +{ FUNARG, FOREFF, + SAREG|SBREG, TCHAR|TUCHAR|TWORD|TPOINT, + SANY, TCHAR|TUCHAR|TWORD|TPOINT, + 0, RNULL, + " sta AL,@sp\n", }, + +#if 0 +{ FUNARG, FOREFF, + SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, RNULL, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TSHORT, + SANY, TSHORT, + NAREG, 0, + " movswl AL,ZN\n pushl ZN\n", }, + +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TUSHORT, + SANY, TUSHORT, + NAREG, 0, + " movzwl AL,ZN\n pushl ZN\n", }, + +{ FUNARG, FOREFF, + SHCH|SNAME|SOREG, TCHAR, + SANY, TCHAR, + NAREG, 0, + " movsbl AL,A1\n pushl A1\n", }, + +{ FUNARG, FOREFF, + SHCH|SNAME|SOREG, TUCHAR, + SANY, TUCHAR, + NAREG, 0, + " movzbl AL,A1\n pushl A1\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TDOUBLE, + SANY, TDOUBLE, + 0, 0, + " pushl UL\n pushl AL\n", }, + +{ FUNARG, FOREFF, + SDREG, TDOUBLE, + SANY, TDOUBLE, + 0, 0, + " subl $8,%esp\n fstpl (%esp)\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " pushl AL\n", }, + +{ FUNARG, FOREFF, + SDREG, TFLOAT, + SANY, TFLOAT, + 0, 0, + " subl $4,%esp\n fstps (%esp)\n", }, + +{ FUNARG, FOREFF, + SDREG, TLDOUBLE, + SANY, TLDOUBLE, + 0, 0, + " subl $12,%esp\n fstpt (%esp)\n", }, + +{ STARG, FOREFF, + SAREG|SOREG|SNAME|SCON, TANY, + SANY, TSTRUCT, + NSPECIAL|NAREG, 0, + "ZF", }, + +#endif + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/pdp10/README b/lang/pcc/pcc/arch/pdp10/README new file mode 100644 index 000000000..176eca77d --- /dev/null +++ b/lang/pcc/pcc/arch/pdp10/README @@ -0,0 +1,20 @@ + + +PDP10 C calling convention +-------------------------- +Register 1-7 are argument registers. Types of sizes up to 36 bits are +given in one register, two otherwise. CHAR and SHORT are given as INTs. + +If the argument that would end up in register 7 requires two registers, +it is saved on the stack instead and no more registers would end up +on the stack. + +struct return: a hidden argument containing the address of the struct +is stored as the first argument _on_the_stack_, never in register. + +struct argument: always saved on stack, and terminates the list +of arguments that are kept in registers. + +In case of debugging all arguments are saved on stack in the function. + +All variadic arguments are always saved on the stack. diff --git a/lang/pcc/pcc/arch/pdp10/code.c b/lang/pcc/pcc/arch/pdp10/code.c new file mode 100644 index 000000000..fdeede27e --- /dev/null +++ b/lang/pcc/pcc/arch/pdp10/code.c @@ -0,0 +1,204 @@ +/* $Id: code.c,v 1.42 2012/04/22 21:07:40 plunky Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + char *nextsect = NULL; /* notyet */ + static char *loctbl[] = { "text", "data", "section .rodata" }; + static int lastloc = -1; + TWORD t; + int s; + + if (sp == NULL) { + lastloc = -1; + return; + } + t = sp->stype; + s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA; + if (nextsect) { + printf(" .section %s\n", nextsect); + nextsect = NULL; + s = -1; + } else if (s != lastloc) + printf(" .%s\n", loctbl[s]); + lastloc = s; + if (sp->sclass == EXTDEF) + printf(" .globl %s\n", sp->soname); + if (sp->slevel == 0) + printf("%s:\n", sp->soname); + else + printf(LABFMT ":\n", sp->soffset); +} + +/* + * code for the end of a function + */ +void +efcode(void) +{ +} + +/* + * code for the beginning of a function; a is an array of + * indices in stab for the arguments; n is the number + */ +void +bfcode(struct symtab **sp, int cnt) +{ + NODE *p, *q; + int i, n; + + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + uerror("no struct return yet"); + } + /* recalculate the arg offset and create TEMP moves */ + for (n = 1, i = 0; i < cnt; i++) { + if (n < 8) { + p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->ssue); + q = block(REG, NIL, NIL, + sp[i]->stype, sp[i]->sdf, sp[i]->ssue); + q->n_rval = n; + p = buildtree(ASSIGN, p, q); + sp[i]->soffset = regno(p->n_left); + sp[i]->sflags |= STNODE; + ecomp(p); + } else { + sp[i]->soffset += SZINT * n; + if (xtemps) { + /* put stack args in temps if optimizing */ + p = tempnode(0, sp[i]->stype, + sp[i]->sdf, sp[i]->ssue); + p = buildtree(ASSIGN, p, nametree(sp[i])); + sp[i]->soffset = regno(p->n_left); + sp[i]->sflags |= STNODE; + ecomp(p); + } + } + n += szty(sp[i]->stype); + } +} + + +void +bjobcode(void) +{ +} + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ +} + +/* + * Make a register node, helper for funcode. + */ +static NODE * +mkreg(NODE *p, int n) +{ + NODE *r; + + r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue); + if (szty(p->n_type) == 2) + n += 16; + r->n_rval = n; + return r; +} + +static int regnum; +/* + * Move args to registers and emit expressions bottom-up. + */ +static void +fixargs(NODE *p) +{ + NODE *r; + + if (p->n_op == CM) { + fixargs(p->n_left); + r = p->n_right; + if (r->n_op == STARG) + regnum = 9; /* end of register list */ + else if (regnum + szty(r->n_type) > 8) + p->n_right = block(FUNARG, r, NIL, r->n_type, + r->n_df, r->n_sue); + else + p->n_right = buildtree(ASSIGN, mkreg(r, regnum), r); + } else { + if (p->n_op == STARG) { + regnum = 9; /* end of register list */ + } else { + r = talloc(); + *r = *p; + r = buildtree(ASSIGN, mkreg(r, regnum), r); + *p = *r; + nfree(r); + } + r = p; + } + regnum += szty(r->n_type); +} + + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + */ +NODE * +funcode(NODE *p) +{ + + regnum = 1; + + fixargs(p->n_right); + return p; +} + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} diff --git a/lang/pcc/pcc/arch/pdp10/local.c b/lang/pcc/pcc/arch/pdp10/local.c new file mode 100644 index 000000000..44a293097 --- /dev/null +++ b/lang/pcc/pcc/arch/pdp10/local.c @@ -0,0 +1,838 @@ +/* $Id: local.c,v 1.78 2014/05/29 19:20:03 plunky Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +/* this file contains code which is dependent on the target machine */ + +static int pointp(TWORD t); +static struct symtab *newfun(char *name, TWORD type); + +#define PTRNORMAL 1 +#define PTRCHAR 2 +#define PTRSHORT 3 +static int xptype(TWORD t); + +NODE * +clocal(NODE *p) +{ + /* this is called to do local transformations on + an expression tree preparitory to its being + written out in intermediate code. + */ + + /* the major essential job is rewriting the + automatic variables and arguments in terms of + REG and OREG nodes */ + /* conversion ops which are not necessary are also clobbered here */ + /* in addition, any special features (such as rewriting + exclusive or) are easily handled here as well */ + + register struct symtab *q; + register NODE *r, *l, *oop; + register int o; + register int m, ml; + int siz; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + + switch( o = p->n_op ){ + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + /* First 7 parameters are in registers */ + /* XXX last may be double */ + if (q->soffset/SZINT < 7) { + p->n_op = REG; + p->n_rval = q->soffset/SZINT; + break; + } else + q->soffset -= 7*SZINT; + + case AUTO: + /* fake up a structure reference */ + if (q->stype == CHAR || q->stype == UCHAR || + q->stype == SHORT || q->stype == USHORT) + r = block(REG, NIL, NIL, PTR+q->stype, 0, 0); + else + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + r->n_lval = 0; + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case STATIC: + if (q->slevel == 0) + break; + p->n_lval = 0; + break; + + case REGISTER: + p->n_op = REG; + p->n_lval = 0; + p->n_rval = q->soffset; + break; + + } + break; + + case CALL: + /* avoid recursive calls */ + r = tempnode(0, p->n_type, p->n_df, p->n_sue); + l = tempnode(regno(r), p->n_type, p->n_df, p->n_sue); + ecomp(buildtree(ASSIGN, r, p)); + p = l; + break; + + case PCONV: + l = p->n_left; + /* + * Handle frame pointer directly without conversion, + * for efficiency. + */ + if (l->n_op == REG && l->n_rval == 0) { +rmpc: l->n_type = p->n_type; + l->n_df = p->n_df; + l->n_sue = p->n_sue; + nfree(p); + return l; + } + /* Convert ICON with name to new type */ + if (l->n_op == ICON && l->n_sp != NULL && + l->n_type == INCREF(STRTY) && + (p->n_type == INCREF(CHAR) || + p->n_type == INCREF(UCHAR) || + p->n_type == INCREF(SHORT) || + p->n_type == INCREF(USHORT))) { + l->n_lval *= (BTYPE(p->n_type) == CHAR || + BTYPE(p->n_type) == UCHAR ? 4 : 2); + goto rmpc; + } + /* Convert only address constants, never convert other */ + if (l->n_op == ICON) { + if (l->n_sp == NULL) + goto rmpc; + if (p->n_type == INCREF(CHAR) || + p->n_type == INCREF(UCHAR) || + p->n_type == INCREF(VOID)) + l->n_lval = (l->n_lval & 07777777777) | + 0700000000000LL; + else if (p->n_type == INCREF(SHORT) || + p->n_type == INCREF(USHORT)) + l->n_lval = (l->n_lval & 07777777777) | + 0750000000000LL; + else + l->n_lval = l->n_lval & 07777777777; + goto rmpc; + } + + /* Remove more conversions of identical pointers */ + /* Be careful! optim() may do bad things */ + if (ISPTR(DECREF(p->n_type))) { + if (ISPTR(DECREF(l->n_type))) { + if ((coptype(l->n_op) == UTYPE || + coptype(l->n_op) == BITYPE) && + (l->n_left->n_op == REG)) + l->n_left->n_type = p->n_type; + goto rmpc; + } + } + + /* Change PCONV from int to double pointer to right shift */ + if (ISPTR(p->n_type) && ISPTR(DECREF(p->n_type)) && + (l->n_type == INT || l->n_type == UNSIGNED)) { + p->n_op = RS; + p->n_right = bcon(2); + break; + } + + /* Check for cast integral -> pointer */ + if (BTYPE(l->n_type) == l->n_type) + break; + + /* Remove conversions to identical pointers */ + switch (xptype(p->n_type)) { + case PTRNORMAL: + if (xptype(l->n_type) == PTRNORMAL) + goto rmpc; + break; + + case PTRSHORT: + if (xptype(l->n_type) == PTRSHORT) + goto rmpc; + break; + + case PTRCHAR: + if (xptype(l->n_type) == PTRCHAR) + goto rmpc; + break; + } + + break; + + case SCONV: + l = p->n_left; + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + btdims[p->n_type].suesize == btdims[l->n_type].suesize) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE) { + nfree(p); + return l; + } + } + /* cast to (void) XXX should be removed in MI code */ + if (p->n_type == VOID) { + nfree(p); + return l; + } + m = p->n_type; + ml = l->n_type; + if (m == ml) { + nfree(p); + return l; + } + o = l->n_op; + if (ml == FLOAT || ml == DOUBLE) { + if (o != FCON) + break; + ml = ISUNSIGNED(m) ? UNSIGNED : INT; /* LONG? */ + r = xbcon(ml == INT ? (int)p->n_left->n_dcon : + (unsigned)p->n_left->n_dcon, + NULL, ml); + nfree(p->n_left); + p->n_left = r; + o = ICON; + if (m == ml) { + r = p->n_left; + nfree(p); + return r; + } + } + if (o == ICON) { + CONSZ val = l->n_lval; + + switch (m) { + case CHAR: + l->n_lval = val & 0777; + if (val & 0400) + l->n_lval |= ~((CONSZ)0777); + break; + case UCHAR: + l->n_lval = val & 0777; + break; + case USHORT: + l->n_lval = val & 0777777; + break; + case SHORT: + l->n_lval = val & 0777777; + if (val & 0400000) + l->n_lval |= ~((CONSZ)0777777); + break; + case UNSIGNED: + l->n_lval = val & 0777777777777LL; + break; + case INT: + l->n_lval = val & 0777777777777LL; + if (val & 0400000000000LL) + l->n_lval |= ~(0777777777777LL); + break; + case LONGLONG: /* XXX */ + case ULONGLONG: + l->n_lval = val; + break; + case VOID: + break; + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = 0; + break; + default: + cerror("unknown type %d", m); + } + l->n_type = m; + l->n_sue = 0; + nfree(p); + return l; + } + break; + + case PMCONV: + case PVCONV: +/* if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); */ + nfree(p); + return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right)); + + case RS: + case RSEQ: + /* convert >> to << with negative shift count */ + /* Beware! constant shifts will be converted back in optim() */ + + if (p->n_right->n_op != UMINUS) { + p->n_right = buildtree(UMINUS, p->n_right, NIL); + } else { + r = p->n_right; + p->n_right = p->n_right->n_left; + nfree(r); + } + if (p->n_op == RS) + p->n_op = LS; + else + p->n_op = LSEQ; + break; + + case UMUL: /* Convert structure assignment to memcpy() */ + if (p->n_left->n_op == PLUS && + p->n_left->n_left->n_op == PCONV && + p->n_left->n_right->n_op == ICON && + (p->n_type == CHAR || p->n_type == UCHAR || + p->n_type == SHORT || p->n_type == USHORT)) { + /* Can remove the left SCONV */ + l = p->n_left->n_left; + p->n_left->n_left = l->n_left; + nfree(l); + break; + + } + if (p->n_left->n_op != STASG) + break; + oop = p; + p = p->n_left; + siz = p->n_sue->suesize/SZCHAR; + l = p->n_left; + r = p->n_right; + if (l->n_type == STRTY || l->n_type == UNIONTY) { + if (l->n_op == UMUL) { + p->n_left = l->n_left; + nfree(l); + l = p->n_left; + } else { + l = block(ADDROF, l, NIL, INCREF(l->n_type), + 0, 0); + } + } + if ((l->n_type != (STRTY+PTR) && l->n_type != (UNIONTY+PTR)) || + (r->n_type != (STRTY+PTR) && r->n_type != (UNIONTY+PTR))) + cerror("bad stasg, l = %o, r = %o", l->n_type, r->n_type); + q = newfun("__structcpy", p->n_type); + + /* structure pointer block */ + l = block(CM, l, r, INT, 0, 0); + /* Size block */ + r = block(CM, l, bcon(siz), INT, 0, 0); + + l = xbcon(0, q, q->stype); + p->n_left = l; + p->n_right = r; + p->n_op = CALL; + oop->n_left = p; + return oop; + + case FORCE: + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + p->n_left->n_rval = RETREG(p->n_type); + break; + + } + + return(p); +} + +void +myp2tree(NODE *p) +{ + NODE *r; + + switch (p->n_op) { + case ULT: /* exor sign bit to avoid unsigned comparitions */ + case ULE: + case UGT: + case UGE: + if (ISLONGLONG(p->n_left->n_type)) { + /* XXX */ + r = xbcon(0x8000000000000000ULL, NULL, LONGLONG); + } else + r = xbcon(0400000000000LL, NULL, INT); + p->n_left = buildtree(ER, p->n_left, r); + if (ISUNSIGNED(p->n_left->n_type)) + p->n_left->n_type = DEUNSIGN(p->n_left->n_type); + + if (ISLONGLONG(p->n_right->n_type)) { + /* XXX */ + r = xbcon(0x8000000000000000ULL, NULL, LONGLONG); + } else + r = xbcon(0400000000000LL, NULL, INT); + p->n_right = buildtree(ER, p->n_right, r); + if (ISUNSIGNED(p->n_right->n_type)) + p->n_right->n_type = DEUNSIGN(p->n_right->n_type); + + p->n_op -= (ULT-LT); + break; + case FCON: + cerror("fix float constants"); + } +} + + +struct symtab * +newfun(char *name, TWORD type) +{ + struct symtab *sp; + + sp = lookup(name, 0); + if (sp->stype == VOID) { + sp->stype = INCREF(type | FTN); + sp->sclass = EXTERN; + sp->soffset = 0; + } +#ifdef notdef + else if (!ISFTN(DECREF(sp->stype))) + uerror("reserved name '%s' used illegally", name); +#endif + return sp; +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * is an automatic variable of type t OK for a register variable + * Everything is trusted to be in register here. + */ +int +cisreg(TWORD t) +{ + return(1); +} + +int +xptype(TWORD t) +{ + int tt = BTYPE(t); + int e, rv; + + if (!ISPTR(t)) + cerror("not a pointer"); + + e = t & ~BTMASK; + rv = e; + while (e) { + rv = e; + if (DECREF(e) == 0) + break; + e = DECREF(e); + } + if (ISFTN(rv)) + return PTRNORMAL; + + switch (tt) { + case INT: + case LONG: + case LONGLONG: + case FLOAT: + case DOUBLE: + case STRTY: + case UNIONTY: + case UNSIGNED: + case ULONG: + case ULONGLONG: + return PTRNORMAL; + case VOID: + case CHAR: + case UCHAR: + if (DECREF(t) == tt || ISARY(rv)) + return PTRCHAR; + return PTRNORMAL; + case SHORT: + case USHORT: + if (DECREF(t) == tt || ISARY(rv)) + return PTRSHORT; + return PTRNORMAL; + default: + break; + } + cerror("unknown type"); + return PTRNORMAL; /* XXX */ +} + +/* + * Help routine to the one below; return true if it's not a word pointer. + */ +static int +pointp(TWORD t) +{ + int rv = 0; + + if (ISPTR(t) && ((t & TMASK1) == 0)) + return 1; + + t &= ~BTMASK; + while (t) { + rv = ISARY(t); + t = DECREF(t); + } + return rv; +} + +/* + * return a node, for structure references, which is suitable for + * being added to a pointer of type t, in order to be off bits offset + * into a structure + * t, d, and s are the type, dimension offset, and sizeoffset + * For pdp10, return the type-specific index number which calculation + * is based on its size. For example, short a[3] would return 3. + * Be careful about only handling first-level pointers, the following + * indirections must be fullword. + */ +NODE * +offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue) +{ + register NODE *p; + + if (xdebug) + printf("offcon: OFFSZ %lld type %x dim %p siz %d\n", + off, t, d, sue->suesize); + + p = bcon(0); + p->n_lval = off/SZINT; /* Default */ + if (ISPTR(DECREF(t))) + return p; /* Pointer/pointer reference */ + switch (BTMASK & t) { + case INT: + case UNSIGNED: + case LONG: + case ULONG: + case STRTY: + case UNIONTY: + case LONGLONG: + case ULONGLONG: + case FLOAT: + case DOUBLE: + break; + + case SHORT: + case USHORT: + if (pointp(t)) + p->n_lval = off/SZSHORT; + break; + + case VOID: /* void pointers */ + case CHAR: + case UCHAR: + if (pointp(t)) + p->n_lval = off/SZCHAR; + break; + + default: + cerror("offcon, off %llo size %d type %x", off, sue->suesize, t); + } + if (xdebug) + printf("offcon return 0%llo\n", p->n_lval); + return(p); +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a NAME node where to write + * the allocated address. + * Be aware that a pointer conversion may be needed when saving + * to node t! + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + if ((off % SZINT) == 0) + p = buildtree(MUL, p, bcon(off/SZINT)); + else if ((off % SZSHORT) == 0) { + p = buildtree(MUL, p, bcon(off/SZSHORT)); + p = buildtree(PLUS, p, bcon(1)); + p = buildtree(RS, p, bcon(1)); + } else if ((off % SZCHAR) == 0) { + p = buildtree(MUL, p, bcon(off/SZCHAR)); + p = buildtree(PLUS, p, bcon(3)); + p = buildtree(RS, p, bcon(2)); + } else + cerror("roundsp"); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); + sp->n_lval = 0; + sp->n_rval = STKREG; + /* Cast sp to destination type (may be redundant) */ + sp = buildtree(CAST, + block(NAME, NIL, NIL, t->n_type, t->n_df, t->n_sue), sp); + nfree(sp->n_left); + nfree(sp); + sp = sp->n_right; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + + /* add the size to sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(PLUSEQ, sp, p)); +} + +#if 0 +static int inwd; /* current bit offsed in word */ +static CONSZ word; /* word being built from fields */ + +/* + * Generate initialization code for assigning a constant c + * to a field of width sz + * we assume that the proper alignment has been obtained + * inoff is updated to have the proper final value + * we also assume sz < SZINT + */ +void +incode(NODE *p, int sz) +{ + char *s; + + inoff += sz; + if ((sz + inwd) > SZINT) + cerror("incode: field > int"); + + word |= ((p->n_lval & ((1 << sz) - 1)) << (36 - inwd - sz)); + + inwd += sz; + if (inoff % SZINT == 0) { + s = isinlining ? permalloc(30) : tmpalloc(30); + sprintf(s, "\t.long 0%llo\n", word); + send_passt(IP_ASM, s); + word = inwd = 0; + } + tfree(p); +} + +/* output code to initialize space of size sz to the value d */ +/* the proper alignment has been obtained */ +/* inoff is updated to have the proper final value */ +/* on the target machine, write it out in octal! */ +void +fincode(NODE *p, int sz) +{ + double d = p->n_dcon; + + if(!nerrors) + printf(" %s 0%c%.20e\n", + sz == SZDOUBLE ? ".double" : ".float", + sz == SZDOUBLE ? 'd' : 'f', d); + inoff += sz; +} + +void +cinit(NODE *p, int sz) +{ + NODE *l; + + /* + * as a favor (?) to people who want to write + * int i = 9600/134.5; + * we will, under the proper circumstances, do + * a coercion here. + */ + switch (p->n_type) { + case INT: + case UNSIGNED: + l = p->n_left; + if (l->n_op != SCONV || l->n_left->n_op != FCON) + break; + nfree(l); + l = l->n_left; + l->n_lval = (long)(l->n_dcon); + l->n_sp = NULL; + l->n_op = ICON; + l->n_type = INT; + p->n_left = l; + break; + } + /* arrange for the initialization of p into a space of size sz */ + /* the proper alignment has been opbtained */ + /* inoff is updated to have the proper final value */ + ecode( p ); + inoff += sz; +} + +/* + * define n bits of zeros in a vfd + */ +void +vfdzero(int n) +{ + char *s; + + inoff += n; + inwd += n; + if (inoff%ALINT ==0) { + s = isinlining ? permalloc(30) : tmpalloc(30); + sprintf(s, "\t.long 0%llo\n", word); + send_passt(IP_ASM, s); + word = inwd = 0; + } +} +#endif + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ + if (p == NULL) + return ""; + return p; +} + +/* + * map types which are not defined on the local machine + */ +TWORD +ctype(TWORD type) +{ + switch (BTYPE(type)) { + case LONG: + MODTYPE(type,INT); + break; + case ULONG: + MODTYPE(type,UNSIGNED); + break; + case LDOUBLE: + MODTYPE(type,DOUBLE); + break; + } + return (type); +} + +/* curid is a variable which is defined but + * is not initialized (and not a function ); + * This routine returns the stroage class for an uninitialized declaration + */ +int +noinit() +{ + return(EXTERN); +} + +void +calldec(NODE *p, NODE *q) +{ +} + +void +extdec(struct symtab *q) +{ +} + +/* make a common declaration for id, if reasonable */ +void +defzero(struct symtab *sp) +{ + int off; + + off = tsize(sp->stype, sp->sdf, sp->ssue); + off = (off+(SZINT-1))/SZINT; + printf(" .%scomm ", sp->sclass == STATIC ? "l" : ""); + if (sp->slevel == 0) + printf("%s,0%o\n", exname(sp->soname), off); + else + printf(LABFMT ",0%o\n", sp->soffset, off); +} + +/* + * set fsz bits in sequence to zero. + */ +void +zbits(OFFSZ off, int fsz) +{ + cerror("zbits"); +} + +/* + * Initialize a bitfield. + */ +void +infld(CONSZ off, int fsz, CONSZ val) +{ +// if (idebug) +// printf("infld off %lld, fsz %d, val %lld inbits %d\n", +// off, fsz, val, inbits); + cerror("infld"); +} + +/* + * print out a constant node, may be associated with a label. + * Do not free the node after use. + * off is bit offset from the beginning of the aggregate + * fsz is the number of bits this is referring to + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ + cerror("ninval"); +} + + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + return 0; +} + +/* + * Called when a identifier has been declared, to give target last word. + */ +void +fixdef(struct symtab *sp) +{ +} + +void +pass1_lastchance(struct interpass *ip) +{ +} + diff --git a/lang/pcc/pcc/arch/pdp10/local2.c b/lang/pcc/pcc/arch/pdp10/local2.c new file mode 100644 index 000000000..e5a2cde94 --- /dev/null +++ b/lang/pcc/pcc/arch/pdp10/local2.c @@ -0,0 +1,1321 @@ +/* $Id: local2.c,v 1.106 2015/01/04 19:17:23 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" +# include + +void acon(FILE *, NODE *p); +int argsize(NODE *p); +void genargs(NODE *p); + +static int offlab; +int offarg; +static int addto; +static int regoff[16]; + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +void +prologue(struct interpass_prolog *ipp) +{ + int i, j; + + if (ipp->ipp_vis) + printf(" .globl %s\n", ipp->ipp_name); + printf("%s:\n", ipp->ipp_name); + addto = p2maxautooff; + if (addto >= AUTOINIT/SZCHAR) + addto -= AUTOINIT/SZCHAR; + addto /= SZINT/SZCHAR; /* use words here */ + printf(" push %s,%s\n",rnames[STKREG], rnames[FPREG]); + printf(" move %s,%s\n", rnames[FPREG],rnames[STKREG]); + + for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) { + if (i & 1) + regoff[j] = addto++; + } + if (addto) + printf(" addi %s,0%o\n", rnames[STKREG], addto); + + for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) { + if (i & 1) + printf(" movem %s,%d(%s)\n", + rnames[j], regoff[j], rnames[STKREG]); + } +} + +void +eoftn(struct interpass_prolog *ipp) +{ + int i, j; + + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + for (i = ipp->ipp_regs[0], j = 0; i ; i >>= 1, j++) { + if (i & 1) + printf(" move %s,%d(%s)\n", + rnames[j], regoff[j], rnames[STKREG]); + } + printf(" move %s,%s\n", rnames[STKREG], rnames[FPREG]); + printf(" pop %s,%s\n", rnames[STKREG], rnames[FPREG]); + printf(" popj %s,\n", rnames[STKREG]); +} + +#if 0 +void +prologue(int regs, int autos) +{ + int i, addto; + + offlab = getlab2(); + if (regs < 0 || autos < 0) { + /* + * non-optimized code, jump to epilogue for code generation. + */ + ftlab1 = getlab2(); + ftlab2 = getlab2(); + printf(" jrst L%d\n", ftlab1); + printf("L%d:\n", ftlab2); + } else { + /* + * We here know what register to save and how much to + * add to the stack. + */ + autos = autos + (SZINT-1); + addto = (autos - AUTOINIT)/SZINT + (MAXRVAR-regs); + if (addto || gflag) { + printf(" push %s,%s\n",rnames[017], rnames[016]); + printf(" move %s,%s\n", rnames[016],rnames[017]); + for (i = regs; i < MAXRVAR; i++) { + int db = ((i+1) < MAXRVAR); + printf(" %smovem %s,0%o(%s)\n", + db ? "d" : "", + rnames[i+1], i+1-regs, rnames[016]); + if (db) + i++; + } + if (addto) + printf(" addi %s,0%o\n", rnames[017], addto); + } else + offarg = 1; + } +} + +/* + * End of block. + */ +void +eoftn(int regs, int autos, int retlab) +{ + register OFFSZ spoff; /* offset from stack pointer */ + int i; + + spoff = autos + (SZINT-1); + if (spoff >= AUTOINIT) + spoff -= AUTOINIT; + spoff /= SZINT; + /* return from function code */ + printf("L%d:\n", retlab); + if (gflag || isoptim == 0 || autos != AUTOINIT || regs != MAXRVAR) { + for (i = regs; i < MAXRVAR; i++) { + int db = ((i+1) < MAXRVAR); + printf(" %smove %s,0%o(%s)\n", db ? "d" : "", + rnames[i+1], i+1-regs, rnames[016]); + if (db) + i++; + } + printf(" move %s,%s\n", rnames[017], rnames[016]); + printf(" pop %s,%s\n", rnames[017], rnames[016]); + } + printf(" popj %s,\n", rnames[017]); + + /* Prolog code */ + if (isoptim == 0) { + printf("L%d:\n", ftlab1); + printf(" push %s,%s\n", rnames[017], rnames[016]); + printf(" move %s,%s\n", rnames[016], rnames[017]); + for (i = regs; i < MAXRVAR; i++) { + int db = ((i+1) < MAXRVAR); + printf(" %smovem %s,0%o(%s)\n", db ? "d" : "", + rnames[i+1], i+1-regs, rnames[016]); + spoff++; + if (db) + i++, spoff++; + } + if (spoff) + printf(" addi %s,0%llo\n", rnames[017], spoff); + printf(" jrst L%d\n", ftlab2); + } + printf(" .set " LABFMT ",0%o\n", offlab, MAXRVAR-regs); + offarg = isoptim = 0; +} +#endif + +/* + * add/sub/... + * + * Param given: + * R - Register + * M - Memory + * C - Constant + */ +void +hopcode(int f, int o) +{ + cerror("hopcode: f %d %d", f, o); +} + +char * +rnames[] = { /* keyed to register number tokens */ + "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", + "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", + "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", + "%10", "%11", "%12", "%13", "%14", "%15", +}; + +int +tlen(p) NODE *p; +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + cerror("tlen type %d not pointer"); + return SZPOINT(0)/SZCHAR; + } +} + +static char * +binskip[] = { + "e", /* jumpe */ + "n", /* jumpn */ + "le", /* jumple */ + "l", /* jumpl */ + "ge", /* jumpge */ + "g", /* jumpg */ +}; + +/* + * Extract the higher 36 bits from a longlong. + */ +static CONSZ +gethval(CONSZ lval) +{ + CONSZ hval = (lval >> 35) & 03777777777LL; + + if ((hval & 03000000000LL) == 03000000000LL) { + hval |= 0777000000000LL; + } else if ((hval & 03000000000LL) == 02000000000LL) { + hval &= 01777777777LL; + hval |= 0400000000000LL; + } + return hval; +} + +/* + * Do a binary comparision, and jump accordingly. + */ +static void +twocomp(NODE *p) +{ + int o = p->n_op; + extern int negrel[]; + int isscon = 0, iscon = p->n_right->n_op == ICON; + + if (o < EQ || o > GT) + cerror("bad binary conditional branch: %s", opst[o]); + + if (iscon && p->n_right->n_name[0] != 0) { + printf(" cam%s ", binskip[negrel[o-EQ]-EQ]); + adrput(stdout, getlr(p, 'L')); + putchar(','); + printf("[ .long "); + adrput(stdout, getlr(p, 'R')); + putchar(']'); + printf("\n jrst L%d\n", p->n_label); + return; + } + if (iscon) + isscon = p->n_right->n_lval >= 0 && + p->n_right->n_lval < 01000000; + + printf(" ca%c%s ", iscon && isscon ? 'i' : 'm', + binskip[negrel[o-EQ]-EQ]); + adrput(stdout, getlr(p, 'L')); + putchar(','); + if (iscon && (isscon == 0)) { + printf("[ .long "); + adrput(stdout, getlr(p, 'R')); + putchar(']'); + } else + adrput(stdout, getlr(p, 'R')); + printf("\n jrst L%d\n", p->n_label); +} + +/* + * Compare byte/word pointers. + * XXX - do not work for highest bit set in address + */ +static void +ptrcomp(NODE *p) +{ + printf(" rot "); adrput(stdout, getlr(p, 'L')); printf(",6\n"); + printf(" rot "); adrput(stdout, getlr(p, 'R')); printf(",6\n"); + twocomp(p); +} + +/* + * Do a binary comparision of two long long, and jump accordingly. + * XXX - can optimize for constants. + */ +static void +twollcomp(NODE *p) +{ + int o = p->n_op; + int iscon = p->n_right->n_op == ICON; + int m = 0; /* XXX gcc */ + + if (o < EQ || o > GT) + cerror("bad long long conditional branch: %s", opst[o]); + + /* Special strategy for equal/not equal */ + if (o == EQ || o == NE) { + if (o == EQ) + m = getlab2(); + printf(" came "); + upput(getlr(p, 'L'), SZLONG); + putchar(','); + if (iscon) + printf("[ .long "); + upput(getlr(p, 'R'), SZLONG); + if (iscon) + putchar(']'); + printf("\n jrst L%d\n", o == EQ ? m : p->n_label); + printf(" cam%c ", o == EQ ? 'n' : 'e'); + adrput(stdout, getlr(p, 'L')); + putchar(','); + if (iscon) + printf("[ .long "); + adrput(stdout, getlr(p, 'R')); + if (iscon) + putchar(']'); + printf("\n jrst L%d\n", p->n_label); + if (o == EQ) + printf("L%d:\n", m); + return; + } + /* First test highword */ + printf(" cam%ce ", o == GT || o == GE ? 'l' : 'g'); + adrput(stdout, getlr(p, 'L')); + putchar(','); + if (iscon) + printf("[ .long "); + adrput(stdout, getlr(p, 'R')); + if (iscon) + putchar(']'); + printf("\n jrst L%d\n", p->n_label); + + /* Test equality */ + printf(" came "); + adrput(stdout, getlr(p, 'L')); + putchar(','); + if (iscon) + printf("[ .long "); + adrput(stdout, getlr(p, 'R')); + if (iscon) + putchar(']'); + printf("\n jrst L%d\n", m = getlab2()); + + /* Test lowword. Only works with pdp10 format for longlongs */ + printf(" cam%c%c ", o == GT || o == GE ? 'l' : 'g', + o == LT || o == GT ? 'e' : ' '); + upput(getlr(p, 'L'), SZLONG); + putchar(','); + if (iscon) + printf("[ .long "); + upput(getlr(p, 'R'), SZLONG); + if (iscon) + putchar(']'); + printf("\n jrst L%d\n", p->n_label); + printf("L%d:\n", m); +} + +/* + * Print the correct instruction for constants. + */ +static void +constput(NODE *p) +{ + CONSZ val = p->n_right->n_lval; + int reg = p->n_left->n_rval; + + /* Only numeric constant */ + if (p->n_right->n_name[0] == '\0') { + if (val == 0) { + printf("movei %s,0", rnames[reg]); + } else if ((val & 0777777000000LL) == 0) { + printf("movei %s,0%llo", rnames[reg], val); + } else if ((val & 0777777) == 0) { + printf("hrlzi %s,0%llo", rnames[reg], val >> 18); + } else { + printf("move %s,[ .long 0%llo]", rnames[reg], + szty(p->n_right->n_type) > 1 ? val : + val & 0777777777777LL); + } + /* Can have more tests here, hrloi etc */ + return; + } else { + printf("xmovei %s,%s", rnames[reg], p->n_right->n_name); + if (val) + printf("+" CONFMT, val); + } +} + +/* + * Return true if the constant can be bundled in an instruction (immediate). + */ +static int +oneinstr(NODE *p) +{ + if (p->n_name[0] != '\0') + return 0; + if ((p->n_lval & 0777777000000ULL) != 0) + return 0; + return 1; +} + +/* + * Emit a halfword or byte instruction, from OREG to REG. + * Sign extension must also be done here. + */ +static void +emitshort(NODE *p) +{ + CONSZ off = p->n_lval; + TWORD type = p->n_type; + int reg = p->n_rval; + int issigned = !ISUNSIGNED(type); + int ischar = type == CHAR || type == UCHAR; + int reg1 = getlr(p, '1')->n_rval; + + if (off < 0) { /* argument, use move instead */ + printf(" move "); + } else if (off == 0 && p->n_name[0] == 0) { + printf(" ldb %s,%s\n", rnames[reg1], rnames[reg]); + /* XXX must sign extend here even if not necessary */ + switch (type) { + case CHAR: + printf(" lsh %s,033\n", rnames[reg1]); + printf(" ash %s,-033\n", rnames[reg1]); + break; + case SHORT: + printf(" hrre %s,%s\n", + rnames[reg1], rnames[reg1]); + break; + } + return; + } else if (ischar) { + if (off >= 0700000000000LL && p->n_name[0] != '\0') { + cerror("emitsh"); + /* reg contains index integer */ +// if (!istreg(reg)) +// cerror("emitshort !istreg"); + printf(" adjbp %s,[ .long 0%llo+%s ]\n", + rnames[reg], off, p->n_name); + printf(" ldb "); + adrput(stdout, getlr(p, '1')); + printf(",%s\n", rnames[reg]); + goto signe; + } + printf(" ldb "); + adrput(stdout, getlr(p, '1')); + if (off) + printf(",[ .long 0%02o11%02o%06o ]\n", + (int)(27-(9*(off&3))), reg, (int)off/4); + else + printf(",%s\n", rnames[reg]); +signe: if (issigned) { + printf(" lsh "); + adrput(stdout, getlr(p, '1')); + printf(",033\n ash "); + adrput(stdout, getlr(p, '1')); + printf(",-033\n"); + } + return; + } else { + printf(" h%cr%c ", off & 1 ? 'r' : 'l', + issigned ? 'e' : 'z'); + } + p->n_lval /= (ischar ? 4 : 2); + adrput(stdout, getlr(p, '1')); + putchar(','); + adrput(stdout, getlr(p, 'L')); + putchar('\n'); +} + +/* + * Store a short from a register. Destination is a OREG. + */ +static void +storeshort(NODE *p) +{ + NODE *l = p->n_left; + CONSZ off = l->n_lval; + int reg = l->n_rval; + int ischar = BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR; + + if (l->n_op == NAME) { + if (ischar) { + printf(" dpb "); + adrput(stdout, getlr(p, 'R')); + printf(",[ .long 0%02o%010o+%s ]\n", + 070+((int)off&3), (int)(off/4), l->n_name); + return; + } + printf(" hr%cm ", off & 1 ? 'r' : 'l'); + l->n_lval /= 2; + adrput(stdout, getlr(p, 'R')); + putchar(','); + adrput(stdout, getlr(p, 'L')); + putchar('\n'); + return; + } + + if (off || reg == FPREG) { /* Can emit halfword instructions */ + if (off < 0) { /* argument, use move instead */ + printf(" movem "); + } else if (ischar) { + printf(" dpb "); + adrput(stdout, getlr(p, '1')); + printf(",[ .long 0%02o11%02o%06o ]\n", + (int)(27-(9*(off&3))), reg, (int)off/4); + return; + } else { + printf(" hr%cm ", off & 1 ? 'r' : 'l'); + } + l->n_lval /= 2; + adrput(stdout, getlr(p, 'R')); + putchar(','); + adrput(stdout, getlr(p, 'L')); + } else { + printf(" dpb "); + adrput(stdout, getlr(p, 'R')); + putchar(','); + l = getlr(p, 'L'); + l->n_op = REG; + adrput(stdout, l); + l->n_op = OREG; + } + putchar('\n'); +} + +/* + * Multiply a register with a constant. + */ +static void +imuli(NODE *p) +{ + NODE *r = p->n_right; + + if (r->n_lval >= 0 && r->n_lval <= 0777777) { + printf(" imuli "); + adrput(stdout, getlr(p, 'L')); + printf(",0%llo\n", r->n_lval); + } else { + printf(" imul "); + adrput(stdout, getlr(p, 'L')); + printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL); + } +} + +/* + * Divide a register with a constant. + */ +static void +idivi(NODE *p) +{ + NODE *r = p->n_right; + + if (r->n_lval >= 0 && r->n_lval <= 0777777) { + printf(" idivi "); + adrput(stdout, getlr(p, '1')); + printf(",0%llo\n", r->n_lval); + } else { + printf(" idiv "); + adrput(stdout, getlr(p, '1')); + printf(",[ .long 0%llo ]\n", r->n_lval & 0777777777777LL); + } +} + +/* + * move a constant into a register. + */ +static void +xmovei(NODE *p) +{ + /* + * Trick: If this is an unnamed constant, just move it directly, + * otherwise use xmovei to get section number. + */ + if (p->n_name[0] == '\0' || p->n_lval > 0777777) { + printf(" "); + zzzcode(p, 'D'); + putchar(' '); + adrput(stdout, getlr(p, '1')); + putchar(','); + zzzcode(p, 'E'); + } else { + printf(" xmovei "); + adrput(stdout, getlr(p, '1')); + printf(",%s", p->n_name); + if (p->n_lval != 0) + printf("+0%llo", p->n_lval); + } + putchar('\n'); +} + +static void +printcon(NODE *p) +{ + CONSZ cz; + + p = p->n_left; + if (p->n_lval >= 0700000000000LL) { + /* converted to pointer in clocal() */ + conput(stdout, p); + return; + } + if (p->n_lval == 0 && p->n_name[0] == '\0') { + putchar('0'); + return; + } + if (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR) + cz = (p->n_lval/4) | ((p->n_lval & 3) << 30); + else + cz = (p->n_lval/2) | (((p->n_lval & 1) + 5) << 30); + cz |= 0700000000000LL; + printf("0%llo", cz); + if (p->n_name[0] != '\0') + printf("+%s", p->n_name); +} + +static void +putcond(NODE *p) +{ + char *c = 0; /* XXX gcc */ + + switch (p->n_op) { + case EQ: c = "e"; break; + case NE: c = "n"; break; + case LE: c = "le"; break; + case LT: c = "l"; break; + case GT: c = "g"; break; + case GE: c = "ge"; break; + default: + cerror("putcond"); + } + printf("%s", c); +} + +void +zzzcode(NODE *p, int c) +{ + NODE *l; + CONSZ hval; + + switch (c) { + case 'A': /* ildb right arg */ + adrput(stdout, p->n_left->n_left); + break; + + case 'B': /* remove from stack after subroutine call */ + if (p->n_qual) + printf(" subi %%17,0%o\n", p->n_qual); + break; + + case 'C': + constput(p); + break; + + case 'D': /* Find out which type of const load insn to use */ + if (p->n_op != ICON) + cerror("zzzcode not ICON"); + if (p->n_name[0] == '\0') { + if ((p->n_lval <= 0777777) && (p->n_lval > 0)) + printf("movei"); + else if ((p->n_lval & 0777777) == 0) + printf("hrlzi"); + else + printf("move"); + } else + printf("move"); + break; + + case 'E': /* Print correct constant expression */ + if (p->n_name[0] == '\0') { + if ((p->n_lval <= 0777777) && (p->n_lval > 0)){ + printf("0%llo", p->n_lval); + } else if ((p->n_lval & 0777777) == 0) { + printf("0%llo", p->n_lval >> 18); + } else { + if (p->n_lval < 0) + printf("[ .long -0%llo]", -p->n_lval); + else + printf("[ .long 0%llo]", p->n_lval); + } + } else { + if (p->n_lval == 0) + printf("[ .long %s]", p->n_name); + else + printf("[ .long %s+0%llo]", + p->n_name, p->n_lval); + } + break; + + case 'G': /* structure argument */ + printf(" addl %%17,0%o\n", + attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/(SZINT/SZCHAR)); + printf(" foo...\n"); + break; + + case 'P': + p = getlr(p, 'R'); + /* FALLTHROUGH */ + case 'O': + /* + * Print long long expression. + */ + hval = gethval(p->n_lval); + printf("[ .long 0%llo,0%llo", hval, + (p->n_lval & 0377777777777LL) | (hval & 0400000000000LL)); + if (p->n_name[0] != '\0') + printf("+%s", p->n_name); + printf(" ]"); + break; + + case 'F': /* Print an "opsimp" instruction based on its const type */ + hopcode(oneinstr(p->n_right) ? 'C' : 'R', p->n_op); + break; + + case 'H': /* Print a small constant */ + p = p->n_right; + printf("0%llo", p->n_lval & 0777777); + break; + + case 'Q': /* two-param long long comparisions */ + twollcomp(p); + break; + + case 'R': /* two-param conditionals */ + twocomp(p); + break; + + case 'U': + emitshort(p); + break; + + case 'V': + storeshort(p); + break; + + case 'Z': + ptrcomp(p); + break; + + case 'a': + imuli(p); + break; + + case 'b': + idivi(p); + break; + + case 'c': + xmovei(p); + break; + + case 'd': + printcon(p); + break; + + case 'e': + putcond(p); + break; + + case 'g': + if (p->n_right->n_op != OREG || p->n_right->n_lval != 0) + comperr("bad Zg oreg"); + printf("%s", rnames[p->n_right->n_rval]); + break; + +#if 0 + case '1': /* double upput */ + p = getlr(p, '1'); + p->n_rval += 2; + adrput(stdout, p); + p->n_rval -= 2; + break; +#endif + + case 'i': /* Write instruction for short load from name */ + l = getlr(p, 'L'); + printf(" h%cr%c %s,%s+" CONFMT "\n", + l->n_lval & 1 ? 'r' : 'l', + ISUNSIGNED(p->n_type) ? 'z' : 'e', + rnames[getlr(p, '1')->n_rval], + l->n_name, l->n_lval >> 1); + break; + + default: + cerror("zzzcode %c", c); + } +} + +/* set up temporary registers */ +void +setregs(void) +{ + fregs = 7; /* 7 free regs on PDP10 (1-7) */ +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + return 0; +} + +int +flshape(NODE *p) +{ + register int o = p->n_op; + + return (o == REG || o == NAME || o == ICON || + (o == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1))); +} + +/* INTEMP shapes must not contain any temporary registers */ +int +shtemp(NODE *p) +{ + return(0); +} + +int +shumul(NODE *p, int order) +{ + register int o; + + if (x2debug) { + int val; + printf("shumul(%p)\n", p); + eprint(p, 0, &val, &val); + } + + o = p->n_op; +#if 0 + if (o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON) + return(STARNM); +#endif + +#if 0 + if ((o == INCR) && + (p->n_left->n_op == REG && p->n_right->n_op == ICON) && + p->n_right->n_name[0] == '\0') { + switch (p->n_type) { + case CHAR|PTR: + case UCHAR|PTR: + o = 1; + break; + + case SHORT|PTR: + case USHORT|PTR: + o = 2; + break; + + case INT|PTR: + case UNSIGNED|PTR: + case LONG|PTR: + case ULONG|PTR: + case FLOAT|PTR: + o = 4; + break; + + case DOUBLE|PTR: + case LONGLONG|PTR: + case ULONGLONG|PTR: + o = 8; + break; + + default: + if (ISPTR(p->n_type) && + ISPTR(DECREF(p->n_type))) { + o = 4; + break; + } else + return(0); + } + return( 0); + } +#endif + return( SRNOPE ); +} + +void +adrcon(CONSZ val) +{ + cerror("adrcon: val %llo\n", val); +} + +void +conput(FILE *fp, NODE *p) +{ + switch (p->n_op) { + case ICON: + if (p->n_lval != 0) { + acon(fp, p); + if (p->n_name[0] != '\0') + fputc('+', fp); + } + if (p->n_name[0] != '\0') + fprintf(fp, "%s", p->n_name); + if (p->n_name[0] == '\0' && p->n_lval == 0) + fputc('0', fp); + return; + + case REG: + fprintf(fp, "%s", rnames[p->n_rval]); + return; + + default: + cerror("illegal conput"); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + cerror("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + + size /= SZLONG; + switch (p->n_op) { + case REG: + printf("%s", rnames[p->n_rval + size]); + break; + + case NAME: + case OREG: + p->n_lval += size; + adrput(stdout, p); + p->n_lval -= size; + break; + case ICON: + printf(CONFMT, p->n_lval >> (36 * size)); + break; + default: + cerror("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *fp, NODE *p) +{ + int r; + /* output an address, with offsets, from p */ + + if (p->n_op == FLD) + p = p->n_left; + + switch (p->n_op) { + + case NAME: + if (p->n_name[0] != '\0') + fputs(p->n_name, fp); + if (p->n_lval != 0) + fprintf(fp, "+" CONFMT, p->n_lval & 0777777777777LL); + return; + + case OREG: + r = p->n_rval; +#if 0 + if (R2TEST(r)) { /* double indexing */ + register int flags; + + flags = R2UPK3(r); + if (flags & 1) + putc('*', fp); + if (flags & 4) + putc('-', fp); + if (p->n_lval != 0 || p->n_name[0] != '\0') + acon(p); + if (R2UPK1(r) != 100) + printf("(%s)", rnames[R2UPK1(r)]); + if (flags & 2) + putchar('+'); + printf("[%s]", rnames[R2UPK2(r)]); + return; + } +#endif + if (R2TEST(r)) + cerror("adrput: unwanted double indexing: r %o", r); + if (p->n_rval != FPREG && p->n_lval < 0 && p->n_name[0]) { + fprintf(fp, "%s", p->n_name); + acon(fp, p); + fprintf(fp, "(%s)", rnames[p->n_rval]); + return; + } + if (p->n_lval < 0 && p->n_rval == FPREG && offarg) { + p->n_lval -= offarg-2; acon(fp, p); p->n_lval += offarg-2; + } else if (p->n_lval != 0) + acon(fp, p); + if (p->n_name[0] != '\0') + fprintf(fp, "%s%s", p->n_lval ? "+" : "", p->n_name); + if (p->n_lval > 0 && p->n_rval == FPREG && offlab) + fprintf(fp, "+" LABFMT, offlab); + if (p->n_lval < 0 && p->n_rval == FPREG && offarg) + fprintf(fp, "(017)"); + else + fprintf(fp, "(%s)", rnames[p->n_rval]); + return; + case ICON: + /* addressable value of the constant */ + if (p->n_lval > 0) { + acon(fp, p); + if (p->n_name[0] != '\0') + putc('+', fp); + } + if (p->n_name[0] != '\0') + fprintf(fp, "%s", p->n_name); + if (p->n_lval < 0) + acon(fp, p); + if (p->n_name[0] == '\0' && p->n_lval == 0) + putc('0', fp); + return; + + case REG: + fputs(rnames[p->n_rval], fp); + return; + + default: + cerror("illegal address, op %d", p->n_op); + return; + + } +} + +/* + * print out a constant + */ +void +acon(FILE *fp, NODE *p) +{ + if (p->n_lval < 0 && p->n_lval > -0777777777777ULL) + fprintf(fp, "-" CONFMT, -p->n_lval); + else + fprintf(fp, CONFMT, p->n_lval); +} + +/* printf conditional and unconditional branches */ +void +cbgen(int o,int lab) +{ +} + +/* + * Do some local optimizations that must be done after optim is called. + */ +static void +optim2(NODE *p, void *arg) +{ + int op = p->n_op; + int m, ml; + NODE *l; + + /* Remove redundant PCONV's */ + if (op == PCONV) { + l = p->n_left; + m = BTYPE(p->n_type); + ml = BTYPE(l->n_type); + if ((m == INT || m == LONG || m == LONGLONG || m == FLOAT || + m == DOUBLE || m == STRTY || m == UNIONTY || + m == UNSIGNED || m == ULONG || m == ULONGLONG) && + (ml == INT || ml == LONG || ml == LONGLONG || ml == FLOAT || + ml == DOUBLE || ml == STRTY || ml == UNIONTY || + ml == UNSIGNED || ml == ULONG || + ml == ULONGLONG) && ISPTR(l->n_type)) { + *p = *l; + nfree(l); + op = p->n_op; + } else + if (ISPTR(DECREF(p->n_type)) && + (l->n_type == INCREF(STRTY))) { + *p = *l; + nfree(l); + op = p->n_op; + } else + if (ISPTR(DECREF(l->n_type)) && + (p->n_type == INCREF(INT) || + p->n_type == INCREF(STRTY) || + p->n_type == INCREF(UNSIGNED))) { + *p = *l; + nfree(l); + op = p->n_op; + } + + } + /* Add constands, similar to the one in optim() */ + if (op == PLUS && p->n_right->n_op == ICON) { + l = p->n_left; + if (l->n_op == PLUS && l->n_right->n_op == ICON && + (p->n_right->n_name[0] == '\0' || + l->n_right->n_name[0] == '\0')) { + l->n_right->n_lval += p->n_right->n_lval; + if (l->n_right->n_name[0] == '\0') + l->n_right->n_name = p->n_right->n_name; + nfree(p->n_right); + *p = *l; + nfree(l); + } + } + + /* Convert "PTR undef" (void *) to "PTR uchar" */ + /* XXX - should be done in MI code */ + if (BTYPE(p->n_type) == VOID) + p->n_type = (p->n_type & ~BTMASK) | UCHAR; + if (op == ICON) { + if ((p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR)) + && p->n_lval == 0 && p->n_name[0] != '\0') + p->n_lval = 0700000000000LL; + if ((p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) + && p->n_lval == 0 && p->n_name[0] != '\0') + p->n_lval = 0750000000000LL; + } + if (op == MINUS) { + if ((p->n_left->n_type == (PTR|CHAR) || + p->n_left->n_type == (PTR|UCHAR)) && + (p->n_right->n_type == (PTR|CHAR) || + p->n_right->n_type == (PTR|UCHAR))) { + l = talloc(); + l->n_op = SCONV; + l->n_type = INT; + l->n_left = p->n_right; + p->n_right = l; + l = talloc(); + l->n_op = SCONV; + l->n_type = INT; + l->n_left = p->n_left; + p->n_left = l; + } + } +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, optim2, 0); + } + + if (x2debug) { + printf("myreader final tree:\n"); + printip(ipole); + } +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE *p, void *arg) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2, 0); +} + +/* + * Remove last goto. + */ +void +myoptim(struct interpass *ip) +{ +} + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + return (szty(t) == 2 ? CLASSB : CLASSA); +} + +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (t == STRTY || t == UNIONTY) + return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/(SZINT/SZCHAR); + return szty(t); +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + if (p->n_right->n_op != ASSIGN) + size += argsiz(p->n_right); + if (p->n_op != ASSIGN) + size += argsiz(p); + op->n_qual = size; /* XXX */ +} + +void +rmove(int s, int d, TWORD t) +{ + printf(" %smove %s,%s\n", + (s > 017 ? "d" : ""), rnames[d], rnames[s]); +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int c, int *r) +{ + int num; + + switch (c) { + case CLASSA: + /* there are 13 classa, so min 6 classb are needed to block */ + num = r[CLASSB] * 2; + num += r[CLASSA]; + return num < 13; + case CLASSB: + /* 7 classa may block all classb */ + num = r[CLASSB] + r[CLASSA]; + return num < 7; + } + comperr("COLORMAP"); + return 0; /* XXX gcc */ +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ +} + +/* + * Do something target-dependent for xasm arguments. + * Supposed to find target-specific constraints and rewrite them. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + return 0; +} diff --git a/lang/pcc/pcc/arch/pdp10/macdefs.h b/lang/pcc/pcc/arch/pdp10/macdefs.h new file mode 100644 index 000000000..cfaca356d --- /dev/null +++ b/lang/pcc/pcc/arch/pdp10/macdefs.h @@ -0,0 +1,243 @@ +/* $Id: macdefs.h,v 1.36 2016/03/05 15:53:04 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + * Assume: If only one value; store at left side (char size), otherwise + * treat it as an integer. + */ +#define makecc(val,i) { \ + if (i == 0) { lastcon = val; \ + } else if (i == 1) { lastcon = (lastcon << 9) | val; lastcon <<= 18; \ + } else { lastcon |= (val << (27 - (i * 9))); } } + +#define ARGINIT 36 /* # bits below fp where arguments start */ +#define AUTOINIT 36 /* # bits above fp where automatics start */ + +/* + * Storage space requirements + */ +#define SZCHAR 9 +#define SZBOOL 36 +#define SZINT 36 +#define SZFLOAT 36 +#define SZDOUBLE 72 +#define SZLDOUBLE 72 +#define SZLONG 36 +#define SZSHORT 18 +#define SZPOINT(x) 36 +#define SZLONGLONG 72 + +/* + * Alignment constraints + */ +#define ALCHAR 9 +#define ALBOOL 36 +#define ALINT 36 +#define ALFLOAT 36 +#define ALDOUBLE 36 +#define ALLDOUBLE 36 +#define ALLONG 36 +#define ALLONGLONG 36 +#define ALSHORT 18 +#define ALPOINT 36 +#define ALSTRUCT 36 +#define ALSTACK 36 + +/* + * Max values. + */ +#define MIN_CHAR -256 +#define MAX_CHAR 255 +#define MAX_UCHAR 511 +#define MIN_SHORT -131072 +#define MAX_SHORT 131071 +#define MAX_USHORT 262143 +#define MIN_INT (-0377777777777LL-1) +#define MAX_INT 0377777777777LL +#define MAX_UNSIGNED 0777777777777ULL +#define MIN_LONG (-0377777777777LL-1) +#define MAX_LONG 0377777777777LL +#define MAX_ULONG 0777777777777ULL +#define MIN_LONGLONG (000777777777777777777777LL-1) /* XXX cross */ +#define MAX_LONGLONG 000777777777777777777777LL /* XXX cross */ +#define MAX_ULONGLONG 001777777777777777777777ULL /* XXX cross */ + +/* Default char is unsigned */ +#define TARGET_STDARGS +#define CHAR_UNSIGNED +#define BOOL_TYPE INT +#define WORD_ADDRESSED + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "0%llo" /* format for printing constants */ +#define LABFMT ".L%d" /* format for printing labels */ +#define STABLBL ".LL%d" /* format for stab (debugging) labels */ + +#undef BACKAUTO /* stack grows negatively for automatics */ +#undef BACKTEMP /* stack grows negatively for temporaries */ + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_BE + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&03) +#define wdal(k) (BYTEOFF(k)==0) + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) +#define genfcall(a,b) gencall(a,b) + +#define szty(t) (((t) == DOUBLE || (t) == FLOAT || \ + (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) + +#define shltype(o, p) \ + ((o) == REG || (o) == NAME || (o) == ICON || \ + (o) == OREG || ((o) == UMUL && shumul((p)->n_left, SOREG))) + +#undef SPECIAL_INTEGERS + +/* + * Special shapes used in code generation. + */ +#define SUSHCON (SPECIAL|6) /* unsigned short constant */ +#define SNSHCON (SPECIAL|7) /* negative short constant */ +#define SILDB (SPECIAL|8) /* use ildb here */ + +/* + * Register allocator definitions. + * + * The pdp10 has 16 general-purpose registers, but the two + * highest are used as sp and fp. Register 0 has special + * constraints in its possible use as index register. + * All regs can be used as pairs, named by the lowest number. + * In here we call the registers Rn and the pairs XRn, in assembler + * just its number prefixed with %. + * + * R1/XR1 are return registers. + * + * R0 is currently not used. + */ + +#define MAXREGS 29 /* 16 + 13 regs */ +#define NUMCLASS 2 + +#define R0 00 +#define R1 01 +#define R2 02 +#define R3 03 +#define R4 04 +#define R5 05 +#define R6 06 +#define R7 07 +#define R10 010 +#define R11 011 +#define R12 012 +#define R13 013 +#define R14 014 +#define R15 015 +#define R16 016 +#define R17 017 +#define FPREG R16 /* frame pointer */ +#define STKREG R17 /* stack pointer */ + + +#define XR0 020 +#define XR1 021 +#define XR2 022 +#define XR3 023 +#define XR4 024 +#define XR5 025 +#define XR6 026 +#define XR7 027 +#define XR10 030 +#define XR11 031 +#define XR12 032 +#define XR13 033 +#define XR14 034 + + +#define RSTATUS \ + 0, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, 0, 0, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SBREG, SBREG, SBREG, SBREG, SBREG, + +#define ROVERLAP \ + { XR0, -1 }, \ + { XR0, XR1, -1 }, \ + { XR1, XR2, -1 }, \ + { XR2, XR3, -1 }, \ + { XR3, XR4, -1 }, \ + { XR4, XR5, -1 }, \ + { XR5, XR6, -1 }, \ + { XR6, XR7, -1 }, \ + { XR7, XR10, -1 }, \ + { XR10, XR11, -1 }, \ + { XR11, XR12, -1 }, \ + { XR12, XR13, -1 }, \ + { XR13, XR14, -1 }, \ + { XR14, -1 }, \ + { -1 }, \ + { -1 }, \ + { R0, R1, XR1, -1 }, \ + { R1, R2, XR0, XR2, -1 }, \ + { R2, R3, XR1, XR3, -1 }, \ + { R3, R4, XR2, XR4, -1 }, \ + { R4, R5, XR3, XR5, -1 }, \ + { R5, R6, XR4, XR6, -1 }, \ + { R6, R7, XR5, XR7, -1 }, \ + { R7, R10, XR6, XR10, -1 }, \ + { R10, R11, XR7, XR11, -1 }, \ + { R11, R12, XR10, XR12, -1 }, \ + { R12, R13, XR11, XR13, -1 }, \ + { R13, R14, XR12, XR14, -1 }, \ + { R14, R15, XR13, -1 }, + +/* Return a register class based on the type of the node */ +#define PCLASS(p) (szty(p->n_type) == 2 ? SBREG : SAREG) +#define RETREG(x) (szty(x) == 2 ? XR1 : R1) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ +#define GCLASS(x) (x < 16 ? CLASSA : CLASSB) +int COLORMAP(int c, int *r); diff --git a/lang/pcc/pcc/arch/pdp10/order.c b/lang/pcc/pcc/arch/pdp10/order.c new file mode 100644 index 000000000..1f695df2e --- /dev/null +++ b/lang/pcc/pcc/arch/pdp10/order.c @@ -0,0 +1,202 @@ +/* $Id: order.c,v 1.63 2008/01/15 21:47:06 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +int canaddr(NODE *); + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + return(0); /* YES */ +} + +int radebug = 0; + +void +offstar(NODE *p, int shape) +{ + NODE *q; + + if (x2debug) + printf("offstar(%p)\n", p); + + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( p->n_right->n_op == ICON ){ + q = p->n_left; + if (q->n_op != REG) + geninsn(q, INAREG); + p->n_su = -1; + } + } + geninsn(p, INAREG); +} + +/* + * findops() failed, see if we can rewrite it to match. + */ +int +setbin(NODE *p) +{ + TWORD ty; + NODE *r, *s; + + ty = p->n_type; + switch (p->n_op) { + case MINUS: + switch (ty) { + case PTR+CHAR: + case PTR+UCHAR: + case PTR+SHORT: + case PTR+USHORT: + /* + * Must negate the right side and change op to PLUS. + */ + r = p->n_right; + if (r->n_op == ICON) { + r->n_lval = -r->n_lval; + } else { + s = talloc(); + s->n_type = r->n_type; + s->n_op = UMINUS; + s->n_left = r; + p->n_right = s; + } + p->n_op = PLUS; + return 1; + } + } + return 0; +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +int +special(NODE *p, int shape) +{ + switch (shape) { + case SUSHCON: + if (p->n_op == ICON && p->n_name[0] == '\0' && + (p->n_lval > 0 && p->n_lval <= 0777777)) + return 1; + break; + + case SNSHCON: + if (p->n_op == ICON && p->n_name[0] == '\0' && + (p->n_lval < 0 && p->n_lval > -01000000)) + return 1; + break; + case SILDB: + if (p->n_op == ASSIGN && p->n_left->n_op == REG && + p->n_right->n_op == PLUS && + p->n_right->n_left->n_op == REG && + p->n_right->n_right->n_op == ICON && + p->n_right->n_right->n_lval == 1 && + p->n_right->n_left->n_rval == p->n_left->n_rval) + return 1; + break; + } + return 0; +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; /* nothing differs on x86 */ +} + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + return 0; /* XXX gcc */ +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + */ +void +myormake(NODE *p) +{ + if (x2debug) + printf("myormake(%p)\n", p); +} + +/* + * set registers in calling conventions live. + */ +int * +livecall(NODE *p) +{ + static int r[8], *s = r; + + *s = -1; + if (p->n_op == UCALL || p->n_op == UFORTCALL || p->n_op == USTCALL || + p->n_op == FORTCALL) + return s; + for (p = p->n_right; p->n_op == CM; p = p->n_left) { + if (p->n_right->n_op == ASSIGN && + p->n_right->n_left->n_op == REG) + *s++ = p->n_right->n_left->n_rval; + } + if (p->n_op == ASSIGN && + p->n_left->n_op == REG) + *s++ = p->n_left->n_rval; + *s = -1; + return r; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/pdp10/table.c b/lang/pcc/pcc/arch/pdp10/table.c new file mode 100644 index 000000000..4e140c5ba --- /dev/null +++ b/lang/pcc/pcc/arch/pdp10/table.c @@ -0,0 +1,1136 @@ +/* $Id: table.c,v 1.97 2008/02/10 19:25:44 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +# define TLL TLONGLONG|TULONGLONG +# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR +# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR +# define ANYFIXED ANYSIGNED|ANYUSIGNED +# define TUWORD TUNSIGNED|TULONG +# define TSWORD TINT|TLONG +# define TWORD TUWORD|TSWORD + +struct optab table[] = { +{ -1, FORREW,SANY,TANY,SANY,TANY,REWRITE,-1,"", }, +/* + * A bunch of pointer conversions. + * First pointer to integer. + */ +/* Convert char pointer to int */ +{ SCONV, INAREG, + SAREG|SAREG, TPTRTO|TCHAR|TUCHAR, + SANY, TWORD, + NAREG, RLEFT, + " lsh AL,2\n" + " move A1,AL\n" + " lsh A1,-040\n" + " trz A1,074\n" + " ior AL,A1\n" + " tlz AL,0740000\n", }, + +/* Convert short pointer to int */ +{ SCONV, INAREG, + SAREG|SAREG, TPTRTO|TSHORT|TUSHORT, + SANY, TWORD, + NAREG, RLEFT, + " lsh AL,2\n" + " move A1,AL\n" + " lsh A1,-041\n" + " trz A1,2\n" + " ior AL,A1\n" + " tlz AL,0740000\n", }, + +/* Convert int/unsigned/long/ulong/struct/union/func ptr to int */ +{ SCONV, INAREG, + SAREG|SAREG, TPTRTO|TWORD|TSTRUCT|TPOINT, + SANY, TWORD, + 0, RLEFT, + " lsh AL,2\n", }, + +/* + * Convert int/long to pointers. + */ +/* Convert int to char pointer */ +{ PCONV, INAREG, + SAREG, TWORD, + SANY, TPTRTO|TCHAR|TUCHAR, + NAREG, RLEFT, + " move A1,AL\n" + " lsh A1,036\n" + " tlo A1,0700000\n" + " tlz A1,0040000\n" + " lsh AL,-2\n" + " ior AL,A1\n", }, + +/* Convert int/long to short pointer */ +{ PCONV, INAREG, + SAREG, TWORD, + SANY, TPTRTO|TSHORT|TUSHORT, + NAREG, RLEFT, + " move A1,AL\n" + " lsh AL,-2\n" + " tlo AL,0750000\n" + " lsh A1,035\n" + " tlz A1,0760000\n" + " add AL,A1\n", }, + +/* Convert int/long to int/struct/multiple ptr */ +{ PCONV, INAREG, + SAREG, TWORD, + SANY, TPOINT|TWORD|TSTRUCT, + 0, RLEFT, + " lsh AL,-2\n", }, + +/* + * Pointer to pointer conversions. + */ +/* Convert char ptr to short ptr */ +{ PCONV, INAREG, + SAREG, TPTRTO|TCHAR|TUCHAR, + SANY, TPTRTO|TSHORT|TUSHORT, + 0, RLEFT, + " tlo AL,050000\n" + " tlne AL,020000\n" + " tlz AL,010000\n", }, + +/* Convert char/short pointer to int/struct/multiple ptr */ +{ PCONV, INAREG, + SAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + SANY, TPOINT|TWORD|TSTRUCT, + 0, RLEFT, + " tlz AL,0770000\n", }, + +/* Convert short pointer to char ptr */ +{ PCONV, INAREG, + SAREG, TPTRTO|TSHORT|TUSHORT, + SANY, TPTRTO|TCHAR|TUCHAR, + 0, RLEFT, + " tlz AL,050000\n", }, + +/* Convert int/struct/foo pointer to char ptr */ +{ PCONV, INAREG, + SAREG, TPOINT|TWORD|TSTRUCT, + SANY, TPTRTO|TCHAR|TUCHAR, + 0, RLEFT, + " tlo AL,0700000\n", }, + +/* Convert int/struct/foo pointer to short ptr */ +{ PCONV, INAREG, + SAREG, TPTRTO|TWORD|TSTRUCT, + SANY, TPTRTO|TSHORT|TUSHORT, + 0, RLEFT, + " tlo AL,0750000\n", }, + +/* + * A bunch conversions of integral<->integral types + */ + +/* convert short/char to int. This is done when register is loaded */ +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD, + SANY, TWORD, + 0, RLEFT, + "", }, + +/* convert int to short/char. This is done when register is loaded */ +{ SCONV, INAREG, + SAREG, TWORD, + SANY, TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD, + 0, RLEFT, + "", }, + +/* convert int/long to unsigned long long */ +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TWORD, + SANY, TULONGLONG, + NAREG|NASL, RESC1, + " move U1,AL\n" + " setz A1,\n" + " tlze U1,0400000\n" + " tro A1,01\n" , }, + +/* convert int/long to long long */ +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TWORD, + SANY, TLONGLONG, + NAREG|NASL, RESC1, + " move U1,AL\n" + " move A1,U1\n" + " ash A1,-043\n", }, + +/* convert uchar/ushort to (unsigned) long long */ +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TUCHAR|TUSHORT, + SANY, TLL, + NAREG|NASL, RESC1, + " move U1,AL\n" + " setz A1,\n", }, + +/* convert long long to int/long */ +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TLL, + SANY, TWORD, + NAREG|NASL, RESC1, + " move A1,UL\n", }, + +/* convert long long to unsigned char - XXX - signed char */ +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TLL, + SANY, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " move A1,UL\n" + " andi A1,0777\n", }, + +/* convert long long to short - XXX - signed short */ +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TLL, + SANY, TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " move A1,UL\n" + " hrrz A1,A1\n", }, + +/* floating point conversions */ +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TDOUBLE|TFLOAT, + SANY, TWORD, + NAREG|NASL, RESC1, + " fix A1,AL\n", }, + +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TWORD, + SANY, TFLOAT, + NAREG|NASL, RESC1, + " fltr A1,AL\n", }, + +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TWORD, + SANY, TDOUBLE, + NAREG|NASL, RESC1, + " fltr A1,AL\n setz U1,\n", }, + +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TDOUBLE, + SANY, TFLOAT, + NAREG|NASL, RESC1, + " move A1,AL\n", }, + +{ SCONV, INAREG, + SAREG|SAREG|SNAME|SOREG, TFLOAT, + SANY, TDOUBLE, + NAREG|NASL, RESC1, + " move A1,AL\n setz U1,\n", }, + +/* + * Subroutine calls. + */ + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, /* should be 0 */ + " pushj 017,AL\nZB", }, + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, /* should be 0 */ + " pushj 017,AL\nZB", }, + +{ UCALL, INAREG, + SCON, TANY, + SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TPOINT, + NAREG, RESC1, /* should be 0 */ + " pushj 017,AL\nZB", }, + +{ CALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " pushj 017,AL\nZB", }, + +{ UCALL, INAREG, + SAREG|SAREG, TANY, + SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT, + NAREG|NASL, RESC1, /* should be 0 */ + " pushj 017,(AL)\nZB", }, + +{ UCALL, INAREG, + SNAME|SOREG, TANY, + SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT, + NAREG, RESC1, /* should be 0 */ + " pushj 017,@AL\nZB", }, + +#ifdef notyet +/* + * INCR can be slightly optimized. + */ +{ INCR, INAREG, + SAREG|SAREG|SNAME|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, + SONE, TANY, + NAREG, RESC1, + " move A1,AL\n" + " ibp AL\n", }, + +/* Fix check of return value */ +{ INCR, FOREFF, + SAREG|SAREG|SNAME|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, + SONE, TANY, + 0, 0, + " ibp AL\n", }, +#endif + +/* + * PLUS operators. + */ +/* Add a value to a char/short pointer */ +{ PLUS, INAREG|INAREG|FOREFF, + SAREG|SAREG|SNAME|SOREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|SAREG, TWORD, + 0, RRIGHT, + " adjbp AR,AL\n", }, + +/* No more search for char/short pointer addition */ +{ PLUS, INAREG|INAREG|FOREFF, + SANY, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE!\n", }, + +/* Add char/short/int to register */ +{ PLUS, FOREFF|INAREG|INAREG, + SAREG|SAREG, TWORD, + SAREG|SAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " add AL,AR\n", }, + +/* Add char/short/int to memory */ +{ PLUS, FOREFF|INAREG|INAREG, + SAREG|SAREG|SNAME|SOREG, TWORD, + SAREG|SAREG, TWORD, + 0, RLEFT, + " addm AR,AL\n", }, + +/* Add a small constant to a register */ +{ PLUS, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT, + SUSHCON, TWORD, + 0, RLEFT, + " addi AL,AR\n", }, + +/* Add a larger constant to a register */ +{ PLUS, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT, + SCON, TWORD, + 0, RLEFT, + " add AL,[ .long AR ]\n", }, + +/* Add long long to register */ +{ PLUS, INAREG|INAREG|FOREFF, + SAREG|SAREG, TLL, + SAREG|SAREG|SNAME|SOREG, TLL, + 0, RLEFT, + " dadd AL,AR\n", }, + +/* Add int (or int pointer) to register */ +{ PLUS, FOREFF|INAREG|INAREG, + SAREG|SAREG, TWORD|TPOINT, + SAREG|SAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " add AL,AR # foo \n", }, + +/* char/short are allowed to be added if they are in registers */ +{ PLUS, INAREG|INAREG|FOREFF, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " add AL,AR\n", }, + +/* get address of an memory position into a register */ +{ PLUS, INAREG|INAREG, + SAREG|SAREG, TWORD|TPTRTO, + SCON, TANY, + NAREG, RESC1, + " xmovei A1,AR(AL)\n", }, + +/* Safety belt for plus */ +{ PLUS, FORREW|FOREFF|INAREG|INAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* + * MINUS operators. + */ +/* Rewrite subtracts from char/short pointers (to negative adds) */ +{ MINUS, FORREW|FOREFF|INAREG|INAREG, + SANY, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* Subtract char/short/int word in memory from reg */ +{ MINUS, FOREFF|INAREG|INAREG, + SAREG|SAREG, TWORD|TPOINT, + SAREG|SAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RLEFT, + " sub AL,AR\n", }, + +/* Subtract a small constant from reg */ +{ MINUS, FOREFF|INAREG|INAREG, + SAREG|SAREG, TWORD|TPOINT, + SUSHCON, TWORD|TPOINT, + 0, RLEFT, + " subi AL,AR\n", }, + +/* Subtract a large constant from reg */ +{ MINUS, FOREFF|INAREG|INAREG, + SAREG|SAREG, TWORD|TPOINT, + SCON, TWORD|TPOINT, + 0, RLEFT, + " sub AL,[ .long AR ]\n", }, + +/* Subtract char/short/int word in memory from reg, save in memory */ +{ MINUS, FOREFF|INAREG|INAREG, + SAREG|SAREG, TWORD, + SAREG|SAREG|SNAME|SOREG, TWORD, + 0, RRIGHT, + " subm AL,AR\n", }, + +/* Subtract long long from register */ +{ MINUS, INAREG|INAREG|FOREFF, + SAREG|SAREG, TLL, + SAREG|SAREG|SNAME|SOREG, TLL, + 0, RLEFT, + " dsub AL,AR\n", }, + +/* char/short are allowed to be subtracted if they are in registers */ +{ MINUS, INAREG|INAREG|FOREFF, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " sub AL,AR\n", }, + +/* Safety belt for plus */ +{ MINUS, FORREW|FOREFF|INAREG|INAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* + * AND/OR/ER operators. + * Simpler that the ops above in that they only work on integral types. + */ +/* And char/short/int with integer memory */ +{ AND, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|SAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " and AL,AR\n", }, + +/* And char/short/int with register */ +{ AND, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " and AL,AR\n", }, + +/* And char/short/int with small constant */ +{ AND, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " andi AL,AR\n", }, + +/* And char/short/int with large constant */ +{ AND, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " and AL,[ .long AR ]\n", }, + +/* long long AND */ +{ AND, INAREG|FOREFF, + SAREG|SAREG, TLL, + SAREG|SAREG|SNAME|SOREG, TLL, + 0, RLEFT, + " and AL,AR\n" + " and UL,UR\n", }, + +/* Safety belt for AND */ +{ AND, FORREW|FOREFF|INAREG|INAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + + +/* OR char/short/int with integer memory */ +{ OR, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|SAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " ior AL,AR\n", }, + +/* OR char/short/int with register */ +{ OR, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " ior AL,AR\n", }, + +/* OR char/short/int with small constant */ +{ OR, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " iori AL,AR\n", }, + +/* OR char/short/int with large constant */ +{ OR, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " ior AL,[ .long AR ]\n", }, + +/* long long OR */ +{ OR, INAREG|FOREFF, + SAREG|SAREG, TLL, + SAREG|SAREG|SNAME|SOREG, TLL, + 0, RLEFT, + " ior AL,AR\n" + " ior UL,UR\n", }, + +/* Safety belt for OR */ +{ OR, FORREW|FOREFF|INAREG|INAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + + +/* ER char/short/int with integer memory */ +{ ER, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|SAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " xor AL,AR\n", }, + +/* ER char/short/int with register */ +{ ER, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " xor AL,AR\n", }, + +/* ER char/short/int with small constant */ +{ ER, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " xori AL,AR\n", }, + +/* ER char/short/int with large constant */ +{ ER, FOREFF|INAREG|INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, + 0, RLEFT, + " xor AL,[ .long AR ]\n", }, + +/* long long ER */ +{ ER, INAREG|FOREFF, + SAREG|SAREG, TLL, + SAREG|SAREG|SNAME|SOREG, TLL, + 0, RLEFT, + " xor AL,AR\n" + " xor UL,UR\n", }, + +/* Safety belt for ER */ +{ ER, FORREW|FOREFF|INAREG|INAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* + * The next rules handle all shift operators. + */ +{ LS, INAREG|INAREG|FOREFF, + SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " lsh AL,(AR)\n", }, + +{ LS, INAREG|INAREG|FOREFF, + SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + SNAME|SOREG, TWORD, + 0, RLEFT, + " lsh AL,@AR\n", }, + +{ LS, INAREG|INAREG|FOREFF, + SAREG|SAREG, TLL, + SCON, TANY, + 0, RLEFT, + " ashc AL,ZH\n", }, + +{ LS, INAREG|INAREG|FOREFF, + SAREG|SAREG, TLL, + SAREG|SAREG /* |SNAME|SOREG */, TANY, + 0, RLEFT, + " ashc AL,(AR)\n", }, + +{ RS, INAREG|INAREG|FOREFF, + SAREG|SAREG, TSWORD, + SCON, TWORD, + 0, RLEFT, + " ash AL,-ZH\n", }, + +{ RS, INAREG|INAREG|FOREFF, + SAREG|SAREG, TUWORD, + SCON, TWORD, + 0, RLEFT, + " lsh AL,-ZH\n", }, + +/* Safety belt for LS/RS */ +{ LS, FORREW|FOREFF|INAREG|INAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +{ RS, FORREW|FOREFF|INAREG|INAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* + * The next rules takes care of assignments. "=". + */ +/* Match zeroed registers first */ +{ ASSIGN, INAREG|FOREFF, + SAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT, + SZERO, TANY, + 0, RDEST, + " setz AL,\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SZERO, TANY, + 0, 0, + " setzm AL\n", }, + +{ ASSIGN, INAREG|FOREFF, + SAREG|SAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT, + SMONE, TANY, + 0, RDEST, + " setom AL\n", }, + +{ ASSIGN, FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SMONE, TANY, + 0, 0, + " setom AL\n", }, + +{ ASSIGN, INAREG|INAREG|FOREFF, + SAREG|SAREG, TWORD|TPOINT, + SCON, TWORD|TPOINT, + 0, RDEST, + " ZC\n", }, + +{ ASSIGN, INAREG|INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT, + SAREG|SAREG, TUCHAR|TUSHORT|TWORD|TPOINT|TFLOAT, + 0, RDEST, + " movem AR,AL\n", }, + +{ ASSIGN, INAREG|INAREG|FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT, + SAREG|SAREG, TSHORT, + 0, RDEST, + " hrrem AR,AL\n", }, + +{ ASSIGN, INAREG|INAREG|FOREFF, + SAREG|SAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT, + SAREG|SAREG|SNAME|SOREG, TWORD|TPOINT, + 0, RDEST, + " move AL,AR\n", }, + +{ ASSIGN, INAREG|INAREG|FOREFF, + SAREG|SAREG, TUCHAR|TUSHORT|TCHAR|TSHORT, + SAREG|SAREG, TUCHAR|TUSHORT|TCHAR|TSHORT, + 0, RDEST, + " move AL,AR\n", }, + +{ ASSIGN, INBREG|FOREFF, + SBREG|SNAME|SOREG, TLL|TDOUBLE, + SBREG, TLL|TDOUBLE, + 0, RDEST, + " dmovem AR,AL\n", }, + +{ ASSIGN, INAREG|INAREG|FOREFF, + SOREG|SNAME, TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG|SAREG, TANY, + 0, RDEST, + "ZV", }, + +{ ASSIGN, INAREG|INAREG|FOREFF, + SAREG|SAREG, TUSHORT|TUCHAR, + SOREG, TANY, + 0, RDEST, + " ldb AL,Zg\n", }, + +{ ASSIGN, INAREG|INAREG|FOREFF, + SAREG|SAREG, TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TANY, + 0, RDEST, + " movei AL,AR\n", }, + +{ ASSIGN, INAREG|INAREG|FOREFF, + SAREG|SAREG, TSHORT|TUSHORT|TCHAR|TUCHAR, + SCON, TANY, + 0, RDEST, + " move AL,[ .long AR]\n", }, + +/* + * DIV/MOD/MUL + * These can be done way more efficient. + */ +/* long long div. XXX - work only with unsigned */ +{ DIV, INBREG, + SBREG|SNAME|SOREG, TLL, + SBREG|SNAME|SOREG, TLL, + (2*NBREG)|NBSL, RESC1, + " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n" + " ddiv A1,AR\n", }, + +/* long long div. with constant. XXX - work only with unsigned */ +{ DIV, INBREG, + SBREG|SNAME|SOREG, TLL, + SCON, TLL, + (2*NBREG)|NBSL, RESC1, + " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n" + " ddiv A1,ZP\n", }, + +/* Simple divide. XXX - fix so next reg can be free */ +{ DIV, INAREG|INAREG|FOREFF, + SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RRIGHT, + " idivm AL,AR\n", }, + +/* Safety belt for DIV */ +{ DIV, FORREW|FOREFF|INAREG|INAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* long long MOD */ +{ MOD, INBREG, + SBREG|SNAME|SOREG, TLL, + SBREG|SNAME|SOREG, TLL, + 2*NBREG|NBSL, RESC2, + " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n" + " ddiv A1,AR\n", }, + +/* integer MOD */ +{ MOD, INAREG, + SAREG|SNAME|SOREG, TWORD, + SAREG|SNAME|SOREG, TWORD, + 2*NAREG|NASL, RESC2, + " move A2,AL\n" + " setz A1,\n" + " idiv A1,AR\n", }, + +/* integer MOD for char/short */ +{ MOD, INAREG, + SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 2*NAREG|NASL, RESC2, + " move A2,AL\n" + " setz A1,\n" + " idiv A1,AR\n", }, + +/* Safety belt for MOD */ +{ MOD, FOREFF, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* long long MUL */ +{ MUL, INBREG, + SBREG|SNAME|SOREG, TLL, + SBREG|SNAME|SOREG, TLL, + 2*NBREG|NBSL, RESC2, + " dmove A1,AL\n" + " dmul A1,AR\n", }, + +/* integer multiply to memory*/ +{ MUL, INAREG|INAREG|FOREFF, + SAREG|SAREG|SNAME|SOREG, TWORD, + SAREG|SAREG, TWORD, + 0, RLEFT, + " imulm AR,AL\n", }, + +/* integer multiply */ +{ MUL, INAREG|INAREG|FOREFF, + SAREG|SAREG, TWORD, + SAREG|SAREG|SNAME|SOREG, TWORD, + 0, RLEFT, + " imul AL,AR\n", }, + +/* integer multiply for char/short */ +{ MUL, INAREG|INAREG|FOREFF, + SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " imul AL,AR\n", }, + +/* integer multiply with small constant */ +{ MUL, INAREG|INAREG|FOREFF, + SAREG|SAREG, TWORD, + SUSHCON, TWORD, + 0, RLEFT, + " imuli AL,AR\n", }, + +/* integer multiply with large constant */ +{ MUL, INAREG|INAREG|FOREFF, + SAREG|SAREG, TWORD, + SCON, TWORD, + 0, RLEFT, + " imul AL,[ .long AR ]\n", }, + +/* Safety belt for MUL */ +{ MUL, FORREW|FOREFF|INAREG|INAREG, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "DIEDIEDIE", }, + +/* read an indirect long long value into register */ +{ UMUL, INAREG, + SAREG|SAREG, TPTRTO|TLL|TWORD, + SANY, TLL, + NAREG|NASL, RESC1, + " dmove A1,(AL)\n", }, + +/* read an indirect integer value into register */ +{ UMUL, INAREG, + SAREG|SAREG, TWORD|TPOINT, + SANY, TWORD|TPOINT, + NAREG|NASL, RESC1, + " move A1,(AL)\n", }, + +/* read an indirect value into register */ +{ UMUL, INAREG, + SOREG, TWORD|TPOINT, + SANY, TWORD|TPOINT, + NAREG, RESC1, + " move A1,@AL\n", }, + +/* read an indirect value into register */ +{ UMUL, INAREG, + SAREG|SAREG|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, + SANY, TCHAR|TUCHAR|TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " ldb A1,AL\n", }, + +#ifdef notyet +/* Match tree shape for ildb */ +{ UMUL, INAREG, + SANY, TANY, + SILDB, TUCHAR|TCHAR|TPTRTO, + NAREG, RESC1, + " ildb A1,ZA\n", }, +#endif + +/* Match char/short pointers first, requires special handling */ +{ OPLOG, FORCC, + SAREG|SAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|SAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RESCC, + "ZZ", }, + +/* Can check anything by just comparing if EQ/NE */ +{ OPLOG, FORCC, + SAREG|SAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, + SZERO, TANY, + 0, RESCC, + " jumpZe AL,LC # bu\n", }, + +{ EQ, FORCC, + SAREG|SAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|SAREG|SOREG|SNAME|SCON, TWORD|TPOINT, + 0, RESCC, + "ZR", }, + +{ NE, FORCC, + SAREG|SAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|SAREG|SOREG|SNAME|SCON, TWORD|TPOINT, + 0, RESCC, + "ZR", }, + +{ OPLOG, FORCC, + SAREG|SAREG, TWORD, + SAREG|SAREG|SOREG|SNAME|SCON, TSWORD, + 0, RESCC, + "ZR", }, + +{ OPLOG, FORCC, + SAREG|SAREG, TCHAR|TUCHAR, + SCON, TANY, + 0, RESCC, + "ZR", }, + +{ OPLOG, FORCC, + SAREG|SAREG, TWORD|TPOINT|TFLOAT, + SAREG|SAREG|SOREG|SNAME|SCON, TWORD|TPOINT|TFLOAT, + 0, RESCC, + "ZR", }, + +{ OPLOG, FORCC, + SAREG|SAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, + SAREG|SAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RESCC, + "ZR", }, + +{ OPLOG, FORCC, + SAREG|SAREG, TLL|TDOUBLE, /* XXX - does double work here? */ + SAREG|SAREG|SOREG|SNAME, TLL|TDOUBLE, + 0, RESCC, + "ZQ", }, + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " jrst LL\n", }, + +/* + * Convert LTYPE to reg. + */ +{ OPLTYPE, INBREG, + SANY, TANY, + SMONE, TLL, + NBREG, RESC1, + " seto A1,\n seto U1,\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SMONE, TANY, + NAREG, RESC1, + " seto A1,\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SZERO, TLL, + NBREG, RESC1, + " setz A1,\n setz U1,\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SZERO, TANY, + NAREG, RESC1, + " setz A1,\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SUSHCON, TLL, + NBREG, RESC1, + " setz A1,\n movei U1,AR\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SUSHCON, ANYFIXED, + NAREG, RESC1, + " movei A1,AR\n", }, + +{ OPLTYPE, INAREG, + SANY, ANYFIXED, + SNSHCON, ANYFIXED, + NAREG, RESC1, + " hrroi A1,AR\n", }, + +{ OPLTYPE, INAREG, + SANY, ANYFIXED, + SCON, ANYFIXED, + NAREG|NASR, RESC1, + " ZD A1,ZE # suspekt\n", }, + +{ OPLTYPE, INAREG, + SANY, TWORD|TPOINT|TFLOAT, + SAREG|SAREG|SOREG|SNAME, TWORD|TPOINT|TFLOAT, + NAREG|NASR, RESC1, + " move A1,AR\n", }, + +{ OPLTYPE, INBREG, + SANY, TLL, + SCON, TLL, + NBREG, RESC1, + " dmove A1,ZO\n", }, + +{ OPLTYPE, INBREG, + SANY, TLL|TDOUBLE, + SANY, TLL|TDOUBLE, + NBREG|NBSR, RESC1, + " dmove A1,AR\n", }, + +{ OPLTYPE, INAREG, + SOREG, TSHORT|TUSHORT|TCHAR|TUCHAR, + SOREG, TSHORT|TUSHORT|TCHAR|TUCHAR, + NASR, RESC1, + "ZU", }, + +{ OPLTYPE, INAREG, + SNAME, TUCHAR, + SNAME, TUCHAR, + NAREG|NASR, RESC1, + " ldb A1,[ .long AL ]\n" }, + +{ OPLTYPE, INAREG, + SNAME, TCHAR, + SNAME, TCHAR, + NAREG|NASR, RESC1, + " ldb A1,[ .long AL ]\n" + " ash A1,033\n" + " ash A1,-033\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME, TSHORT|TUSHORT, + NAREG|NASR, RESC1, + "Zi", }, + +{ OPLTYPE, INAREG, + SANY, TWORD|TPOINT, + SCON, TWORD|TPOINT, + NAREG|NASR, RESC1, + "Zc", }, + +{ OPLTYPE, INAREG, + SAREG|SAREG, TUSHORT|TUCHAR, + SAREG|SAREG, TUSHORT|TUCHAR|TWORD, + NAREG, RESC1, + " move A1,AL\n", }, + +/* + * Negate a word. + */ +{ UMINUS, INAREG, + SAREG|SAREG|SNAME|SOREG, TWORD, + SANY, TWORD, + NAREG|NASL, RESC1, + " movn A1,AL\n", }, + +{ UMINUS, INAREG, + SAREG|SAREG, TWORD, + SANY, TCHAR|TUCHAR|TSHORT|TUSHORT, + 0, RLEFT, + " movn AL,AL\n", }, + +{ UMINUS, INAREG, + SAREG|SNAME|SOREG, TLL, + SANY, TLL, + NAREG|NASR, RESC1, + " dmovn A1,AL\n", }, + +{ COMPL, INAREG, + SAREG|SAREG|SNAME|SOREG, TLL, + SANY, TANY, + NAREG|NASL, RESC1, + " setcm A1,AL\n" + " setcm U1,UL\n", }, + +{ COMPL, INAREG, + SAREG|SAREG|SNAME|SOREG, TWORD, + SANY, TANY, + NAREG|NASL, RESC1, + " setcm A1,AL\n", }, + +{ COMPL, INAREG, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT, + SANY, TCHAR|TUCHAR|TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " setcm A1,AL\n", }, + +/* + * Arguments to functions. + */ +{ FUNARG, FOREFF, + SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT, + SANY, TANY, + 0, RNULL, + " push 017,AL\n", }, + +{ FUNARG, FOREFF, + SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT, + SANY, TANY, + 0, RNULL, + " push 017,AL\n", }, + +{ FUNARG, FOREFF, + SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TPOINT|TWORD, + SANY, TANY, + 0, RNULL, + " push 017,[ .long AL]\n", }, + +{ FUNARG, FOREFF, + SBREG, TLL|TDOUBLE, + SANY, TANY, + 0, RNULL, + " push 017,AL\n push 017,UL\n", }, + +{ STARG, FOREFF, + SAREG|SOREG|SNAME|SCON, TANY, + SANY, TSTRUCT, + 0, 0, + "ZG", }, + + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ OPLEAF, DF(NAME), }, + +{ OPUNARY, DF(UMINUS), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/pdp11/code.c b/lang/pcc/pcc/arch/pdp11/code.c new file mode 100644 index 000000000..53d391329 --- /dev/null +++ b/lang/pcc/pcc/arch/pdp11/code.c @@ -0,0 +1,278 @@ +/* $Id: code.c,v 1.8 2015/09/03 19:24:51 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#define NODE P1ND +#undef NIL +#define NIL NULL +#define talloc p1alloc + +/* + * Print out assembler segment name. + */ +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + case DATA: + case LDATA: name = ".data"; break; + case UDATA: break; + case STRNG: + case RDATA: name = ".rodata"; break; + default: + cerror("setseg"); + } + printf("\t%s\n", name); +} + +void +defalign(int al) +{ + if (al > ALCHAR) + printf(".even\n"); +} + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + static char *loctbl[] = { "text", "data", "data" }; + TWORD t; + char *n; + int s; + + t = sp->stype; + s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA; + if (s != lastloc) + printf(" .%s\n", loctbl[s]); + lastloc = s; + n = sp->soname ? sp->soname : exname(sp->sname); + if (sp->sclass == EXTDEF) + printf(" .globl %s\n", n); + if (sp->slevel == 0) { + printf("%s:\n", n); + } else { + printf(LABFMT ":\n", sp->soffset); + } +} + +/* + * code for the end of a function + * deals with struct return here + */ +void +efcode(void) +{ + NODE *p, *q; + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + /* Create struct assignment */ + q = block(OREG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); + q->n_rval = R5; + q->n_lval = 8; /* return buffer offset */ + q = buildtree(UMUL, q, NIL); + p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); + p = buildtree(UMUL, p, NIL); + p = buildtree(ASSIGN, q, p); + ecomp(p); +} + +/* + * code for the beginning of a function; a is an array of + * indices in symtab for the arguments; n is the number + */ +void +bfcode(struct symtab **sp, int cnt) +{ + struct symtab *sp2; + NODE *n; + int i; + + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + /* Function returns struct, adjust arg offset */ + for (i = 0; i < cnt; i++) + sp[i]->soffset += SZPOINT(INT); + } + + if (xtemps == 0) + return; + + /* put arguments in temporaries */ + for (i = 0; i < cnt; i++) { + if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY || + cisreg(sp[i]->stype) == 0) + continue; + sp2 = sp[i]; + n = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap); + n = buildtree(ASSIGN, n, nametree(sp2)); + sp[i]->soffset = regno(n->n_left); + sp[i]->sflags |= STNODE; + ecomp(n); + } +} + + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ +} + +void +bjobcode(void) +{ +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + * Returns p. + */ +NODE * +funcode(NODE *p) +{ + NODE *r, *l; + + /* Fix function call arguments. On x86, just add funarg */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + if (r->n_right->n_op != STARG) + r->n_right = block(FUNARG, r->n_right, NIL, + r->n_right->n_type, r->n_right->n_df, + r->n_right->n_ap); + } + if (r->n_op != STARG) { + l = talloc(); + *l = *r; + r->n_op = FUNARG; + r->n_left = l; + r->n_type = l->n_type; + } + return p; +} + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + +/* + * Return "canonical frame address". + */ +NODE * +builtin_cfa(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} + +NODE * +builtin_return_address(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} + +NODE * +builtin_frame_address(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} + +NODE * +builtin_huge_val(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} +NODE * +builtin_huge_valf(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} +NODE * +builtin_huge_vall(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} +NODE * +builtin_inf(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} +NODE * +builtin_inff(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} +NODE * +builtin_infl(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} +NODE * +builtin_nan(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} +NODE * +builtin_nanf(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} +NODE * +builtin_nanl(const struct bitable *bt, NODE *a) +{ + uerror(__func__); + return bcon(0); +} diff --git a/lang/pcc/pcc/arch/pdp11/local.c b/lang/pcc/pcc/arch/pdp11/local.c new file mode 100644 index 000000000..243a8cb94 --- /dev/null +++ b/lang/pcc/pcc/arch/pdp11/local.c @@ -0,0 +1,400 @@ +/* $Id: local.c,v 1.15 2015/09/03 19:24:51 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#define NODE P1ND +#undef NIL +#define NIL NULL +#define fwalk p1fwalk +#define nfree p1nfree + +/* this file contains code which is dependent on the target machine */ + +/* clocal() is called to do local transformations on + * an expression tree preparitory to its being + * written out in intermediate code. + * + * the major essential job is rewriting the + * automatic variables and arguments in terms of + * REG and OREG nodes + * conversion ops which are not necessary are also clobbered here + * in addition, any special features (such as rewriting + * exclusive or) are easily handled here as well + */ +NODE * +clocal(NODE *p) +{ + + register struct symtab *q; + register NODE *r, *l; + register int o; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + switch( o = p->n_op ){ + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + r->n_lval = 0; + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case STATIC: + if (q->slevel == 0) + break; + p->n_lval = 0; + break; + + case REGISTER: + p->n_op = REG; + p->n_lval = 0; + p->n_rval = q->soffset; + break; + + case EXTERN: + case EXTDEF: + break; + } + break; + + case CBRANCH: + l = p->n_left; + if (coptype(l->n_op) != BITYPE) + break; + if (l->n_left->n_op != SCONV || l->n_right->n_op != ICON) + break; + if ((r = l->n_left->n_left)->n_type > INT) + break; + /* compare with constant without casting */ + nfree(l->n_left); + l->n_left = r; + l->n_right->n_type = l->n_left->n_type; + break; + + case STASG: /* struct assignment, modify left */ + l = p->n_left; + if (l->n_type == STRTY) + p->n_left = buildtree(ADDROF, l, NIL); + break; + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + p->n_left->n_rval = p->n_left->n_type == BOOL ? + RETREG(CHAR) : RETREG(p->n_type); + break; + + } +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal end: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + return(p); +} + +void +myp2tree(NODE *p) +{ + struct symtab *sp; + + if (p->n_op != FCON) + return; + + sp = tmpalloc(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->sap = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + + locctr(DATA, sp); + defloc(sp); + ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + + p->n_op = NAME; + p->n_lval = 0; + p->n_sp = sp; +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * Return 1 if a variable of type type is OK to put in register. + */ +int +cisreg(TWORD t) +{ + if (t == FLOAT || t == DOUBLE || t == LDOUBLE || + t == LONGLONG || t == ULONGLONG) + return 0; /* not yet */ + return 1; +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a storeable node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ + + /* sub the size from sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(MINUSEQ, sp, p)); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); + sp->n_lval = 0; + sp->n_rval = STKREG; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + +} + +/* + * Print out a string of characters. + * Assume that the assembler understands C-style escape + * sequences. + */ +void +instring(struct symtab *sp) +{ + char *s; + int val, cnt; + + defloc(sp); + + for (cnt = 0, s = sp->sname; *s != 0; ) { + if (cnt++ == 0) + printf(".byte "); + if (*s++ == '\\') + val = esccon(&s); + else + val = s[-1]; + printf("%o", val & 0377); + if (cnt > 15) { + cnt = 0; + printf("\n"); + } else + printf(","); + } + printf("%s0\n", cnt ? "" : ".byte "); +} + +/* + * print out a constant node, may be associated with a label. + * Do not free the node after use. + * off is bit offset from the beginning of the aggregate + * fsz is the number of bits this is referring to + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ +#if defined(__pdp11__) || 1 + union { float f; double d; short s[4]; int i[2]; } u; +#endif + TWORD t; + int i; + + t = p->n_type; + switch (t) { + case LONGLONG: + case ULONGLONG: + i = (p->n_lval >> 32); + p->n_lval &= 0xffffffff; + p->n_type = INT; + ninval(off, 32, p); + p->n_lval = i; + ninval(off+32, 32, p); + break; + case LONG: + case ULONG: + printf("%o ; %o\n", (int)((p->n_lval >> 16) & 0177777), + (int)(p->n_lval & 0177777)); + break; +#if defined(__pdp11__) || 1 + case FLOAT: + u.f = (float)p->n_dcon; + printf("%o ; %o\n", u.i[0], u.i[1]); + break; + case LDOUBLE: + case DOUBLE: + u.d = (double)p->n_dcon; + printf("%o ; %o ; %o ; %o\n", u.i[0], u.i[1], u.i[2], u.i[3]); + break; +#else + /* cross-compiling */ + case FLOAT: + printf("%o ; %o\n", p->n_dcon.fd1, p->n_dcon.fd2); + break; + case LDOUBLE: + case DOUBLE: + printf("%o ; %o ; %o ; %o\n", p->n_dcon.fd1, p->n_dcon.fd2, + p->n_dcon.fd3, p->n_dcon.fd4); + break; +#endif + default: + return 0; + } + return 1; +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ +#define NCHNAM 256 + static char text[NCHNAM+1]; + int i; + + if (p == NULL) + return ""; + + text[0] = '_'; + for (i=1; *p && istype, sp->sdf, sp->sap); + off = (off+(SZCHAR-1))/SZCHAR; + n = sp->soname ? sp->soname : exname(sp->sname); + if (sp->sclass == STATIC) { + printf(".bss\n"); + if (sp->slevel == 0) + printf("%s:", n); + else + printf(LABFMT ":", sp->soffset); + printf(" .=.+%o\n", off); + lastloc = -1; + return; + } + printf(".comm "); + if (sp->slevel == 0) + printf("%s,0%o\n", n, off); + else + printf(LABFMT ",0%o\n", sp->soffset, off); +} + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + return 0; +} + +/* + * Called when a identifier has been declared. + */ +void +fixdef(struct symtab *sp) +{ +} + +void +pass1_lastchance(struct interpass *ip) +{ +} diff --git a/lang/pcc/pcc/arch/pdp11/local2.c b/lang/pcc/pcc/arch/pdp11/local2.c new file mode 100644 index 000000000..0c42ff66d --- /dev/null +++ b/lang/pcc/pcc/arch/pdp11/local2.c @@ -0,0 +1,845 @@ +/* $Id: local2.c,v 1.10 2015/06/29 18:49:36 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" +# include +# include + +static int spcoff; +static int argsiz(NODE *p); + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +void +prologue(struct interpass_prolog *ipp) +{ + int addto; + +#ifdef LANG_F77 + if (ipp->ipp_vis) + printf(" .globl %s\n", ipp->ipp_name); + printf("%s:\n", ipp->ipp_name); +#endif + printf("jsr r5,csv\n"); + addto = p2maxautooff; + if (addto >= AUTOINIT/SZCHAR) + addto -= AUTOINIT/SZCHAR; + if (addto & 1) + addto++; + if (addto == 2) + printf("tst -(sp)\n"); + else if (addto == 4) + printf("cmp -(sp),-(sp)\n"); + else if (addto > 4) + printf("sub $%o,sp\n", addto); + spcoff = 0; +} + +void +eoftn(struct interpass_prolog *ipp) +{ + if (spcoff) + comperr("spcoff == %d", spcoff); + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + printf("jmp cret\n"); +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "add"; + break; + case MINUS: + str = "sub"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s%c", str, f); +} + +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(p) NODE *p; +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +/* + * Emit code to compare two long numbers. + */ +static void +twolcomp(NODE *p) +{ + int o = p->n_op; + int s = getlab2(); + int e = p->n_label; + int cb1, cb2; + + if (o >= ULE) + o -= (ULE-LE); + switch (o) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 2, cb2 += 2; + expand(p, 0, "cmp AR,AL\n"); + if (cb1) cbgen(cb1, s); + if (cb2) cbgen(cb2, e); + expand(p, 0, "cmp UR,UL\n"); + cbgen(p->n_op, e); + deflab(s); +} + + +/* + * Generate compare code for long instructions when right node is 0. + */ +static void +lcomp(NODE *p) +{ + switch (p->n_op) { + case EQ: + expand(p, FORCC, "tst AL\n"); + printf("jne 1f\n"); + expand(p, FORCC, "tst UL\n"); + cbgen(EQ, p->n_label); + printf("1:\n"); + break; + case NE: + expand(p, FORCC, "tst AL\n"); + cbgen(NE, p->n_label); + expand(p, FORCC, "tst UL\n"); + cbgen(NE, p->n_label); + break; + case GE: + expand(p, FORCC, "tst AL\n"); + cbgen(GE, p->n_label); + break; + default: + comperr("lcomp %p", p); + } +} + +void +zzzcode(NODE *p, int c) +{ + switch (c) { + case 'A': /* print out - if not first arg */ + if (spcoff || (p->n_type == FLOAT || p->n_type == DOUBLE)) + printf("-"); + spcoff += argsiz(p); + break; + + case 'B': /* arg is pointer to block */ + expand(p->n_left, FOREFF, "mov AL,ZA(sp)\n"); + expand(p->n_left, FOREFF, "sub CR,(sp)\n"); + break; + + case 'C': /* subtract stack after call */ + spcoff -= p->n_qual; + if (spcoff == 0 /* && !(p->n_flags & NLOCAL1) XXX FIXME */) + p->n_qual -= 2; + if (p->n_qual == 2) + printf("tst (sp)+\n"); + else if (p->n_qual == 4) + printf("cmp (sp)+,(sp)+\n"); + else if (p->n_qual > 2) + printf("add $%o,sp\n", (int)p->n_qual); + break; + + case 'D': /* long comparisions */ + lcomp(p); + break; + + case 'E': /* long move */ + rmove(p->n_right->n_reg, p->n_left->n_reg, p->n_type); + break; + + case 'F': /* long comparision */ + twolcomp(p); + break; + + case 'G': /* printout a subnode for post-inc */ + adrput(stdout, p->n_left->n_left); + break; + + case 'H': /* arg with post-inc */ + expand(p->n_left->n_left, FOREFF, "mov AL,ZA(sp)\n"); + expand(p->n_left->n_left, FOREFF, "inc AL\n"); + break; + + case 'Q': /* struct assignment, no rv */ + printf("mov $%o,", attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/2); + expand(p, INAREG, "A1\n"); + printf("1:\n"); + expand(p, INAREG, "mov (AR)+,(AL)+\n"); + expand(p, INAREG, "dec A1\n"); + printf("jne 1b\n"); + break; + + case 'R': /* struct assignment with rv */ + printf("mov $%o,", attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/2); + expand(p, INAREG, "A1\n"); + expand(p, INAREG, "mov AR,A2\n"); + printf("1:\n"); + expand(p, INAREG, "mov (A2)+,(AL)+\n"); + expand(p, INAREG, "dec A1\n"); + printf("jne 1b\n"); + break; + + case '1': /* lower part of double regs */ + p = getlr(p, '1'); + printf("r%c", rnames[p->n_rval][1]); + break; + + default: + comperr("zzzcode %c", c); + } +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o==NAME || o==REG || o==ICON || o==OREG || + (o==UMUL && shumul(p->n_left, STARNM|SOREG))) + return(1); + return(0); +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + int o = p->n_op; + + if (o == OREG || o == REG || o == NAME) + return SRDIR; /* Direct match */ + if (o == UMUL && shumul(p->n_left, SOREG)) + return SROREG; /* Convert into oreg */ + return SRREG; /* put it into a register */ +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + return 0; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(p->n_rval)); + + case OREG: + r = p->n_rval; + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +static void +negcon(FILE *fp, int con) +{ + if (con < 0) + fprintf(fp, "-"), con = -con; + fprintf(fp, "%o", con & 0177777); +} + +void +adrcon(CONSZ val) +{ + printf("$" CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + int val = p->n_lval; + + switch (p->n_op) { + case ICON: + printf("$"); + if (p->n_name[0] != '\0') { + fprintf(fp, "%s", p->n_name); + if (val) + fprintf(fp, "+%o", val & 0177777); + } else if (p->n_type == LONG || p->n_type == ULONG) + negcon(fp, val >> 16); + else + negcon(fp, val); + return; + + default: + comperr("illegal conput, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + size /= SZINT; + switch (p->n_op) { + case NAME: + case OREG: + p->n_lval += size; + adrput(stdout, p); + p->n_lval -= size; + break; + case REG: + printf("r%c", rnames[p->n_rval][2]); + break; + case ICON: + /* On PDP11 upper value is low 16 bits */ + printf("$"); + negcon(stdout, p->n_lval & 0177777); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +/* + * output an address, with offsets, from p + */ +void +adrput(FILE *io, NODE *p) +{ + int r; + + if (p->n_op == FLD) + p = p->n_left; + + switch (p->n_op) { + case NAME: + if (p->n_name[0] != '\0') { + fputs(p->n_name, io); + if (p->n_lval != 0) + fprintf(io, "+%o", (int)(p->n_lval&0177777)); + } else + negcon(io, p->n_lval); + return; + + case OREG: + r = p->n_rval; + if (p->n_name[0]) + printf("%s%s", p->n_name, p->n_lval ? "+" : ""); + if (R2TEST(r) && R2UPK3(r) == 0) + printf("*"); + if (p->n_lval) + negcon(io, p->n_lval); + if (R2TEST(r)) { + fprintf(io, "(%s)", rnames[R2UPK1(r)]); + if (R2UPK3(r) == 1) + fprintf(io, "+"); + } else + fprintf(io, "(%s)", rnames[p->n_rval]); + return; + case ICON: + /* addressable value of the constant */ + conput(io, p); + return; + + case REG: + switch (p->n_type) { + case LONG: + case ULONG: + fprintf(io, "r%c", rnames[p->n_rval][1]); + break; + default: + fprintf(io, "%s", rnames[p->n_rval]); + } + return; + + case UMUL: + if (tshape(p, STARNM)) { + printf("*"); + adrput(io, p->n_left); + break; + } + /* FALLTHROUGH */ + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +static char * +ccbranches[] = { + "jeq", /* jumpe */ + "jne", /* jumpn */ + "jle", /* jumple */ + "jlt", /* jumpl */ + "jge", /* jumpge */ + "jgt", /* jumpg */ + "jlos", /* jumple (jlequ) */ + "jlo", /* jumpl (jlssu) */ + "jhis", /* jumpge (jgequ) */ + "jhi", /* jumpg (jgtru) */ +}; + + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + if (o < EQ || o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf("%s " LABFMT "\n", ccbranches[o-EQ], lab); +} + +#define IS1CON(p) ((p)->n_op == ICON && (p)->n_lval == 1) + +/* + * Move postfix operators to the next statement, unless they are + * within a function call or a branch. + */ +static void +cvtree(NODE *p, struct interpass *ip2) +{ + struct interpass *ip; + NODE *q; + + if (callop(p->n_op) || p->n_op == CBRANCH) + return; + + if ((p->n_op == PLUS || p->n_op == MINUS) && + IS1CON(p->n_right) && (q = p->n_left)->n_op == ASSIGN && + treecmp(q->n_left, q->n_right->n_left) && + IS1CON(q->n_right->n_right)) { + if ((p->n_op == PLUS && q->n_right->n_op == MINUS) || + (p->n_op == MINUS && q->n_right->n_op == PLUS)) { + nfree(p->n_right); + *p = *q->n_left; + if (optype(p->n_op) != LTYPE) + p->n_left = tcopy(p->n_left); + ip = ipnode(q); + DLIST_INSERT_AFTER(ip2, ip, qelem); + return; + } + } + if (optype(p->n_op) == BITYPE) + cvtree(p->n_right, ip2); + if (optype(p->n_op) != LTYPE) + cvtree(p->n_left, ip2); +} + +/* + * Convert AND to BIC. + */ +static void +fixops(NODE *p, void *arg) +{ + static int fltwritten; + + if (!fltwritten && (p->n_type == FLOAT || p->n_type == DOUBLE)) { + printf(".globl fltused\n"); + fltwritten = 1; + } + switch (p->n_op) { + case AND: + if (p->n_right->n_op == ICON) { + p->n_right->n_lval = ((~p->n_right->n_lval) & 0177777); + } else if (p->n_right->n_op == COMPL) { + NODE *q = p->n_right->n_left; + nfree(p->n_right); + p->n_right = q; + } else + p->n_right = mkunode(COMPL, p->n_right, 0, p->n_type); + break; + case RS: + p->n_right = mkunode(UMINUS, p->n_right, 0, p->n_right->n_type); + p->n_op = LS; + break; + case EQ: + case NE: /* Hack not to clear bits if FORCC */ + if (p->n_left->n_op == AND) + fixops(p->n_left, 0); /* Convert an extra time */ + break; + } +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + +#ifdef PCC_DEBUG + if (x2debug) { + printf("myreader before\n"); + printip(ipole); + } +#endif + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, fixops, 0); + canon(ip->ip_node); /* call it early */ + } +#ifdef PCC_DEBUG + if (x2debug) { + printf("myreader middle\n"); + printip(ipole); + } +#endif + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type == IP_NODE) + cvtree(ip->ip_node, ip); + } +#ifdef PCC_DEBUG + if (x2debug) { + printf("myreader after\n"); + printip(ipole); + } +#endif +} + +/* + * Remove SCONVs where the left node is an OREG with a smaller type. + */ +static void +delsconv(NODE *p, void *arg) +{ +#if 0 + NODE *l; + + if (p->n_op != SCONV || (l = p->n_left)->n_op != OREG) + return; + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == LONG) { + p->n_op = OREG; + p->n_lval = l->n_lval; /* high word */ + p->n_rval = l->n_rval; + nfree(l); + } +#endif + /* Could do this for char etc. also */ +} + +void +mycanon(NODE *p) +{ + walkf(p, delsconv, 0); +} + +void +myoptim(struct interpass *ip) +{ +} + +void +rmove(int s, int d, TWORD t) +{ + if (t < LONG || t > BTMASK) { + printf("mov%s %s,%s\n", t < SHORT ? "b" : "", + rnames[s],rnames[d]); /* XXX char should be full reg? */ + } else if (t == LONG || t == ULONG) { + /* avoid trashing double regs */ + if (d > s) + printf("mov r%c,r%c\nmov r%c,r%c\n", + rnames[s][2],rnames[d][2], + rnames[s][1],rnames[d][1]); + else + printf("mov r%c,r%c\nmov r%c,r%c\n", + rnames[s][1],rnames[d][1], + rnames[s][2],rnames[d][2]); + } else if (t == FLOAT || t == DOUBLE) { + printf("movf %s,%s\n", rnames[s],rnames[d]); + } else + comperr("bad float rmove: %d %d %x", s, d, t); + +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int c, int *r) +{ + switch (c) { + case CLASSA: + return (r[CLASSB] * 2 + r[CLASSA]) < 5; + case CLASSB: + if (r[CLASSB] > 1) return 0; + if (r[CLASSB] == 1 && r[CLASSA] > 0) return 0; + if (r[CLASSA] > 2) return 0; + return 1; + case CLASSC: + return r[CLASSC] < 8; + } + return 0; +} + +char *rnames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc", + "r01", "r12", "r23", "r34", "XXX", "XXX", "XXX", "XXX", + "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "XXX", "XXX", +}; + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t < LONG || t > BTMASK) + return CLASSA; + if (t == LONG || t == ULONG) + return CLASSB; + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) + return CLASSC; + comperr("gclass"); + return CLASSD; +} + +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (t == LONG || t == ULONG || t == FLOAT) + return 4; + if (t == DOUBLE) + return 8; + if (t == STRTY || t == UNIONTY) + return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + return 2; +} + +/* + * Argument specialties. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + + /* + * Calculate arg sizes. + * Mark first arg not to have - before it. + */ + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) { + p->n_right->n_qual = 0; + size += argsiz(p->n_right); + } + p->n_qual = 0; + size += argsiz(p); + p = op->n_right; + + if (p->n_op == CM) + p = p->n_right; +#if 0 /* XXX fixme */ + if (p->n_type == FLOAT || p->n_type == DOUBLE || + p->n_type == STRTY || p->n_type == UNIONTY) + op->n_flags |= NLOCAL1; /* Does not use stack slot */ + else + op->n_flags &= ~NLOCAL1; +#endif + op->n_qual = size; /* XXX */ +} + +static int +is1con(NODE *p) +{ + if (p->n_op == ICON && p->n_lval == 1) + return 1; + return 0; +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + CONSZ s; + + switch (shape) { + case SANDSCON: + s = ~p->n_lval; + if (s < 65536 || s > -65537) + return SRDIR; + break; + case SINCB: /* Check if subject for post-inc */ + if (p->n_op == ASSIGN && p->n_right->n_op == PLUS && + treecmp(p->n_left, p->n_right->n_left) && + is1con(p->n_right->n_right)) + return SRDIR; + break; + case SARGSUB: + if (p->n_op == MINUS && p->n_right->n_op == ICON && + p->n_left->n_op == REG) + return SRDIR; + break; + case SARGINC: + if (p->n_op == MINUS && is1con(p->n_right)) + return special(p->n_left, SINCB); + break; + } + return SRNOPE; +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ +} + +/* + * Do something target-dependent for xasm arguments. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + return 0; +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + return 0; +} + diff --git a/lang/pcc/pcc/arch/pdp11/macdefs.h b/lang/pcc/pcc/arch/pdp11/macdefs.h new file mode 100644 index 000000000..1c8a75c9d --- /dev/null +++ b/lang/pcc/pcc/arch/pdp11/macdefs.h @@ -0,0 +1,235 @@ +/* $Id: macdefs.h,v 1.11 2016/03/05 15:53:04 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = i ? (val<<8)|lastcon : val + +#define ARGINIT 32 /* # bits above r5 where arguments start */ +#define AUTOINIT 64 /* # bits below r5 where automatics start */ + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZBOOL 8 +#define SZINT 16 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 64 +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 64 +#define SZPOINT(t) 16 + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALBOOL 8 +#define ALINT 16 +#define ALFLOAT 16 +#define ALDOUBLE 16 +#define ALLDOUBLE 16 +#define ALLONG 16 +#define ALLONGLONG 16 +#define ALSHORT 16 +#define ALPOINT 16 +#define ALSTRUCT 16 +#define ALSTACK 16 + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT (-0x7fff-1) +#define MAX_INT 0x7fff +#define MAX_UNSIGNED 0xffff +#define MIN_LONG (-0x7fffffff-1) +#define MAX_LONG 0x7fffffff +#define MAX_ULONG 0xffffffff +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +/* Default char is signed */ +#undef CHAR_UNSIGNED +#define BOOL_TYPE CHAR /* what used to store _Bool */ + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#define LABFMT "L%d" /* format for printing labels */ +#ifdef LANG_F77 +#define BLANKCOMMON "_BLNK_" +#define MSKIREG (M(TYSHORT)|M(TYLONG)) +#define TYIREG TYLONG +#define FSZLENG FSZLONG +#define AUTOREG EBP +#define ARGREG EBP +#define ARGOFFSET 8 +#endif + +#define BACKAUTO /* stack grows negatively for automatics */ +#define BACKTEMP /* stack grows negatively for temporaries */ + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_LE /* XXX TARGET_PDP */ +#define MYINSTRING +#define MYALIGN + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&01) +#define wdal(k) (BYTEOFF(k)==0) + +#define STOARG(p) +#define STOFARG(p) +#define STOSTARG(p) + +#define FINDMOPS /* pdp11 has instructions that modifies memory */ + +#define szty(t) ((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG ? 4 : \ + (t) == FLOAT || (t) == LONG || (t) == ULONG ? 2 : 1) + +/* + * The pdp11 has 3 register classes, 16-bit, 32-bit and floats. + * Class membership and overlaps are defined in the macros RSTATUS + * and ROVERLAP below. + * + * The classes used on pdp11 are: + * A - 16-bit + * B - 32-bit (concatenated 16-bit) + * C - floating point + */ +#define R0 000 /* Scratch and return register */ +#define R1 001 /* Scratch and secondary return register */ +#define R2 002 /* Scratch register */ +#define R3 003 /* Scratch register */ +#define R4 004 /* Scratch register */ +#define R5 005 /* Frame pointer */ +#define SP 006 /* Stack pointer */ +#define PC 007 /* Program counter */ + +#define R01 010 +#define R12 011 +#define R23 012 +#define R34 013 + +#define FR0 020 +#define FR1 021 +#define FR2 022 +#define FR3 023 +#define FR4 024 +#define FR5 025 +#define FR6 026 +#define FR7 027 + +#define MAXREGS 030 /* 24 registers */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG, SAREG, SAREG, 0, 0, 0, \ + SBREG, SBREG, SBREG, SBREG, 0, 0, 0, 0, \ + SCREG, SCREG, SCREG, SCREG, 0, 0, 0, 0 + +#define ROVERLAP \ + /* 8 basic registers */\ + { R01, -1 }, \ + { R01, R12, -1 }, \ + { R12, R23, -1 }, \ + { R23, R34, -1 }, \ + { R34, -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ +\ + /* 4 long registers */\ + { R0, R1, R12, -1 }, \ + { R1, R2, R01, R23, -1 }, \ + { R2, R3, R12, R34, -1 }, \ + { R3, R4, R23, -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ +\ + /* The fp registers do not overlap with anything */\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 },\ + { -1 }, + + +/* Return a register class based on the type of the node */ + +#define PCLASS(p) (p->n_type < LONG || p->n_type > BTMASK ? SAREG : \ + (p->n_type == LONG || p->n_type == ULONG ? SBREG : SCREG)) + +#define NUMCLASS 3 /* highest number of reg classes used */ + +int COLORMAP(int c, int *r); +#define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : CLASSC) +#define DECRA(x,y) (((x) >> (y*5)) & 31) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 5) /* A1 */ +#define ENCRA2(x) ((x) << 10) /* A2 */ +#define ENCRA(x,y) ((x) << (5+y*5)) /* encode regs in int */ +#define RETREG(x) ((x) == LONG || (x) == ULONG ? R01 : \ + (x) == FLOAT || (x) == DOUBLE ? FR0 : R0) + +//#define R2REGS 1 /* permit double indexing */ + +/* XXX - to die */ +#define FPREG R5 /* frame pointer */ +#define STKREG SP /* stack pointer */ + +/* A bunch of specials to make life easier for pdp11 */ +#define SANDSCON (MAXSPECIAL+1) +#define SINCB (MAXSPECIAL+2) /* post-increment */ +#define SINCW (MAXSPECIAL+3) /* post-increment */ +#define SARGSUB (MAXSPECIAL+4) /* arg pointer to array */ +#define SARGINC (MAXSPECIAL+5) /* post-increment arg */ diff --git a/lang/pcc/pcc/arch/pdp11/order.c b/lang/pcc/pcc/arch/pdp11/order.c new file mode 100644 index 000000000..15d1588b2 --- /dev/null +++ b/lang/pcc/pcc/arch/pdp11/order.c @@ -0,0 +1,249 @@ +/* $Id: order.c,v 1.3 2008/10/04 08:43:17 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +#include + +int canaddr(NODE *); + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + return(0); /* YES */ +} + +static int +inctree(NODE *p) +{ + if (p->n_op == MINUS && p->n_left->n_op == ASSIGN && + p->n_left->n_right->n_op == PLUS && + treecmp(p->n_left->n_left, p->n_left->n_right->n_left) && + p->n_right->n_op == ICON && p->n_right->n_lval == 1 && + p->n_left->n_right->n_right->n_op == ICON && + p->n_left->n_right->n_right->n_lval == 1) { + /* post-increment by 1; (r0)+ */ + if (isreg(p->n_left->n_left)) /* Ignore if index not in reg */ + return 1; + } + return 0; +} + +/* + * Turn a UMUL-referenced node into OREG. + * Be careful about register classes, this is a place where classes change. + */ +void +offstar(NODE *p, int shape) +{ + if (x2debug) + printf("offstar(%p)\n", p); + + if (isreg(p)) + return; /* Is already OREG */ + + if (p->n_op == UMUL) + p = p->n_left; /* double indexed umul */ + + if (inctree(p)) /* Do post-inc conversion */ + return; + + if( p->n_op == PLUS || p->n_op == MINUS ){ + if (p->n_right->n_op == ICON) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + } + (void)geninsn(p, INAREG); +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + */ +void +myormake(NODE *p) +{ + NODE *q = p->n_left; + + if (x2debug) { + printf("myormake(%p)\n", p); + fwalk(p, e2print, 0); + } + if (inctree(q)) { + if (q->n_left->n_left->n_op == TEMP) + return; + p->n_op = OREG; + p->n_lval = 0; /* Add support for index offset */ + p->n_rval = R2PACK(regno(q->n_left->n_left), 0, 1); + tfree(q); + return; + } + if (q->n_op != OREG) + return; + p->n_op = OREG; + p->n_lval = q->n_lval; + p->n_rval = R2PACK(q->n_rval, 0, 0); + nfree(q); +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + if (p->n_op == NAME && (shape & STARNM)) + return SRDIR; + if (shape & SOREG) + return SROREG; /* Calls offstar */ + return SRNOPE; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return(0); +} + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + case MUL: + if (q->visit == INAREG) { + static struct rspecial s[] = { { NLEFT, R1 }, { 0 } }; + return s; + } else if (q->visit == INBREG) { + static struct rspecial s[] = { { NRES, R01 }, { 0 } }; + return s; + } + break; + + case DIV: + if (q->visit == INAREG && q->ltype == TUNSIGNED) { + static struct rspecial s[] = { + { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } }; + return s; + } else if (q->visit == INAREG) { + static struct rspecial s[] = { + { NRES, R0 }, { 0 } }; + return s; + } else if (q->visit == INBREG) { + static struct rspecial s[] = { { NRES, R01 }, { 0 } }; + return s; + } + break; + + case MOD: + if (q->visit == INAREG && q->ltype == TUNSIGNED) { + static struct rspecial s[] = { + { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } }; + return s; + } else if (q->visit == INBREG) { + static struct rspecial s[] = { { NRES, R01 }, { 0 } }; + return s; + } + break; + + case SCONV: + if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R1 }, { NRES, R01 }, { 0 } }; + return s; + } + break; + } + comperr("nspecial entry %d", q - table); + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; /* nothing differs on x86 */ +} + +/* + * set registers in calling conventions live. + */ +int * +livecall(NODE *p) +{ + static int r[] = { -1 }; + + return r; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/pdp11/table.c b/lang/pcc/pcc/arch/pdp11/table.c new file mode 100644 index 000000000..586b039f3 --- /dev/null +++ b/lang/pcc/pcc/arch/pdp11/table.c @@ -0,0 +1,843 @@ +/* $Id: table.c,v 1.5 2008/10/19 15:25:25 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass2.h" + +# define TLL TLONGLONG|TULONGLONG +# define ANYSIGNED TINT|TLONG|TSHORT|TCHAR +# define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR +# define ANYFIXED ANYSIGNED|ANYUSIGNED +# define TUWORD TUNSIGNED +# define TSWORD TINT +# define TWORD TUWORD|TSWORD +# define ANYSH SCON|SAREG|SOREG|SNAME +# define ARONS SAREG|SOREG|SNAME|STARNM + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are usually not necessary */ +{ PCONV, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + "", }, + +/* convert char to int or unsigned */ +{ SCONV, INAREG, + SAREG, TCHAR, + SAREG, TINT|TUNSIGNED, + NAREG|NASL, RESC1, + "", }, /* chars are stored as ints in registers */ + +{ SCONV, INAREG, + SOREG|SCON|SNAME, TCHAR, + SAREG, TINT, + NAREG|NASL, RESC1, + "movb AL,A1\n", }, + +/* convert uchar to int or unsigned */ +{ SCONV, INAREG, + SAREG|SOREG|SCON|SNAME, TUCHAR, + SAREG, TINT|TUNSIGNED, + NAREG, RESC1, + "clr A1\nbisb AL,A1\n", }, + +/* convert (u)int to (u)char. Nothing to do. */ +{ SCONV, INAREG, + SAREG, TWORD, + SANY, TCHAR|TUCHAR, + 0, RLEFT, + "", }, + +/* convert (u)int to (u)int */ +{ SCONV, INAREG, + SAREG, TWORD, + SANY, TWORD, + 0, RLEFT, + "", }, + +/* convert pointer to (u)int */ +{ SCONV, INAREG, + SAREG, TPOINT, + SANY, TWORD, + 0, RLEFT, + "", }, + +/* convert int to long from memory */ +{ SCONV, INBREG, + SNAME|SOREG, TINT, + SANY, TLONG, + NBREG, RESC1, + "mov AL,U1\nsxt A1\n", }, + +/* int -> (u)long. XXX - only in r0 and r1 */ +{ SCONV, INBREG, + SAREG, TINT, + SANY, TLONG|TULONG, + NSPECIAL|NBREG|NBSL, RESC1, + "tst AL\nsxt r0\n", }, + +/* unsigned -> (u)long. XXX - only in r0 and r1 */ +{ SCONV, INBREG, + SAREG, TUNSIGNED, + SANY, TLONG|TULONG, + NSPECIAL|NBREG|NBSL, RESC1, + "clr r0\n", }, + +/* uint -> double */ +{ SCONV, INCREG, + SAREG|SNAME|SOREG|SCON, TUNSIGNED, + SANY, TFLOAT|TDOUBLE, + NCREG|NCSL, RESC1, + "mov AL,-(sp)\nclr -(sp)\n" + "setl\nmovif (sp)+,A1\nseti\n", }, + +/* long -> int */ +{ SCONV, INAREG, + SBREG|SOREG|SNAME, TLONG|TULONG, + SAREG, TWORD, + NAREG|NASL, RESC1, + "mov UL,A1\n", }, + + +/* (u)long -> (u)long, nothing */ +{ SCONV, INBREG, + SBREG, TLONG|TULONG, + SANY, TLONG|TULONG, + NBREG|NBSL, RESC1, + "", }, + +/* long -> double */ +{ SCONV, INCREG, + SBREG|SNAME|SOREG|SCON, TLONG, + SANY, TFLOAT|TDOUBLE, + NCREG|NCSL, RESC1, + "mov UL,-(sp)\nmov AL,-(sp)\n" + "setl\nmovif (sp)+,A1\nseti\n", }, + +/* + * Subroutine calls. + */ +{ CALL, INBREG, + SCON, TANY, + SBREG, TLONG|TULONG, + NBREG|NBSL, RESC1, + "jsr pc,*CL\nZC", }, + +{ UCALL, INBREG, + SCON, TANY, + SBREG, TLONG|TULONG, + NBREG|NBSL, RESC1, + "jsr pc,*CL\n", }, + +{ CALL, FOREFF, + SCON|SNAME|SOREG, TANY, + SANY, TANY, + 0, 0, + "jsr pc,*AL\nZC", }, + +{ UCALL, FOREFF, + SCON|SNAME|SOREG, TANY, + SANY, TANY, + 0, 0, + "jsr pc,*AL\n", }, + +{ CALL, INAREG, + SCON|SOREG|SNAME, TANY, + SAREG, TWORD|TPOINT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + "jsr pc,*AL\nZC", }, + +{ UCALL, INAREG, + SCON|SOREG|SNAME, TANY, + SAREG, TWORD|TPOINT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + "jsr pc,*AL\n", }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + "jsr pc,(AL)\nZC", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + "jsr pc,(AL)\n", }, + +{ CALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "jsr pc,(AL)\nZC", }, + +{ UCALL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + "jsr pc,(AL)\n", }, + +/* + * The next rules handle all binop-style operators. + */ +/* Add one to anything left but use only for side effects */ +{ PLUS, FOREFF|INAREG|FORCC, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SONE, TANY, + 0, RLEFT|RESCC, + "inc AL\n", }, + +/* add one for char to reg, special handling */ +{ PLUS, FOREFF|INAREG|FORCC, + SAREG, TCHAR|TUCHAR, + SONE, TANY, + 0, RLEFT|RESCC, + "inc AL\n", }, + +/* add one for char to memory */ +{ PLUS, FOREFF|FORCC, + SNAME|SOREG|STARNM, TCHAR|TUCHAR, + SONE, TANY, + 0, RLEFT|RESCC, + "incb AL\n", }, + +{ PLUS, INBREG|FOREFF, + SBREG, TLONG, + SBREG|SNAME|SOREG|SCON, TLONG, + 0, RLEFT, + "add AR,AL\nadd UR,UL\nadc AL\n", }, + +/* Add to reg left and reclaim reg */ +{ PLUS, INAREG|FOREFF|FORCC, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT|RESCC, + "add AR,AL\n", }, + +/* Add to anything left but use only for side effects */ +{ PLUS, FOREFF|FORCC, + SNAME|SOREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT|RESCC, + "add AR,AL\n", }, + +{ PLUS, INAREG|FOREFF|FORCC, + SAREG, TCHAR|TUCHAR, + SAREG|SNAME|SOREG|SCON, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + "add AR,AL\n", }, + +/* Post-increment read, byte */ +{ MINUS, INAREG, + SINCB, TCHAR|TUCHAR, + SONE, TANY, + NAREG, RESC1, + "movb ZG,A1\nincb ZG\n", }, + +/* Post-increment read, int */ +{ MINUS, INAREG, + SINCB, TWORD|TPOINT, + SONE, TANY, + NAREG, RESC1, + "mov ZG,A1\ninc ZG\n", }, + +{ MINUS, INBREG|FOREFF, + SBREG, TLONG|TULONG, + SBREG|SNAME|SOREG|SCON, TLONG|TULONG, + 0, RLEFT, + "sub AR,AL\nsub UR,UL\nsbc AL\n", }, + +/* Sub one from anything left */ +{ MINUS, FOREFF|INAREG|FORCC, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SONE, TANY, + 0, RLEFT|RESCC, + "dec AL\n", }, + +{ MINUS, INAREG|FOREFF, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT, + "sub AR,AL\n", }, + +/* Sub from anything left but use only for side effects */ +{ MINUS, FOREFF|INAREG|FORCC, + SAREG|SNAME|SOREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RLEFT|RESCC, + "sub AR,AL\n", }, + +/* Sub one left but use only for side effects */ +{ MINUS, FOREFF|FORCC, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SONE, TANY, + 0, RLEFT|RESCC, + "decb AL\n", }, + +/* Sub from anything left but use only for side effects */ +{ MINUS, FOREFF|FORCC, + SAREG|SNAME|SOREG, TCHAR|TUCHAR, + SAREG|SNAME|SOREG|SCON, TCHAR|TUCHAR|TWORD|TPOINT, + 0, RLEFT|RESCC, + "subb AR,AL\n", }, + +/* + * The next rules handle all shift operators. + */ +{ LS, INBREG|FOREFF, + SBREG, TLONG|TULONG, + SANY, TANY, + 0, RLEFT, + "ashc AR,AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG, TWORD, + SONE, TANY, + 0, RLEFT, + "asl AL\n", }, + +{ LS, INAREG|FOREFF, + SAREG, TWORD, + ANYSH, TWORD, + 0, RLEFT, + "ash AR,AL\n", }, + +/* + * The next rules takes care of assignments. "=". + */ + +/* First optimizations, in lack of weight it uses first found */ +/* Start with class A registers */ + +/* Clear word at address */ +{ ASSIGN, FOREFF|FORCC, + ARONS, TWORD|TPOINT, + SZERO, TANY, + 0, RESCC, + "clr AL\n", }, + +/* Clear word at reg */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SZERO, TANY, + 0, RDEST, + "clr AL\n", }, + +/* Clear byte at address. No reg here. */ +{ ASSIGN, FOREFF, + SNAME|SOREG|STARNM, TCHAR|TUCHAR, + SZERO, TANY, + 0, RDEST, + "clrb AL\n", }, + +/* Clear byte in reg. must clear the whole register. */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TCHAR|TUCHAR, + SZERO, TANY, + 0, RDEST, + "clr AL\n", }, + +/* The next is class B regs */ + +/* Clear long at address or in reg */ +{ ASSIGN, FOREFF|INBREG, + SNAME|SOREG|SBREG, TLONG|TULONG, + SZERO, TANY, + 0, RDEST, + "clr AL\nclr UL\n", }, + +/* Save 2 bytes if high-order bits are zero */ +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONG|TULONG, + SSCON, TLONG, + 0, RDEST, + "mov UR,UL\nsxt AL\n", }, + +/* Must have multiple rules for long otherwise regs may be trashed */ +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONG|TULONG, + SCON|SNAME|SOREG, TLONG|TULONG, + 0, RDEST, + "mov AR,AL\nmov UR,UL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SNAME|SOREG, TLONG|TULONG, + SBREG, TLONG|TULONG, + 0, RDEST, + "mov AR,AL\nmov UR,UL\n", }, + +{ ASSIGN, FOREFF, + SNAME|SOREG, TLONG|TULONG, + SCON|SNAME|SOREG, TLONG|TULONG, + 0, 0, + "mov AR,AL\nmov UR,UL\n", }, + +{ ASSIGN, INBREG|FOREFF, + SBREG, TLONG|TULONG, + SBREG, TLONG|TULONG, + 0, RDEST, + "ZE\n", }, + +{ ASSIGN, FOREFF|INAREG|FORCC, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RDEST|RESCC, + "mov AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG|FORCC, + ARONS, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RDEST|RESCC, + "mov AR,AL\n", }, + +{ ASSIGN, FOREFF|FORCC, + SNAME|SOREG, TWORD|TPOINT, + SNAME|SOREG|SCON, TWORD|TPOINT, + 0, RESCC, + "mov AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG|FORCC, + SAREG, TCHAR|TUCHAR, + ARONS|SCON, TCHAR|TUCHAR, + 0, RDEST|RESCC, + "movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG|FORCC, + ARONS, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + 0, RDEST|RESCC, + "movb AR,AL\n", }, + +{ ASSIGN, FOREFF|FORCC, + SNAME|SOREG|STARNM, TCHAR|TUCHAR, + SNAME|SOREG|SCON|STARNM, TCHAR|TUCHAR, + 0, RDEST|RESCC, + "movb AR,AL\n", }, + +{ ASSIGN, FOREFF|INCREG, + SCREG, TDOUBLE, + SNAME|SOREG|SCON, TDOUBLE, + 0, RDEST, + "movf AR,AL\n", }, + +{ ASSIGN, FOREFF|INCREG, + SCREG, TFLOAT, + SNAME|SOREG|SCON, TFLOAT, + 0, RDEST, + "movof AR,AL\n", }, + +{ ASSIGN, FOREFF|INCREG, + SNAME|SOREG|SCREG, TDOUBLE, + SCREG, TDOUBLE, + 0, RDEST, + "movf AR,AL\n", }, + +{ ASSIGN, FOREFF|INCREG, + SNAME|SOREG|SCREG, TFLOAT, + SCREG, TFLOAT, + 0, RDEST, + "movfo AR,AL\n", }, + +/* + * DIV/MOD/MUL + */ +/* XXX - mul may use any odd register, only r1 for now */ +{ MUL, INAREG, + SAREG, TWORD|TPOINT, + SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, + NSPECIAL, RLEFT, + "mul AR,AL\n", }, + +{ MUL, INBREG, + SBREG|SNAME|SCON|SOREG, TLONG|TULONG, + SBREG|SNAME|SCON|SOREG, TLONG|TULONG, + NSPECIAL|NBREG|NBSL|NBSR, RESC1, + "mov UR,-(sp)\nmov AR,-(sp)\n" + "mov UL,-(sp)\nmov AL,-(sp)\n" + "jsr pc,lmul\nadd $10,sp\n", }, + +{ MUL, INCREG, + SCREG, TFLOAT|TDOUBLE, + SCREG|SNAME|SOREG, TFLOAT|TDOUBLE, + 0, RLEFT, + "mulf AR,AL\n", }, + +/* need extra move to be sure N flag is correct for sxt */ +{ DIV, INAREG, + ANYSH, TINT|TPOINT, + ANYSH, TINT|TPOINT, + NSPECIAL, RDEST, + "mov AL,r1\nsxt r0\ndiv AR,r0\n", }, + +/* udiv uses args in registers */ +{ DIV, INAREG, + SAREG, TUNSIGNED, + SAREG, TUNSIGNED, + NSPECIAL|NAREG|NASL|NASR, RESC1, + "jsr pc,udiv\n", }, + +{ DIV, INBREG, + SBREG|SNAME|SCON|SOREG, TLONG|TULONG, + SBREG|SNAME|SCON|SOREG, TLONG|TULONG, + NSPECIAL|NBREG|NBSL|NBSR, RESC1, + "mov UR,-(sp)\nmov AR,-(sp)\n" + "mov UL,-(sp)\nmov AL,-(sp)\n" + "jsr pc,ldiv\nadd $10,sp\n", }, + +{ DIV, INCREG, + SCREG, TFLOAT|TDOUBLE, + SCREG|SNAME|SOREG, TFLOAT|TDOUBLE, + 0, RLEFT, + "divf AR,AL\n", }, + +/* XXX merge the two below to one */ +{ MOD, INBREG, + SBREG|SNAME|SCON|SOREG, TLONG, + SBREG|SNAME|SCON|SOREG, TLONG, + NSPECIAL|NBREG|NBSL|NBSR, RESC1, + "mov UR,-(sp)\nmov AR,-(sp)\n" + "mov UL,-(sp)\nmov AL,-(sp)\n" + "jsr pc,lrem\nadd $10,sp\n", }, + +{ MOD, INBREG, + SBREG|SNAME|SCON|SOREG, TULONG, + SBREG|SNAME|SCON|SOREG, TULONG, + NSPECIAL|NBREG|NBSL|NBSR, RESC1, + "mov UR,-(sp)\nmov AR,-(sp)\n" + "mov UL,-(sp)\nmov AL,-(sp)\n" + "jsr pc,ulrem\nadd $10,sp\n", }, + +/* urem uses args in registers */ +{ MOD, INAREG, + SAREG, TUNSIGNED, + SAREG, TUNSIGNED, + NSPECIAL|NAREG|NASL|NASR, RESC1, + "jsr pc,urem\n", }, + +/* + * Indirection operators. + */ +{ UMUL, INBREG, + SANY, TPOINT|TWORD, + SOREG, TLONG|TULONG, + NBREG, RESC1, /* |NBSL - may overwrite index reg */ + "mov AR,A1\nmov UR,U1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG|NASL, RESC1, + "mov AR,A1\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG, TCHAR|TUCHAR, + NAREG|NASL, RESC1, + "movb AR,A1\n", }, + +/* + * Logical/branching operators + */ +{ OPLOG, FORCC, + SAREG|SOREG|SNAME|SCON, TWORD|TPOINT, + SZERO, TANY, + 0, RESCC, + "tst AL\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, + SZERO, TANY, + 0, RESCC, + "tstb AL\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME|SCON, TWORD|TPOINT, + SAREG|SOREG|SNAME|SCON, TWORD|TPOINT, + 0, RESCC, + "cmp AL,AR\n", }, + +{ OPLOG, FORCC, + SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, + SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, + 0, RESCC, + "cmpb AL,AR\n", }, + +{ OPLOG, FORCC, + SBREG|SOREG|SNAME|SCON, TLONG|TULONG, + SZERO, TANY, + 0, RNULL, + "ZD", }, + +{ OPLOG, FORCC, + SBREG|SOREG|SNAME, TLONG|TULONG, + SBREG|SOREG|SNAME, TLONG|TULONG, + 0, RNULL, + "ZF", }, + +/* AND/OR/ER/NOT */ +/* Optimize if high order bits are zero */ +{ AND, FOREFF|INBREG|FORCC, + SOREG|SNAME|SBREG, TLONG|TULONG, + SANDSCON, TLONG|TULONG, + 0, RLEFT|RESCC, + "clr AL\nbic UR,UL\n", }, + +{ AND, INBREG|FORCC, + SBREG, TLONG|TULONG, + SCON|SBREG|SOREG|SNAME, TLONG|TULONG, + 0, RLEFT|RESCC, + "bic AR,AL\nbic UR,UL\n", }, + +/* set status bits */ +{ AND, FORCC, + ARONS|SCON, TWORD|TPOINT, + ARONS|SCON, TWORD|TPOINT, + 0, RESCC, + "bit AR,AL\n", }, + +/* AND with int */ +{ AND, INAREG|FORCC|FOREFF, + SAREG|SNAME|SOREG, TWORD, + SCON|SAREG|SOREG|SNAME, TWORD, + 0, RLEFT|RESCC, + "bic AR,AL\n", }, + +/* AND with char */ +{ AND, INAREG|FORCC, + SAREG|SOREG|SNAME, TCHAR|TUCHAR, + ARONS|SCON, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + "bicb AR,AL\n", }, + +{ OR, INBREG|FORCC, + SBREG, TLONG|TULONG, + SCON|SBREG|SOREG|SNAME, TLONG|TULONG, + 0, RLEFT|RESCC, + "bis AR,AL\nbis UR,UL\n", }, + +/* OR with int */ +{ OR, FOREFF|INAREG|FORCC, + ARONS, TWORD, + ARONS|SCON, TWORD, + 0, RLEFT|RESCC, + "bis AR,AL\n", }, + +/* OR with char */ +{ OR, INAREG|FORCC, + SAREG|SOREG|SNAME, TCHAR|TUCHAR, + ARONS|SCON, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + "bisb AR,AL\n", }, + +/* XOR with int (extended insn) */ +{ ER, INAREG|FORCC, + ARONS, TWORD, + SAREG, TWORD, + 0, RLEFT|RESCC, + "xor AR,AL\n", }, + +/* XOR with char (extended insn) */ +{ ER, INAREG|FORCC, + SAREG, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + "xor AR,AL\n", }, + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + "jbr LL\n", }, + +/* + * Convert LTYPE to reg. + */ +/* Two bytes less if high half of constant is zero */ +{ OPLTYPE, INBREG, + SANY, TANY, + SSCON, TLONG|TULONG, + NBREG, RESC1, + "mov UL,U1\nsxt A1\n", }, + +/* XXX - avoid OREG index register to be overwritten */ +{ OPLTYPE, INBREG, + SANY, TANY, + SCON|SBREG|SNAME|SOREG, TLONG|TULONG, + NBREG, RESC1, + "mov AL,A1\nmov UL,U1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TWORD|TPOINT, + NAREG|NASR, RESC1, + "mov AL,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TCHAR, + NAREG, RESC1, + "movb AR,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG|SCON|SOREG|SNAME, TUCHAR, + NAREG, RESC1, + "clr A1\nbisb AL,A1\n", }, + +{ OPLTYPE, INCREG, + SANY, TANY, + SCREG|SCON|SOREG|SNAME, TDOUBLE, + NCREG, RESC1, + "movf AL,A1\n", }, + +{ OPLTYPE, INCREG, + SANY, TANY, + SCREG|SCON|SOREG|SNAME, TFLOAT, + NCREG, RESC1, + "movof AL,A1\n", }, + +/* + * Negate a word. + */ +{ UMINUS, INAREG|FOREFF, + SAREG, TWORD|TPOINT|TCHAR|TUCHAR, + SANY, TANY, + 0, RLEFT, + "neg AL\n", }, + +{ UMINUS, INBREG|FOREFF, + SBREG|SOREG|SNAME, TLONG, + SANY, TANY, + 0, RLEFT, + "neg AL\nneg UL\nsbc AL\n", }, + + +{ COMPL, INBREG, + SBREG, TLONG|TULONG, + SANY, TANY, + 0, RLEFT, + "com AL\ncom UL\n", }, + +{ COMPL, INAREG, + SAREG, TWORD, + SANY, TANY, + 0, RLEFT, + "com AL\n", }, + +/* + * Arguments to functions. + */ +{ FUNARG, FOREFF, + SCON|SBREG|SNAME|SOREG, TLONG|TULONG, + SANY, TLONG|TULONG, + 0, RNULL, + "mov UL,ZA(sp)\nmov AL,-(sp)\n", }, + +{ FUNARG, FOREFF, + SZERO, TANY, + SANY, TANY, + 0, RNULL, + "clr ZA(sp)\n", }, + +{ FUNARG, FOREFF, + SARGSUB, TWORD|TPOINT, + SANY, TWORD|TPOINT, + 0, RNULL, + "ZB", }, + +{ FUNARG, FOREFF, + SARGINC, TWORD|TPOINT, + SANY, TWORD|TPOINT, + 0, RNULL, + "ZH", }, + +{ FUNARG, FOREFF, + SCON|SAREG|SNAME|SOREG, TWORD|TPOINT, + SANY, TWORD|TPOINT, + 0, RNULL, + "mov AL,ZA(sp)\n", }, + +{ FUNARG, FOREFF, + SCON, TCHAR|TUCHAR, + SANY, TANY, + 0, RNULL, + "mov AL,ZA(sp)\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TCHAR, + SANY, TCHAR, + NAREG, RNULL, + "movb AL,A1\nmov A1,ZA(sp)\n", }, + +{ FUNARG, FOREFF, + SNAME|SOREG, TUCHAR, + SANY, TUCHAR, + NAREG, RNULL, + "clr ZA(sp)\nbisb AL,(sp)\n", }, + +{ FUNARG, FOREFF, + SAREG, TUCHAR|TCHAR, + SANY, TUCHAR|TCHAR, + 0, RNULL, + "mov AL,ZA(sp)\n", }, + +{ FUNARG, FOREFF, + SCREG, TFLOAT|TDOUBLE, + SANY, TANY, + 0, RNULL, + "movf AL,ZA(sp)\n", }, + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +/* { INIT, DF(INIT), }, */ + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/powerpc/README b/lang/pcc/pcc/arch/powerpc/README new file mode 100644 index 000000000..d3c867815 --- /dev/null +++ b/lang/pcc/pcc/arch/powerpc/README @@ -0,0 +1,48 @@ +macdefs.h ; machine-dependent definitions +code.c ; machine-dependent code for prologs, switches (pass 1) +local.c ; machine-dependent code for prologs, switches (pass 1) +local2.c ; misc routines and tables of register names (pass 2) +order.c ; machine-dependent code-generation strategy (pass 2) +table.c ; code templates (pass 2) + +On OS X, binaries are not ELF and all binaries are compiled PIC. To use pcc +on OS X while linking against the system libraries, use the -k option. + +Current issues: + +- no floating point (need mickey's patches to support >64 registers) +- mod/div on longlong not supported +- the stack frame is always 200 bytes - need to calculate size and patch + OREGs to temporaries and arguments [see discussion below] +- function arguments are always saved to the stack [need to change MI code] +- permanent registers >R13 are not saved [need to change MI code] +- structure arguments don't work +- return of structure doesn't work +- function pointers don't work for PIC +- constant structure assignment doesn't work properly for PIC +- no built-in vararg support [shouldn't be too hard to add] + +The way most modern CPUs create the stack is to allocate the frame +to contain room for the temporaries, to save the permanent registers +and to store the arguments to functions invoked from within the function. +To achieve this, all the information must be known when the prologue +is generated. Currently we only know the size of the temporaries - +we don't know the size of the argument space for each function that +gets invoked from this function. Even if we did know this information, +we create ops to save the register arguments (R3-R10), early in pass1 +and don't know the position of the stack pointer, and the size of the +argument space required to "step over". + +One solution is to have two pointers to the stack. One for the top +of the stack and the other pointing just below the temporaries but above +the argument space. Then our function arguments and the permanent registers can +be saved fixed-relative to this register. If we don't know the size of +argument space, we cannot "dynamically" alter the stack (like we do with mips), +since the powerpc ABI specifies that the "lowest" address +in the stack frame is the saved stack pointer (pointing to the previous +stack frame). While this is a nice feature for tracking back through the +stack frames (which mips has always had problems with), it makes it +next-to-impossible to increase the strack frame dynamically. + +I guess the best approach is to determine the size of the argument stack +and have a second frame pointer. diff --git a/lang/pcc/pcc/arch/powerpc/code.c b/lang/pcc/pcc/arch/powerpc/code.c new file mode 100644 index 000000000..e306ff1a8 --- /dev/null +++ b/lang/pcc/pcc/arch/powerpc/code.c @@ -0,0 +1,1543 @@ +/* $Id: code.c,v 1.31 2014/05/29 19:20:03 plunky Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 +#include + +#include "pass1.h" +#include "pass2.h" + +static void genswitch_bintree(int num, TWORD ty, struct swents **p, int n); + +#if 0 +static void genswitch_table(int num, struct swents **p, int n); +static void genswitch_mrst(int num, struct swents **p, int n); +#endif + +static int rvnr; + +/* + * Print out assembler segment name. + */ +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + case DATA: + case LDATA: name = ".data"; break; + case UDATA: break; +#ifdef MACHOABI + case PICLDATA: + case PICDATA: name = ".section .data.rel.rw,\"aw\""; break; + case PICRDATA: name = ".section .data.rel.ro,\"aw\""; break; + case STRNG: name = ".cstring"; break; + case RDATA: name = ".const_data"; break; +#else + case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break; + case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; + case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; + case STRNG: +#ifdef AOUTABI + case RDATA: name = ".data"; break; +#else + case RDATA: name = ".section .rodata"; break; +#endif +#endif + case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; + case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; + case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; + case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; + case NMSEG: + printf("\t.section %s,\"a%c\",@progbits\n", name, + cftnsp ? 'x' : 'w'); + return; + } + printf("\t%s\n", name); +} + +void +defalign(int al) +{ + if (ispow2(al/ALCHAR)) + printf("\t.p2align %d\n", ispow2(al/ALCHAR)); +} + + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + char *name; + + name = sp->soname ? sp->soname : exname(sp->sname); + if (sp->sclass == EXTDEF) + printf(" .globl %s\n", name); + if (sp->slevel == 0) + printf("%s:\n", name); + else + printf(LABFMT ":\n", sp->soffset); +} + +/* Put a symbol in a temporary + * used by bfcode() and its helpers + */ +static void +putintemp(struct symtab *sym) +{ + NODE *p; + + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + p = buildtree(ASSIGN, p, nametree(sym)); + sym->soffset = regno(p->n_left); + sym->sflags |= STNODE; + ecomp(p); +} + +/* setup a 64-bit parameter (double/ldouble/longlong) + * used by bfcode() */ +static void +param_64bit(struct symtab *sym, int *argofsp, int dotemps) +{ + int argofs = *argofsp; + NODE *p, *q; + int navail; + +#if ALLONGLONG == 64 + /* alignment */ + ++argofs; + argofs &= ~1; +#endif + + navail = NARGREGS - argofs; + + if (navail < 2) { + /* half in and half out of the registers */ + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = R3 + argofs; + p = block(REG, NIL, NIL, INT, 0, 0); + regno(p) = FPREG; + p = block(PLUS, p, bcon(sym->soffset/SZCHAR), PTR+INT, 0, 0); + p = block(UMUL, p, NIL, INT, 0, 0); + } else { + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); + regno(q) = R3R4 + argofs; + if (dotemps) { + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + sym->soffset = regno(p); + sym->sflags |= STNODE; + } else { + p = nametree(sym); + } + } + p = buildtree(ASSIGN, p, q); + ecomp(p); + *argofsp = argofs + 2; +} + +/* setup a 32-bit param on the stack + * used by bfcode() */ +static void +param_32bit(struct symtab *sym, int *argofsp, int dotemps) +{ + NODE *p, *q; + + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); + regno(q) = R3 + (*argofsp)++; + if (dotemps) { + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + sym->soffset = regno(p); + sym->sflags |= STNODE; + } else { + p = nametree(sym); + } + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + +/* setup a double param on the stack + * used by bfcode() */ +static void +param_double(struct symtab *sym, int *argofsp, int dotemps) +{ + NODE *p, *q, *t; + int tmpnr; + + /* + * we have to dump the double from the general register + * into a temp, since the register allocator doesn't like + * floats to be in CLASSA. This may not work for -xtemps. + */ + + if (xtemps) { + q = block(REG, NIL, NIL, ULONGLONG, 0, 0); + regno(q) = R3R4 + *argofsp; + p = block(REG, NIL, NIL, PTR+ULONGLONG, 0, 0); + regno(p) = SPREG; + p = block(PLUS, p, bcon(-8), INT, 0, 0); + p = block(UMUL, p, NIL, ULONGLONG, 0, 0); + p = buildtree(ASSIGN, p, q); + ecomp(p); + + t = tempnode(0, sym->stype, sym->sdf, sym->sap); + tmpnr = regno(t); + p = block(REG, NIL, NIL, + INCREF(sym->stype), sym->sdf, sym->sap); + regno(p) = SPREG; + p = block(PLUS, p, bcon(-8), INT, 0, 0); + p = block(UMUL, p, NIL, sym->stype, sym->sdf, sym->sap); + p = buildtree(ASSIGN, t, p); + ecomp(p); + } else { + /* bounce straight into temp */ + p = block(REG, NIL, NIL, ULONGLONG, 0, 0); + regno(p) = R3R4 + *argofsp; + t = tempnode(0, ULONGLONG, 0, 0); + tmpnr = regno(t); + p = buildtree(ASSIGN, t, p); + ecomp(p); + } + + (*argofsp) += 2; + + sym->soffset = tmpnr; + sym->sflags |= STNODE; +} + +/* setup a float param on the stack + * used by bfcode() */ +static void +param_float(struct symtab *sym, int *argofsp, int dotemps) +{ + NODE *p, *q, *t; + int tmpnr; + + /* + * we have to dump the float from the general register + * into a temp, since the register allocator doesn't like + * floats to be in CLASSA. This may not work for -xtemps. + */ + + if (xtemps) { + /* bounce onto TOS */ + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = R3 + (*argofsp); + p = block(REG, NIL, NIL, INT, 0, 0); + regno(p) = SPREG; + p = block(PLUS, p, bcon(-4), INT, 0, 0); + p = block(UMUL, p, NIL, INT, 0, 0); + p = buildtree(ASSIGN, p, q); + ecomp(p); + + t = tempnode(0, sym->stype, sym->sdf, sym->sap); + tmpnr = regno(t); + p = block(REG, NIL, NIL, INCREF(sym->stype), + sym->sdf, sym->sap); + regno(p) = SPREG; + p = block(PLUS, p, bcon(-4), INT, 0, 0); + p = block(UMUL, p, NIL, sym->stype, sym->sdf, sym->sap); + p = buildtree(ASSIGN, t, p); + ecomp(p); + } else { + /* bounce straight into temp */ + p = block(REG, NIL, NIL, INT, 0, 0); + regno(p) = R3 + (*argofsp); + t = tempnode(0, INT, 0, 0); + tmpnr = regno(t); + p = buildtree(ASSIGN, t, p); + ecomp(p); + } + + (*argofsp)++; + + sym->soffset = tmpnr; + sym->sflags |= STNODE; +} + +/* setup the hidden pointer to struct return parameter + * used by bfcode() */ +static void +param_retstruct(void) +{ + NODE *p, *q; + + p = tempnode(0, INCREF(cftnsp->stype), 0, cftnsp->sap); + rvnr = regno(p); + q = block(REG, NIL, NIL, INCREF(cftnsp->stype), + cftnsp->sdf, cftnsp->sap); + regno(q) = R3; + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + + +/* setup struct parameter + * push the registers out to memory + * used by bfcode() */ +static void +param_struct(struct symtab *sym, int *argofsp) +{ + int argofs = *argofsp; + NODE *p, *q; + int navail; + int sz; + int off; + int num; + int i; + + navail = NARGREGS - argofs; + sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT; + off = ARGINIT/SZINT + argofs; + num = sz > navail ? navail : sz; + for (i = 0; i < num; i++) { + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = R3 + argofs++; + p = block(REG, NIL, NIL, INT, 0, 0); + regno(p) = SPREG; + p = block(PLUS, p, bcon(4*off++), INT, 0, 0); + p = block(UMUL, p, NIL, INT, 0, 0); + p = buildtree(ASSIGN, p, q); + ecomp(p); + } + + *argofsp = argofs; +} + +/* + * code for the beginning of a function + * sp is an array of indices in symtab for the arguments + * cnt is the number of arguments + */ +void +bfcode(struct symtab **sp, int cnt) +{ +#ifdef USE_GOTNR + extern int gotnr; +#endif + + struct symtab *sp2; + union arglist *usym; + int saveallargs = 0; + int i, argofs = 0; + + /* + * Detect if this function has ellipses and save all + * argument registers onto stack. + */ + usym = cftnsp->sdf->dfun; + while (usym && usym->type != TNULL) { + if (usym->type == TELLIPSIS) { + saveallargs = 1; + break; + } + ++usym; + } + + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + param_retstruct(); + ++argofs; + } + +#ifdef USE_GOTNR + if (kflag) { + /* put GOT register into temporary */ + NODE *q, *p; + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = GOTREG; + p = tempnode(0, INT, 0, 0); + gotnr = regno(p); + ecomp(buildtree(ASSIGN, p, q)); + } +#endif + + /* recalculate the arg offset and create TEMP moves */ + for (i = 0; i < cnt; i++) { + + if (sp[i] == NULL) + continue; + + if ((argofs >= NARGREGS) && !xtemps) + break; + + if (argofs >= NARGREGS) { + putintemp(sp[i]); + } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) { + param_struct(sp[i], &argofs); + } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) { + param_64bit(sp[i], &argofs, xtemps && !saveallargs); + } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) { + if (features(FEATURE_HARDFLOAT)) + param_double(sp[i], &argofs, + xtemps && !saveallargs); + else + param_64bit(sp[i], &argofs, + xtemps && !saveallargs); + } else if (sp[i]->stype == FLOAT) { + if (features(FEATURE_HARDFLOAT)) + param_float(sp[i], &argofs, + xtemps && !saveallargs); + else + param_32bit(sp[i], &argofs, + xtemps && !saveallargs); + } else { + param_32bit(sp[i], &argofs, xtemps && !saveallargs); + } + } + + /* if saveallargs, save the rest of the args onto the stack */ + while (saveallargs && argofs < NARGREGS) { + NODE *p, *q; + /* int off = (ARGINIT+FIXEDSTACKSIZE*SZCHAR)/SZINT + argofs; */ + int off = ARGINIT/SZINT + argofs; + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = R3 + argofs++; + p = block(REG, NIL, NIL, INT, 0, 0); + regno(p) = FPREG; + p = block(PLUS, p, bcon(4*off), INT, 0, 0); + p = block(UMUL, p, NIL, INT, 0, 0); + p = buildtree(ASSIGN, p, q); + ecomp(p); + } + + /* profiling */ + if (pflag) { + NODE *p; + +#if defined(ELFABI) + + sp2 = lookup("_mcount", 0); + sp2->stype = EXTERN; + p = nametree(sp2); + p->n_sp->sclass = EXTERN; + p = clocal(p); + p = buildtree(ADDROF, p, NIL); + p = block(UCALL, p, NIL, INT, 0, 0); + ecomp(funcode(p)); + + +#elif defined(MACHOABI) + + NODE *q; + int tmpnr; + + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = R0; + p = tempnode(0, INT, 0, 0); + tmpnr = regno(p); + p = buildtree(ASSIGN, p, q); + ecomp(p); + + q = tempnode(tmpnr, INT, 0, 0); + + sp2 = lookup("mcount", 0); + sp2->stype = EXTERN; + p = nametree(sp2); + p->n_sp->sclass = EXTERN; + p = clocal(p); + p = buildtree(ADDROF, p, NIL); + p = block(CALL, p, q, INT, 0, 0); + ecomp(funcode(p)); + +#endif + } +} + +/* + * code for the end of a function + * deals with struct return here + */ +void +efcode(void) +{ + NODE *p, *q; + int tempnr; + int ty; + +#ifdef USE_GOTNR + extern int gotnr; + gotnr = 0; +#endif + + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + + ty = cftnsp->stype - FTN; + + q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); + regno(q) = R3; + p = tempnode(0, INCREF(ty), 0, cftnsp->sap); + tempnr = regno(p); + p = buildtree(ASSIGN, p, q); + ecomp(p); + + q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap); + q = buildtree(UMUL, q, NIL); + + p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); + p = buildtree(UMUL, p, NIL); + + p = buildtree(ASSIGN, p, q); + ecomp(p); + + q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); + p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); + regno(p) = R3; + p = buildtree(ASSIGN, p, q); + ecomp(p); +} + +struct stub stublist; +struct stub nlplist; + +/* called just before final exit */ +/* flag is 1 if errors, 0 if none */ +void +ejobcode(int flag) +{ + +#if defined(MACHOABI) + /* + * iterate over the stublist and output the PIC stubs +` */ + if (kflag) { + struct stub *p; + + DLIST_FOREACH(p, &stublist, link) { + printf("\t.section __TEXT, __picsymbolstub1,symbol_stubs,pure_instructions,32\n"); + printf("\t.align 5\n"); + printf("L%s$stub:\n", p->name); + if (strcmp(p->name, "mcount") == 0) + printf("\t.indirect_symbol %s\n", p->name); + else + printf("\t.indirect_symbol %s\n", p->name); + printf("\tmflr r0\n"); + printf("\tbcl 20,31,L%s$spb\n", p->name); + printf("L%s$spb:\n", p->name); + printf("\tmflr r11\n"); + printf("\taddis r11,r11,ha16(L%s$lazy_ptr-L%s$spb)\n", + p->name, p->name); + printf("\tmtlr r0\n"); + printf("\tlwzu r12,lo16(L%s$lazy_ptr-L%s$spb)(r11)\n", + p->name, p->name); + printf("\tmtctr r12\n"); + printf("\tbctr\n"); + printf("\t.lazy_symbol_pointer\n"); + printf("L%s$lazy_ptr:\n", p->name); + if (strcmp(p->name, "mcount") == 0) + printf("\t.indirect_symbol %s\n", p->name); + else + printf("\t.indirect_symbol %s\n", p->name); + printf("\t.long dyld_stub_binding_helper\n"); + printf("\t.subsections_via_symbols\n"); + } + + printf("\t.non_lazy_symbol_pointer\n"); + DLIST_FOREACH(p, &nlplist, link) { + printf("L%s$non_lazy_ptr:\n", p->name); + if (strcmp(p->name, "mcount") == 0) + printf("\t.indirect_symbol %s\n", p->name); + else + printf("\t.indirect_symbol %s\n", p->name); + printf("\t.long 0\n"); + } + + } +#endif + +#ifndef os_darwin + printf("\t.ident \"PCC: %s\"\n", VERSSTR); +#endif + +} + +void +bjobcode(void) +{ + DLIST_INIT(&stublist, link); + DLIST_INIT(&nlplist, link); +} + +#ifdef notdef +/* + * Print character t at position i in one string, until t == -1. + * Locctr & label is already defined. + */ +void +bycode(int t, int i) +{ + static int lastoctal = 0; + + /* put byte i+1 in a string */ + + if (t < 0) { + if (i != 0) + puts("\""); + } else { + if (i == 0) + printf("\t.ascii \""); + if (t == '\\' || t == '"') { + lastoctal = 0; + putchar('\\'); + putchar(t); + } else if (t < 040 || t >= 0177) { + lastoctal++; + printf("\\%o",t); + } else if (lastoctal && '0' <= t && t <= '9') { + lastoctal = 0; + printf("\"\n\t.ascii \"%c", t); + } else { + lastoctal = 0; + putchar(t); + } + } +} +#endif + +/* fix up type of field p */ +void +fldty(struct symtab *p) +{ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + if (num < 0) { + genswitch_bintree(num, type, p, n); + return 1; + } + + return 0; + +#if 0 + if (0) + genswitch_table(num, p, n); + if (0) + genswitch_bintree(num, p, n); + genswitch_mrst(num, p, n); +#endif +} + +static void bintree_rec(TWORD ty, int num, + struct swents **p, int n, int s, int e); + +static void +genswitch_bintree(int num, TWORD ty, struct swents **p, int n) +{ + int lab = getlab(); + + if (p[0]->slab == 0) + p[0]->slab = lab; + + bintree_rec(ty, num, p, n, 1, n); + + plabel(lab); +} + +static void +bintree_rec(TWORD ty, int num, struct swents **p, int n, int s, int e) +{ + NODE *r; + int rlabel; + int h; + + if (s == e) { + r = tempnode(num, ty, 0, 0); + r = buildtree(NE, r, bcon(p[s]->sval)); + cbranch(buildtree(NOT, r, NIL), bcon(p[s]->slab)); + branch(p[0]->slab); + return; + } + + rlabel = getlab(); + + h = s + (e - s) / 2; + + r = tempnode(num, ty, 0, 0); + r = buildtree(GT, r, bcon(p[h]->sval)); + cbranch(r, bcon(rlabel)); + bintree_rec(ty, num, p, n, s, h); + plabel(rlabel); + bintree_rec(ty, num, p, n, h+1, e); +} + + +#if 0 + +static void +genswitch_table(int num, struct swents **p, int n) +{ + NODE *r, *t; + int tval; + int minval, maxval, range; + int deflabel, tbllabel; + int i, j; + + minval = p[1]->sval; + maxval = p[n]->sval; + + range = maxval - minval + 1; + + if (n < 10 || range > 3 * n) { + /* too small or too sparse for jump table */ + genswitch_simple(num, p, n); + return; + } + + r = tempnode(num, UNSIGNED, 0, 0); + r = buildtree(MINUS, r, bcon(minval)); + t = tempnode(0, UNSIGNED, 0, 0); + tval = regno(t); + r = buildtree(ASSIGN, t, r); + ecomp(r); + + deflabel = p[0]->slab; + if (deflabel == 0) + deflabel = getlab(); + + t = tempnode(tval, UNSIGNED, 0, 0); + cbranch(buildtree(GT, t, bcon(maxval-minval)), bcon(deflabel)); + + tbllabel = getlab(); + struct symtab *strtbl = lookup("__switch_table", SLBLNAME|STEMP); + strtbl->soffset = tbllabel; + strtbl->sclass = ILABEL; + strtbl->stype = INCREF(UCHAR); + + t = block(NAME, NIL, NIL, UNSIGNED, 0, 0); + t->n_sp = strtbl; + t = buildtree(ADDROF, t, NIL); + r = tempnode(tval, UNSIGNED, 0, 0); + r = buildtree(PLUS, t, r); + t = tempnode(0, INCREF(UNSIGNED), 0, 0); + r = buildtree(ASSIGN, t, r); + ecomp(r); + + r = tempnode(regno(t), INCREF(UNSIGNED), 0, 0); + r = buildtree(UMUL, r, NIL); + t = block(NAME, NIL, NIL, UCHAR, 0, 0); + t->n_sp = strtbl; + t = buildtree(ADDROF, t, NIL); + r = buildtree(PLUS, t, r); + r = block(GOTO, r, NIL, 0, 0, 0); + ecomp(r); + + plabel(tbllabel); + for (i = minval, j=1; i <= maxval; i++) { + char *entry = tmpalloc(20); + int lab = deflabel; + //printf("; minval=%d, maxval=%d, i=%d, j=%d p[j]=%lld\n", minval, maxval, i, j, p[j]->sval); + if (p[j]->sval == i) { + lab = p[j]->slab; + j++; + } + snprintf(entry, 20, "\t.long " LABFMT "-" LABFMT "\n", lab, tbllabel); + send_passt(IP_ASM, entry); + } + + if (p[0]->slab <= 0) + plabel(deflabel); +} + +#define DPRINTF(x) if (xdebug) printf x +//#define DPRINTF(x) do { } while(0) + +#define MIN_TABLE_SIZE 8 + +/* + * Multi-way Radix Search Tree (MRST) + */ + +static void mrst_rec(int num, struct swents **p, int n, int *state, int lab); +static unsigned long mrst_find_window(struct swents **p, int n, int *state, int lab, int *len, int *lowbit); +void mrst_put_entry_and_recurse(int num, struct swents **p, int n, int *state, int tbllabel, int lab, unsigned long j, unsigned long tblsize, unsigned long Wmax, int lowbit); + +static void +genswitch_mrst(int num, struct swents **p, int n) +{ + int *state; + int i; + int putlabel = 0; + + if (n < 10) { + /* too small for MRST */ + genswitch_simple(num, p, n); + return; + } + + state = tmpalloc((n+1)*sizeof(int)); + for (i = 0; i <= n; i++) + state[i] = 0; + + if (p[0]->slab == 0) { + p[0]->slab = getlab(); + putlabel = 1; + } + + mrst_rec(num, p, n, state, 0); + + if (putlabel) + plabel(p[0]->slab); +} + + +/* + * Look through the cases and generate a table or + * list of simple comparisons. If generating a table, + * invoke mrst_put_entry_and_recurse() to put + * an entry in the table and recurse. + */ +static void +mrst_rec(int num, struct swents **p, int n, int *state, int lab) +{ + int len, lowbit; + unsigned long Wmax; + unsigned int tblsize; + NODE *t; + NODE *r; + int tval; + int i; + + DPRINTF(("mrst_rec: num=%d, n=%d, lab=%d\n", num, n, lab)); + + /* find best window to cover set*/ + Wmax = mrst_find_window(p, n, state, lab, &len, &lowbit); + tblsize = (1 << len); + assert(len > 0 && tblsize > 0); + + DPRINTF(("mrst_rec: Wmax=%lu, lowbit=%d, tblsize=%u\n", + Wmax, lowbit, tblsize)); + + if (lab) + plabel(lab); + + if (tblsize <= MIN_TABLE_SIZE) { + DPRINTF(("msrt_rec: break the recursion\n")); + for (i = 1; i <= n; i++) { + if (state[i] == lab) { + t = tempnode(num, UNSIGNED, 0, 0); + cbranch(buildtree(EQ, t, bcon(p[i]->sval)), + bcon(p[i]->slab)); + } + } + branch(p[0]->slab); + return; + } + + DPRINTF(("generating table with %d elements\n", tblsize)); + + // AND with Wmax + t = tempnode(num, UNSIGNED, 0, 0); + r = buildtree(AND, t, bcon(Wmax)); + + // RS lowbits + r = buildtree(RS, r, bcon(lowbit)); + + t = tempnode(0, UNSIGNED, 0, 0); + tval = regno(t); + r = buildtree(ASSIGN, t, r); + ecomp(r); + + int tbllabel = getlab(); + struct symtab *strtbl = lookup("__switch_table", SLBLNAME|STEMP); + strtbl->sclass = STATIC; + strtbl->sap = 0; + strtbl->slevel = 1; + strtbl->soffset = tbllabel; + strtbl->stype = INCREF(UCHAR); + strtbl->squal = (CON >> TSHIFT); + + t = block(NAME, NIL, NIL, UNSIGNED, 0, 0); + t->n_sp = strtbl; + t = buildtree(ADDROF, t, NIL); + r = tempnode(tval, UNSIGNED, 0, 0); + r = buildtree(PLUS, t, r); + t = tempnode(0, INCREF(UNSIGNED), 0, 0); + r = buildtree(ASSIGN, t, r); + ecomp(r); + + r = tempnode(regno(t), INCREF(UNSIGNED), 0, 0); + r = buildtree(UMUL, r, NIL); + t = block(NAME, NIL, NIL, UCHAR, 0, 0); + t->n_sp = strtbl; + t = buildtree(ADDROF, t, NIL); + r = buildtree(PLUS, t, r); + r = block(GOTO, r, NIL, 0, 0, 0); + ecomp(r); + + plabel(tbllabel); + + mrst_put_entry_and_recurse(num, p, n, state, tbllabel, lab, + 0, tblsize, Wmax, lowbit); +} + + +/* + * Put an entry into the table and recurse to the next entry + * in the table. On the way back through the recursion, invoke + * mrst_rec() to check to see if we should generate another + * table. + */ +void +mrst_put_entry_and_recurse(int num, struct swents **p, int n, int *state, + int tbllabel, int labval, + unsigned long j, unsigned long tblsize, unsigned long Wmax, int lowbit) +{ + int i; + int found = 0; + int lab = getlab(); + + /* + * Look for labels which map to this table entry. + * Mark each one in "state" that they fall inside this table. + */ + for (i = 1; i <= n; i++) { + unsigned int val = (p[i]->sval & Wmax) >> lowbit; + if (val == j && state[i] == labval) { + found = 1; + state[i] = lab; + } + } + + /* couldn't find any labels? goto the default label */ + if (!found) + lab = p[0]->slab; + + /* generate the table entry */ + char *entry = tmpalloc(20); + snprintf(entry, 20, "\t.long " LABFMT "-" LABFMT "\n", lab, tbllabel); + send_passt(IP_ASM, entry); + + DPRINTF(("mrst_put_entry: table=%d, pos=%lu/%lu, label=%d\n", + tbllabel, j, tblsize, lab)); + + /* go to the next table entry */ + if (j+1 < tblsize) { + mrst_put_entry_and_recurse(num, p, n, state, tbllabel, labval, + j+1, tblsize, Wmax, lowbit); + } + + /* if we are going to the default label, bail now */ + if (!found) + return; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("state: "); + for (i = 1; i <= n; i++) + printf("%d ", state[i]); + printf("\n"); + } +#endif + + /* build another table */ + mrst_rec(num, p, n, state, lab); +} + +/* + * counts the number of entries in a table of size (1 << L) which would + * be used given the cases and the mask (W, lowbit). + */ +static unsigned int +mrst_cardinality(struct swents **p, int n, int *state, int step, unsigned long W, int L, int lowbit) +{ + unsigned int count = 0; + int i; + + if (W == 0) + return 0; + + int *vals = (int *)calloc(1 << L, sizeof(int)); + assert(vals); + + DPRINTF(("mrst_cardinality: ")); + for (i = 1; i <= n; i++) { + int idx; + if (state[i] != step) + continue; + idx = (p[i]->sval & W) >> lowbit; + DPRINTF(("%llu->%d, ", p[i]->sval, idx)); + if (!vals[idx]) { + count++; + } + vals[idx] = 1; + } + DPRINTF((": found %d entries\n", count)); + free(vals); + + return count; +} + +/* + * Find the maximum window (table size) which would best cover + * the set of labels. Algorithm explained in: + * + * Ulfar Erlingsson, Mukkai Krishnamoorthy and T.V. Raman. + * Efficient Multiway Radix Search Trees. + * Information Processing Letters 60:3 115-120 (November 1996) + */ + +static unsigned long +mrst_find_window(struct swents **p, int n, int *state, int lab, int *len, int *lowbit) +{ + unsigned int tblsize; + unsigned long W = 0; + unsigned long Wmax = 0; + unsigned long Wleft = (1 << (SZLONG-1)); + unsigned int C = 0; + unsigned int Cmax = 0; + int L = 0; + int Lmax = 0; + int lowmax = 0; + int no_b = SZLONG-1; + unsigned long b = (1 << (SZLONG-1)); + + DPRINTF(("mrst_find_window: n=%d, lab=%d\n", n, lab)); + + for (; b > 0; b >>= 1, no_b--) { + + // select the next bit + W |= b; + L += 1; + + tblsize = 1 << L; + assert(tblsize > 0); + + DPRINTF(("no_b=%d, b=0x%lx, Wleft=0x%lx, W=0x%lx, Wmax=0x%lx, L=%d, Lmax=%d, Cmax=%u, lowmax=%d, tblsize=%u\n", no_b, b, Wleft, W, Wmax, L, Lmax, Cmax, lowmax, tblsize)); + + C = mrst_cardinality(p, n, state, lab, W, L, no_b); + DPRINTF((" -> cardinality is %d\n", C)); + + if (2*C >= tblsize) { + DPRINTF(("(found good match, keep adding to table)\n")); + Wmax = W; + Lmax = L; + lowmax = no_b; + Cmax = C; + } else { + DPRINTF(("(too sparse)\n")); + assert((W & Wleft) != 0); + + /* flip the MSB and see if we get a better match */ + W ^= Wleft; + Wleft >>= 1; + L -= 1; + + DPRINTF((" --> trying W=0x%lx and L=%d and Cmax=%u\n", W, L, Cmax)); + C = mrst_cardinality(p, n, state, lab, W, L, no_b); + DPRINTF((" --> C=%u\n", C)); + if (C > Cmax) { + Wmax = W; + Lmax = L; + lowmax = no_b; + Cmax = C; + DPRINTF((" --> better!\n")); + } else { + DPRINTF((" --> no better\n")); + } + } + + } + +#ifdef PCC_DEBUG + if (xdebug) { + int i; + int hibit = lowmax + Lmax; + printf("msrt_find_window: Wmax=0x%lx, lowbit=%d, result=", Wmax, lowmax); + for (i = 31; i >= 0; i--) { + int mask = (1 << i); + if (i == hibit) + printf("["); + if (Wmax & mask) + printf("1"); + else + printf("0"); + if (i == lowmax) + printf("]"); + } + printf("\n"); + } +#endif + + assert(Lmax > 0); + *len = Lmax; + *lowbit = lowmax; + + DPRINTF(("msrt_find_window: returning Wmax=%lu, len=%d, lowbit=%d [tblsize=%u, entries=%u]\n", Wmax, Lmax, lowmax, tblsize, C)); + + return Wmax; +} +#endif + +/* + * Straighten a chain of CM ops so that the CM nodes + * only appear on the left node. + * + * CM CM + * CM CM CM b + * x y a b CM a + * x y + * + * CM CM + * CM CM CM c + * CM z CM c CM b + * x y a b CM a + * CM z + * x y + */ +static NODE * +straighten(NODE *p) +{ + NODE *r = p->n_right; + + if (p->n_op != CM || r->n_op != CM) + return p; + + p->n_right = r->n_left; + r->n_left = straighten(p); + + return r; +} + +static NODE * +reverse1(NODE *p, NODE *a) +{ + NODE *l = p->n_left; + NODE *r = p->n_right; + + a->n_right = r; + p->n_left = a; + + if (l->n_op == CM) { + return reverse1(l, p); + } else { + p->n_right = l; + return p; + } +} + +/* + * Reverse a chain of CM ops + */ +static NODE * +reverse(NODE *p) +{ + NODE *l = p->n_left; + NODE *r = p->n_right; + + p->n_left = r; + + if (l->n_op == CM) + return reverse1(l, p); + + p->n_right = l; + + return p; +} + +/* push arg onto the stack */ +/* called by moveargs() */ +static NODE * +pusharg(NODE *p, int *regp) +{ + NODE *q; + int sz; + int off; + + /* convert to register size, if smaller */ + sz = tsize(p->n_type, p->n_df, p->n_ap); + if (sz < SZINT) + p = block(SCONV, p, NIL, INT, 0, 0); + + q = block(REG, NIL, NIL, INCREF(p->n_type), p->n_df, p->n_ap); + regno(q) = SPREG; + + off = ARGINIT/SZCHAR + 4 * (*regp - R3); + q = block(PLUS, q, bcon(off), INT, 0, 0); + q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_ap); + (*regp) += szty(p->n_type); + + return buildtree(ASSIGN, q, p); +} + +/* setup call stack with 32-bit argument */ +/* called from moveargs() */ +static NODE * +movearg_32bit(NODE *p, int *regp) +{ + int reg = *regp; + NODE *q; + + q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); + regno(q) = reg++; + q = buildtree(ASSIGN, q, p); + + *regp = reg; + return q; +} + +/* setup call stack with 64-bit argument */ +/* called from moveargs() */ +static NODE * +movearg_64bit(NODE *p, int *regp) +{ + int reg = *regp; + NODE *q, *r; + +#if ALLONGLONG == 64 + /* alignment */ + ++reg; + reg &= ~1; +#endif + + if (reg > R10) { + *regp = reg; + q = pusharg(p, regp); + } else if (reg == R10) { + /* half in and half out of the registers */ + r = tcopy(p); + if (!features(FEATURE_BIGENDIAN)) { + q = block(SCONV, p, NIL, INT, 0, 0); + q = movearg_32bit(q, regp); /* little-endian */ + r = buildtree(RS, r, bcon(32)); + r = block(SCONV, r, NIL, INT, 0, 0); + r = pusharg(r, regp); /* little-endian */ + } else { + q = buildtree(RS, p, bcon(32)); + q = block(SCONV, q, NIL, INT, 0, 0); + q = movearg_32bit(q, regp); /* big-endian */ + r = block(SCONV, r, NIL, INT, 0, 0); + r = pusharg(r, regp); /* big-endian */ + } + q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_ap)); + } else { + q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); + regno(q) = R3R4 + (reg - R3); + q = buildtree(ASSIGN, q, p); + *regp = reg + 2; + } + + return q; +} + +/* setup call stack with float argument */ +/* called from moveargs() */ +static NODE * +movearg_float(NODE *p, int *fregp, int *regp) +{ +#if defined(MACHOABI) + NODE *q, *r; + TWORD ty = INCREF(p->n_type); + int tmpnr; +#endif + + p = movearg_32bit(p, fregp); + + /* + * On OS/X, floats are passed in the floating-point registers + * and in the general registers for compatibily with libraries + * compiled to handle soft-float. + */ + +#if defined(MACHOABI) + + if (xtemps) { + /* bounce into TOS */ + r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap); + regno(r) = SPREG; + r = block(PLUS, r, bcon(-4), INT, 0, 0); + r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap); + r = buildtree(ASSIGN, r, p); + ecomp(r); + + /* bounce into temp */ + r = block(REG, NIL, NIL, PTR+INT, 0, 0); + regno(r) = SPREG; + r = block(PLUS, r, bcon(-4), INT, 0, 0); + r = block(UMUL, r, NIL, INT, 0, 0); + q = tempnode(0, INT, 0, 0); + tmpnr = regno(q); + r = buildtree(ASSIGN, q, r); + ecomp(r); + } else { + /* copy directly into temp */ + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(q); + r = buildtree(ASSIGN, q, p); + ecomp(r); + } + + /* copy from temp to register parameter */ + r = tempnode(tmpnr, INT, 0, 0); + q = block(REG, NIL, NIL, INT, 0, 0); + regno(q) = (*regp)++; + p = buildtree(ASSIGN, q, r); + +#endif + return p; + +} + +/* setup call stack with float/double argument */ +/* called from moveargs() */ +static NODE * +movearg_double(NODE *p, int *fregp, int *regp) +{ +#if defined(MACHOABI) + NODE *q, *r; + TWORD ty = INCREF(p->n_type); + int tmpnr; +#endif + + /* this does the move to a single register for us */ + p = movearg_32bit(p, fregp); + + /* + * On OS/X, doubles are passed in the floating-point registers + * and in the general registers for compatibily with libraries + * compiled to handle soft-float. + */ + +#if defined(MACHOABI) + + if (xtemps) { + /* bounce on TOS */ + r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap); + regno(r) = SPREG; + r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_ap); + r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap); + r = buildtree(ASSIGN, r, p); + ecomp(r); + + /* bounce into temp */ + r = block(REG, NIL, NIL, PTR+LONGLONG, 0, 0); + regno(r) = SPREG; + r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, 0); + r = block(UMUL, r, NIL, LONGLONG, 0, 0); + q = tempnode(0, LONGLONG, 0, 0); + tmpnr = regno(q); + r = buildtree(ASSIGN, q, r); + ecomp(r); + } else { + /* copy directly into temp */ + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(q); + r = buildtree(ASSIGN, q, p); + ecomp(r); + } + + /* copy from temp to register parameter */ + r = tempnode(tmpnr, LONGLONG, 0, 0); + q = block(REG, NIL, NIL, LONGLONG, 0, 0); + regno(q) = R3R4 - R3 + (*regp); + p = buildtree(ASSIGN, q, r); + + (*regp) += 2; + +#endif + + return p; +} + +/* setup call stack with a structure */ +/* called from moveargs() */ +static NODE * +movearg_struct(NODE *p, int *regp) +{ + int reg = *regp; + NODE *l, *q, *t, *r; + int tmpnr; + int navail; + int num; + int sz; + int ty; + int i; + + assert(p->n_op == STARG); + + navail = NARGREGS - (reg - R3); + navail = navail < 0 ? 0 : navail; + sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT; + num = sz > navail ? navail : sz; + + /* remove STARG node */ + l = p->n_left; + nfree(p); + ty = l->n_type; + + /* + * put it into a TEMP, rather than tcopy(), since the tree + * in p may have side-affects + */ + t = tempnode(0, ty, l->n_df, l->n_ap); + tmpnr = regno(t); + q = buildtree(ASSIGN, t, l); + + /* copy structure into registers */ + for (i = 0; i < num; i++) { + t = tempnode(tmpnr, ty, 0, 0); + t = block(SCONV, t, NIL, PTR+INT, 0, 0); + t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); + t = buildtree(UMUL, t, NIL); + + r = block(REG, NIL, NIL, INT, 0, 0); + regno(r) = reg++; + r = buildtree(ASSIGN, r, t); + + q = block(CM, q, r, INT, 0, 0); + } + + /* put the rest of the structure on the stack */ + for (i = num; i < sz; i++) { + t = tempnode(tmpnr, ty, 0, 0); + t = block(SCONV, t, NIL, PTR+INT, 0, 0); + t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); + t = buildtree(UMUL, t, NIL); + r = pusharg(t, ®); + q = block(CM, q, r, INT, 0, 0); + } + + q = reverse(q); + + *regp = reg; + return q; +} + + +static NODE * +moveargs(NODE *p, int *regp, int *fregp) +{ + NODE *r, **rp; + int reg, freg; + + if (p->n_op == CM) { + p->n_left = moveargs(p->n_left, regp, fregp); + r = p->n_right; + rp = &p->n_right; + } else { + r = p; + rp = &p; + } + + reg = *regp; + freg = *fregp; + +#define ISFLOAT(p) (p->n_type == FLOAT || \ + p->n_type == DOUBLE || \ + p->n_type == LDOUBLE) + + if (reg > R10 && r->n_op != STARG) { + *rp = pusharg(r, regp); + } else if (r->n_op == STARG) { + *rp = movearg_struct(r, regp); + } else if (DEUNSIGN(r->n_type) == LONGLONG) { + *rp = movearg_64bit(r, regp); + } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { + if (features(FEATURE_HARDFLOAT)) + *rp = movearg_double(r, fregp, regp); + else + *rp = movearg_64bit(r, regp); + } else if (r->n_type == FLOAT) { + if (features(FEATURE_HARDFLOAT)) + *rp = movearg_float(r, fregp, regp); + else + *rp = movearg_32bit(r, regp); + } else { + *rp = movearg_32bit(r, regp); + } + + return straighten(p); +} + +/* + * Fixup arguments to pass pointer-to-struct as first argument. + * + * called from funcode(). + */ +static NODE * +retstruct(NODE *p) +{ + struct symtab s; + NODE *l, *r, *t, *q; + TWORD ty; + + l = p->n_left; + r = p->n_right; + + ty = DECREF(l->n_type) - FTN; + + s.sclass = AUTO; + s.stype = ty; + s.sdf = l->n_df; + s.sap = l->n_ap; + oalloc(&s, &autooff); + q = block(REG, NIL, NIL, INCREF(ty), l->n_df, l->n_ap); + regno(q) = FPREG; + q = block(MINUS, q, bcon(autooff/SZCHAR), INCREF(ty), + l->n_df, l->n_ap); + + /* insert hidden assignment at beginning of list */ + if (r->n_op != CM) { + p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap); + } else { + for (t = r; t->n_left->n_op == CM; t = t->n_left) + ; + t->n_left = block(CM, q, t->n_left, INCREF(ty), + l->n_df, l->n_ap); + } + + return p; +} + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + */ +NODE * +funcode(NODE *p) +{ + int regnum = R3; + int fregnum = F1; + + if (DECREF(p->n_left->n_type) == STRTY+FTN || + DECREF(p->n_left->n_type) == UNIONTY+FTN) + p = retstruct(p); + + p->n_right = moveargs(p->n_right, ®num, &fregnum); + + if (p->n_right == NULL) + p->n_op += (UCALL - CALL); + + return p; +} diff --git a/lang/pcc/pcc/arch/powerpc/local.c b/lang/pcc/pcc/arch/powerpc/local.c new file mode 100644 index 000000000..e469235ec --- /dev/null +++ b/lang/pcc/pcc/arch/powerpc/local.c @@ -0,0 +1,1358 @@ +/* $Id: local.c,v 1.34 2012/09/06 13:07:29 plunky Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 +#include "pass1.h" + +#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) + +extern int kflag; + +static void simmod(NODE *p); + +/* this file contains code which is dependent on the target machine */ + +#if defined(MACHOABI) + +/* + * Keep track of PIC stubs. + */ + +void +addstub(struct stub *list, char *name) +{ + struct stub *s; + + DLIST_FOREACH(s, list, link) { + if (strcmp(s->name, name) == 0) + return; + } + + s = permalloc(sizeof(struct stub)); + s->name = newstring(name, strlen(name)); + DLIST_INSERT_BEFORE(list, s, link); +} + +#endif + + +/* + * Make a symtab entry for PIC use. + */ +static struct symtab * +picsymtab(char *p, char *s, char *s2) +{ + struct symtab *sp = IALLOC(sizeof(struct symtab)); + size_t len = strlen(p) + strlen(s) + strlen(s2) + 1; + + sp->sname = sp->soname = IALLOC(len); + strlcpy(sp->soname, p, len); + strlcat(sp->soname, s, len); + strlcat(sp->soname, s2, len); + sp->sclass = EXTERN; + sp->sflags = sp->slevel = 0; + + return sp; +} + +int gotnr; /* tempnum for GOT register */ + +/* + * Create a reference for an extern variable. + */ +static NODE * +picext(NODE *p) +{ + NODE *q; + struct symtab *sp; + char *name; + + name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname); + + if (strncmp(name, "__builtin", 9) == 0) + return p; + +#if defined(ELFABI) + + sp = picsymtab("", name, "@got(31)"); + q = xbcon(0, sp, PTR+VOID); + q = block(UMUL, q, 0, PTR+VOID, 0, 0); + +#elif defined(MACHOABI) + + char buf2[64]; + NODE *r; + char *fname; + + fname = cftnsp->soname ? cftnsp->soname : cftnsp->sname; + + if (p->n_sp->sclass == EXTDEF) { + snprintf(buf2, 64, "-L%s$pb", fname); + sp = picsymtab("", name, buf2); + } else { + snprintf(buf2, 64, "$non_lazy_ptr-L%s$pb", fname); + sp = picsymtab("L", name, buf2); + addstub(&nlplist, name); + } +#if USE_GOTNR + q = tempnode(gotnr, PTR+VOID, 0, 0); +#else + q = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(q) = GOTREG; +#endif + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + + if (p->n_sp->sclass != EXTDEF) + q = block(UMUL, q, 0, PTR+VOID, 0, 0); + +#endif + + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; /* for init */ + nfree(p); + + return q; +} + +/* + * Create a reference for a static variable + */ + +static NODE * +picstatic(NODE *p) +{ + NODE *q; + struct symtab *sp; + +#if defined(ELFABI) + char *n; + + if (p->n_sp->slevel > 0) { + char buf[64]; + snprintf(buf, 64, LABFMT, (int)p->n_sp->soffset); + sp = picsymtab("", buf, "@got(31)"); + } else { + n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname; + sp = picsymtab("", exname(n), "@got(31)"); + } + sp->sclass = STATIC; + sp->stype = p->n_sp->stype; + q = xbcon(0, sp, PTR+VOID); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; + nfree(p); + +#elif defined(MACHOABI) + + char buf2[64]; + NODE *r; + + snprintf(buf2, 64, "-L%s$pb", + cftnsp->soname ? cftnsp->soname : cftnsp->sname); + + if (p->n_sp->slevel > 0) { + char buf1[64]; + snprintf(buf1, 64, LABFMT, (int)p->n_sp->soffset); + sp = picsymtab("", buf1, buf2); + } else { + char *name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname); + sp = picsymtab("", name, buf2); + } + sp->sclass = STATIC; + sp->stype = p->n_sp->stype; +#if USE_GOTNR + q = tempnode(gotnr, PTR+VOID, 0, 0); +#else + q = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(q) = GOTREG; +#endif + r = xbcon(0, sp, INT); + q = buildtree(PLUS, q, r); + q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); + q->n_sp = p->n_sp; + nfree(p); + +#endif + + return q; +} + +static NODE * +convert_ulltof(NODE *p) +{ + NODE *q, *r, *l, *t; + int ty; + int tmpnr; + + ty = p->n_type; + l = p->n_left; + nfree(p); + + q = tempnode(0, ULONGLONG, 0, 0); + tmpnr = regno(q); + t = buildtree(ASSIGN, q, l); + ecomp(t); + +#if 0 + q = tempnode(tmpnr, ULONGLONG, 0, 0); + q = block(SCONV, q, NIL, LONGLONG, 0, 0); +#endif + q = tempnode(tmpnr, LONGLONG, 0, 0); + r = block(SCONV, q, NIL, ty, 0, 0); + + q = tempnode(tmpnr, ULONGLONG, 0, 0); + q = block(RS, q, bcon(1), ULONGLONG, 0, 0); + q = block(SCONV, q, NIL, LONGLONG, 0, 0); + q = block(SCONV, q, NIL, ty, 0, 0); + t = block(FCON, NIL, NIL, ty, 0, 0); + t->n_dcon = 2; + l = block(MUL, q, t, ty, 0, 0); + + r = buildtree(COLON, l, r); + + q = tempnode(tmpnr, ULONGLONG, 0, 0); + q = block(SCONV, q, NIL, LONGLONG, 0, 0); + l = block(LE, q, xbcon(0, NULL, LONGLONG), INT, 0, 0); + + return clocal(buildtree(QUEST, l, r)); + +} + + +/* clocal() is called to do local transformations on + * an expression tree preparitory to its being + * written out in intermediate code. + * + * the major essential job is rewriting the + * automatic variables and arguments in terms of + * REG and OREG nodes + * conversion ops which are not necessary are also clobbered here + * in addition, any special features (such as rewriting + * exclusive or) are easily handled here as well + */ +NODE * +clocal(NODE *p) +{ + + struct symtab *q; + NODE *r, *l; + int o; + int m; + TWORD t; + int isptrvoid = 0; + int tmpnr; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + switch (o = p->n_op) { + + case ADDROF: +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal(): ADDROF\n"); + printf("type: 0x%x\n", p->n_type); + } +#endif + /* XXX cannot takes addresses of PARAMs */ + + if (kflag == 0 || blevel == 0) + break; + /* char arrays may end up here */ + l = p->n_left; + if (l->n_op != NAME || + (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE)) + break; + l = p; + p = picstatic(p->n_left); + nfree(l); + if (p->n_op != UMUL) + cerror("ADDROF error"); + l = p; + p = p->n_left; + nfree(l); + break; + + case NAME: + if ((q = p->n_sp) == NULL) + return p; /* Nothing to care about */ + + switch (q->sclass) { + + case PARAM: + case AUTO: + /* fake up a structure reference */ + r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + r->n_lval = 0; + r->n_rval = FPREG; + p = stref(block(STREF, r, p, 0, 0, 0)); + break; + + case USTATIC: + if (kflag == 0) + break; + /* FALLTHROUGH */ + + case STATIC: + if (kflag == 0) { + if (q->slevel == 0) + break; + p->n_lval = 0; + } else if (blevel > 0) { + p = picstatic(p); + } + break; + + case REGISTER: + p->n_op = REG; + p->n_lval = 0; + p->n_rval = q->soffset; + break; + + case EXTERN: + case EXTDEF: + if (kflag == 0) + break; + if (blevel > 0) + p = picext(p); + break; + } + break; + + case UCALL: + case CALL: + case USTCALL: + case STCALL: + if (p->n_type == VOID) + break; + /* + * if the function returns void*, ecode() invokes + * delvoid() to convert it to uchar*. + * We just let this happen on the ASSIGN to the temp, + * and cast the pointer back to void* on access + * from the temp. + */ + if (p->n_type == PTR+VOID) + isptrvoid = 1; + r = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(r); + r = buildtree(ASSIGN, r, p); + + p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); + if (isptrvoid) { + p = block(PCONV, p, NIL, PTR+VOID, + p->n_df, 0); + } +#if 1 + p = buildtree(COMOP, r, p); +#else + /* XXX this doesn't work if the call is already in a COMOP */ + r = clocal(r); + ecomp(r); +#endif + break; + + case CBRANCH: + l = p->n_left; + + /* + * Remove unnecessary conversion ops. + */ + if (clogop(l->n_op) && l->n_left->n_op == SCONV) { + if (coptype(l->n_op) != BITYPE) + break; + if (l->n_right->n_op == ICON) { + r = l->n_left->n_left; + if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) + break; + /* Type must be correct */ + t = r->n_type; + nfree(l->n_left); + l->n_left = r; + l->n_type = t; + l->n_right->n_type = t; + } + } + break; + + case PCONV: + /* Remove redundant PCONV's. Be careful */ + l = p->n_left; + if (l->n_op == ICON) { + l->n_lval = (unsigned)l->n_lval; + goto delp; + } + if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { + /* float etc? */ + p->n_left = block(SCONV, l, NIL, + UNSIGNED, 0, 0); + break; + } + /* if left is SCONV, cannot remove */ + if (l->n_op == SCONV) + break; + + /* avoid ADDROF TEMP */ + if (l->n_op == ADDROF && l->n_left->n_op == TEMP) + break; + + /* if conversion to another pointer type, just remove */ + if (p->n_type > BTMASK && l->n_type > BTMASK) + goto delp; + break; + + delp: l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_ap = p->n_ap; + nfree(p); + p = l; + break; + + case SCONV: + l = p->n_left; + + if (p->n_type == l->n_type) { + nfree(p); + return l; + } + + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + tsize(p->n_type, p->n_df, p->n_ap) == + tsize(l->n_type, l->n_df, l->n_ap)) { + if (p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != LDOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + return l; + } + } + } + + if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && + coptype(l->n_op) == BITYPE) { + l->n_type = p->n_type; + nfree(p); + return l; + } + + /* + * if converting ULONGLONG to FLOAT/(L)DOUBLE, + * replace ___floatunsdidf() with ___floatdidf() + */ + if (l->n_type == ULONGLONG && p->n_type >= FLOAT && + p->n_type <= LDOUBLE) { + return convert_ulltof(p); + } + + o = l->n_op; + m = p->n_type; + + if (o == ICON) { + CONSZ val = l->n_lval; + + if (!ISPTR(m)) /* Pointers don't need to be conv'd */ + switch (m) { + case BOOL: + l->n_lval = l->n_lval != 0; + break; + case CHAR: + l->n_lval = (char)val; + break; + case UCHAR: + l->n_lval = val & 0377; + break; + case SHORT: + l->n_lval = (short)val; + break; + case USHORT: + l->n_lval = val & 0177777; + break; + case ULONG: + case UNSIGNED: + l->n_lval = val & 0xffffffff; + break; + case LONG: + case INT: + l->n_lval = (int)val; + break; + case LONGLONG: + l->n_lval = (long long)val; + break; + case ULONGLONG: + l->n_lval = val; + break; + case VOID: + break; + case LDOUBLE: + case DOUBLE: + case FLOAT: + l->n_op = FCON; + l->n_dcon = val; + break; + default: + cerror("unknown type %d", m); + } + l->n_type = m; + l->n_ap = 0; + nfree(p); + return l; + } else if (o == FCON) { + l->n_lval = l->n_dcon; + l->n_sp = NULL; + l->n_op = ICON; + l->n_type = m; + l->n_ap = 0; + nfree(p); + return clocal(l); + } + if (DEUNSIGN(p->n_type) == SHORT && + DEUNSIGN(l->n_type) == SHORT) { + nfree(p); + p = l; + } + if ((DEUNSIGN(p->n_type) == CHAR || + DEUNSIGN(p->n_type) == SHORT) && + (l->n_type == FLOAT || l->n_type == DOUBLE || + l->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left->n_type = INT; + return p; + } + if ((DEUNSIGN(l->n_type) == CHAR || + DEUNSIGN(l->n_type) == SHORT) && + (p->n_type == FLOAT || p->n_type == DOUBLE || + p->n_type == LDOUBLE)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left->n_type = INT; + return p; + } + break; + + case MOD: + simmod(p); + break; + + case DIV: + if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) + break; + /* make it an int division by inserting conversions */ + p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); + p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); + p = block(SCONV, p, NIL, p->n_type, 0, 0); + p->n_left->n_type = INT; + break; + + case STNAME: + if ((q = p->n_sp) == NULL) + return p; + if (q->sclass != STNAME) + return p; + t = p->n_type; + p = block(ADDROF, p, NIL, INCREF(t), p->n_df, p->n_ap); + p = block(UMUL, p, NIL, t, p->n_df, p->n_ap); + break; + + case FORCE: + /* put return value in return reg */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + p->n_left->n_rval = p->n_left->n_type == BOOL ? + RETREG(BOOL_TYPE) : RETREG(p->n_type); + break; + + case LS: + case RS: + if (p->n_right->n_op == ICON) + break; /* do not do anything */ + if (DEUNSIGN(p->n_right->n_type) == INT) + break; + p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); + break; + } + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal end: %p\n", p); + fwalk(p, eprint, 0); + } +#endif + return(p); +} + +/* + * Change CALL references to either direct (static) or PLT. + */ +static void +fixnames(NODE *p, void *arg) +{ + struct symtab *sp; + struct attr *ap; + NODE *q; + char *c; + int isu; + + if ((cdope(p->n_op) & CALLFLG) == 0) + return; + + isu = 0; + q = p->n_left; + ap = q->n_ap; + if (q->n_op == UMUL) + q = q->n_left, isu = 1; + +#if defined(ELFABI) + + if (q->n_op == ICON) { + sp = q->n_sp; + +#elif defined(MACHOABI) + +#ifdef USE_GOTNR + if (q->n_op == PLUS && q->n_left->n_op == TEMP && +#else + if (q->n_op == PLUS && q->n_left->n_op == REG && +#endif + q->n_right->n_op == ICON) { + sp = q->n_right->n_sp; +#endif + + if (sp == NULL) + return; /* nothing to do */ + if (sp->sclass == STATIC && !ISFTN(sp->stype)) + return; /* function pointer */ + + if (sp->sclass != STATIC && sp->sclass != EXTERN && + sp->sclass != EXTDEF) + cerror("fixnames"); + c = NULL; +#if defined(ELFABI) + + if (sp->soname == NULL || + (c = strstr(sp->soname, "@got(31)")) == NULL) + cerror("fixnames2"); + if (isu) { + memcpy(c, "@plt", sizeof("@plt")); + } else + *c = 0; + +#elif defined(MACHOABI) + + if (sp->soname == NULL || + ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL && + (c = strstr(sp->soname, "-L")) == NULL)) + cerror("fixnames2"); + if (isu) { + addstub(&stublist, sp->soname+1); + memcpy(c, "$stub", sizeof("$stub")); + } else + *c = 0; + + nfree(q->n_left); + q = q->n_right; + if (isu) + nfree(p->n_left->n_left); + nfree(p->n_left); + p->n_left = q; + q->n_ap = ap; + +#endif + } +} + +void +myp2tree(NODE *p) +{ + int o = p->n_op; + struct symtab *sp; + + if (kflag) + walkf(p, fixnames, 0); + if (o != FCON) + return; + + /* Write float constants to memory */ + /* Should be voluntary per architecture */ + + sp = IALLOC(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->sap = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + + defloc(sp); + ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + + p->n_op = NAME; + p->n_lval = 0; + p->n_sp = sp; +} + +/*ARGSUSED*/ +int +andable(NODE *p) +{ + return(1); /* all names can have & taken on them */ +} + +/* + * Return 1 if a variable of type type is OK to put in register. + */ +int +cisreg(TWORD t) +{ + return 1; +} + +/* + * Allocate bits on the stack. + * 'off' is the number of bits to allocate + * 'p' is a tree that when evaluated is the multiply count for 'off' + * 't' is a storeable node where to write the allocated address + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *q, *r; + int nbytes = off / SZCHAR; + int stacksize = 24+40; /* this should be p2stacksize */ + + /* + * After we subtract the requisite bytes + * off the stack, we need to step back over + * the 40 bytes for the arguments registers + * *and* any other parameters which will get + * saved to the stack. Unfortunately, we + * don't have that information in pass1 and + * the parameters will stomp on the allocated + * space for alloca(). + * + * No fix yet. + */ + werror("parameters may stomp on alloca()"); + + /* compute size */ + p = buildtree(MUL, p, bcon(nbytes)); + p = buildtree(PLUS, p, bcon(ALSTACK/SZCHAR)); + + /* load the top-of-stack */ + q = block(REG, NIL, NIL, PTR+INT, 0, 0); + regno(q) = SPREG; + q = block(UMUL, q, NIL, INT, 0, 0); + + /* save old top-of-stack value to new top-of-stack position */ + r = block(REG, NIL, NIL, PTR+INT, 0, 0); + regno(r) = SPREG; + r = block(MINUSEQ, r, p, INT, 0, 0); + r = block(UMUL, r, NIL, INT, 0, 0); + ecomp(buildtree(ASSIGN, r, q)); + + r = block(REG, NIL, NIL, PTR+INT, 0, 0); + regno(r) = SPREG; + + /* skip over the arguments space and align to 16 bytes */ + r = block(PLUS, r, bcon(stacksize + 15), INT, 0, 0); + r = block(RS, r, bcon(4), INT, 0, 0); + r = block(LS, r, bcon(4), INT, 0, 0); + + t->n_type = p->n_type; + ecomp(buildtree(ASSIGN, t, r)); +} + +/* + * Print out a string of characters. + * Unfortunately, this code assumes that the assembler understands + * C-style escape sequences. (which it doesn't!) + * Location is already set. + */ +void +instring(struct symtab *sp) +{ + char *s, *str = sp->sname; + +#if defined(ELFABI) + + defloc(sp); + +#elif defined(MACHOABI) + + extern int lastloc; + if (lastloc != STRNG) + printf(" .cstring\n"); + lastloc = STRNG; + printf("\t.p2align 2\n"); + printf(LABFMT ":\n", sp->soffset); + +#endif + + /* be kind to assemblers and avoid long strings */ + printf("\t.ascii \""); + for (s = str; *s != 0; ) { + if (*s++ == '\\') { + (void)esccon(&s); + } + if (s - str > 64) { + fwrite(str, 1, s - str, stdout); + printf("\"\n\t.ascii \""); + str = s; + } + } + fwrite(str, 1, s - str, stdout); + printf("\\0\"\n"); +} + +/* + * print out a constant node, may be associated with a label. + * Do not free the node after use. + * off is bit offset from the beginning of the aggregate + * fsz is the number of bits this is referring to + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; long double l; int i[3]; } u; + struct symtab *q; + char *c; + TWORD t; + int i; + + t = p->n_type; + if (t > BTMASK) + p->n_type = t = INT; /* pointer */ + + + if (kflag && (p->n_op == PLUS || p->n_op == UMUL)) { + if (p->n_op == UMUL) + p = p->n_left; + p = p->n_right; + q = p->n_sp; + +#if defined(ELFABI) + + if (q->soname && (c = strstr(q->soname, "@got(31)")) != NULL) + *c = 0; /* ignore GOT ref here */ + +#elif defined(MACHOABI) + + if ((c = strstr(q->soname, "$non_lazy_ptr")) != NULL) { + q->soname++; /* skip "L" */ + *c = 0; /* ignore GOT ref here */ + } + else if ((c = strstr(q->soname, "-L")) != NULL) + *c = 0; /* ignore GOT ref here */ + +#endif + + } + + if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) + uerror("element not constant"); + + switch (t) { + case LONGLONG: + case ULONGLONG: +#if 0 + /* little-endian */ + i = (p->n_lval >> 32); + p->n_lval &= 0xffffffff; + p->n_type = INT; + ninval(off, 32, p); + p->n_lval = i; + ninval(off+32, 32, p); +#endif + /* big-endian */ + i = (p->n_lval & 0xffffffff); + p->n_lval >>= 32; + p->n_type = INT; + ninval(off, 32, p); + p->n_lval = i; + ninval(off+32, 32, p); + + break; + case INT: + case UNSIGNED: + printf("\t.long %d", (int)p->n_lval); + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0)) { + printf("+" LABFMT, q->soffset); + } else { + char *name = q->soname ? q->soname : exname(q->sname); + printf("+%s", name); + } + } + printf("\n"); + break; + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)p->n_dcon; +#if 0 + /* little-endian */ + printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]); +#endif + /* big-endian */ + printf("\t.long 0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]); + break; + case DOUBLE: + u.d = (double)p->n_dcon; + printf("\t.long 0x%x\n\t.long 0x%x\n", u.i[0], u.i[1]); + break; + case FLOAT: + u.f = (float)p->n_dcon; + printf("\t.long 0x%x\n", u.i[0]); + break; + default: + return 0; + } + return 1; +} + +/* make a name look like an external name in the local machine */ +char * +exname(char *p) +{ +#if defined(ELFABI) + + return (p == NULL ? "" : p); + +#elif defined(MACHOABI) + +#define NCHNAM 256 + static char text[NCHNAM+1]; + int i; + + if (p == NULL) + return ""; + + text[0] = '_'; + for (i=1; *p && istype, sp->sdf, sp->sap); + off = (off+(SZCHAR-1))/SZCHAR; + printf("\t.%scomm ", sp->sclass == STATIC ? "l" : ""); + n = sp->soname ? sp->soname : exname(sp->sname); + if (sp->slevel == 0) + printf("%s,%d\n", n, off); + else + printf(LABFMT ",%d\n", sp->soffset, off); +} + + +#ifdef notdef +/* make a common declaration for id, if reasonable */ +void +commdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + printf("\t.comm %s,0%o\n", q->soname ? q->soname : exname(q->sname), off); +} + +/* make a local common declaration for id, if reasonable */ +void +lcommdec(struct symtab *q) +{ + int off; + + off = tsize(q->stype, q->sdf, q->ssue); + off = (off+(SZCHAR-1))/SZCHAR; + if (q->slevel == 0) + printf("\t.lcomm %s,%d\n", q->soname ? q->soname : exname(q->sname), off); + else + printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off); +} + +/* + * print a (non-prog) label. + */ +void +deflab1(int label) +{ + printf(LABFMT ":\n", label); +} + +#if defined(ELFABI) + +static char *loctbl[] = { "text", "data", "section .rodata,", + "section .rodata" }; + +#elif defined(MACHOABI) + +static char *loctbl[] = { "text", "data", "section .rodata,", "cstring" }; + +#endif + +void +setloc1(int locc) +{ +#ifdef PCC_DEBUG + if (xdebug) + printf("setloc1: locc=%d, lastloc=%d\n", locc, lastloc); +#endif + + if (locc == lastloc) + return; + lastloc = locc; + printf(" .%s\n", loctbl[locc]); +} +#endif + +/* simulate and optimise the MOD opcode */ +static void +simmod(NODE *p) +{ + NODE *r = p->n_right; + + assert(p->n_op == MOD); + + if (!ISUNSIGNED(p->n_type)) + return; + +#define ISPOW2(n) ((n) && (((n)&((n)-1)) == 0)) + + /* if the right is a constant power of two, then replace with AND */ + if (r->n_op == ICON && ISPOW2(r->n_lval)) { + p->n_op = AND; + r->n_lval--; + return; + } + +#undef ISPOW2 + + /* other optimizations can go here */ +} + +static int constructor; +static int destructor; + +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + if (strcmp(str, "tls") == 0) { + uerror("thread-local storage not supported for this target"); + return 1; + } + if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { + constructor = 1; + return 1; + } + if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { + destructor = 1; + return 1; + } + + return 0; +} + +/* + * Called when a identifier has been declared, to give target last word. + */ +void +fixdef(struct symtab *sp) +{ + /* may have sanity checks here */ + if ((constructor || destructor) && (sp->sclass != PARAM)) { +#ifdef MACHOABI + if (kflag) { + if (constructor) + printf("\t.mod_init_func\n"); + else + printf("\t.mod_term_func\n"); + } else { + if (constructor) + printf("\t.constructor\n"); + else + printf("\t.destructor\n"); + } + printf("\t.p2align 2\n"); + printf("\t.long %s\n", exname(sp->sname)); + printf("\t.text\n"); + constructor = destructor = 0; +#endif + } +} + +/* + * There is very little different here to the standard builtins. + * It basically handles promotion of types smaller than INT. + */ + +NODE * +powerpc_builtin_stdarg_start(NODE *f, NODE *a, TWORD t) +{ + NODE *p, *q; + int sz = 1; + + /* check num args and type */ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || + !ISPTR(a->n_left->n_type)) + goto bad; + + /* must first deal with argument size; use int size */ + p = a->n_right; + if (p->n_type < INT) { + /* round up to word */ + sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap); + } + + p = buildtree(ADDROF, p, NIL); /* address of last arg */ + p = optim(buildtree(PLUS, p, bcon(sz))); + q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); + q = buildtree(CAST, q, p); + p = q->n_right; + nfree(q->n_left); + nfree(q); + p = buildtree(ASSIGN, a->n_left, p); + tfree(f); + nfree(a); + + return p; + +bad: + uerror("bad argument to __builtin_stdarg_start"); + return bcon(0); +} + +NODE * +powerpc_builtin_va_arg(NODE *f, NODE *a, TWORD t) +{ + NODE *p, *q, *r; + int sz, tmpnr; + + /* check num args and type */ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || + !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE) + goto bad; + + r = a->n_right; + + /* get type size */ + sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR; + if (sz < SZINT/SZCHAR) { + werror("%s%s promoted to int when passed through ...", + ISUNSIGNED(r->n_type) ? "unsigned " : "", + DEUNSIGN(r->n_type) == SHORT ? "short" : "char"); + sz = SZINT/SZCHAR; + r->n_type = INT; + r->n_ap = 0; + } + + p = tcopy(a->n_left); + +#if defined(ELFABI) + + /* alignment */ + if (SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) { + p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1)); + p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap); + } + +#endif + + /* create a copy to a temp node */ + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + tmpnr = regno(q); + p = buildtree(ASSIGN, q, p); + + q = tempnode(tmpnr, p->n_type, p->n_df, p->n_ap); + q = buildtree(PLUS, q, bcon(sz)); + q = buildtree(ASSIGN, a->n_left, q); + + q = buildtree(COMOP, p, q); + + nfree(a->n_right); + nfree(a); + nfree(f); + + p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap); + p = buildtree(UMUL, p, NIL); + p = buildtree(COMOP, q, p); + + return p; + +bad: + uerror("bad argument to __builtin_va_arg"); + return bcon(0); +} + +NODE * +powerpc_builtin_va_end(NODE *f, NODE *a, TWORD t) +{ + tfree(f); + tfree(a); + + return bcon(0); +} + +NODE * +powerpc_builtin_va_copy(NODE *f, NODE *a, TWORD t) +{ + if (a == NULL || a->n_op != CM || a->n_left->n_op == CM) + goto bad; + tfree(f); + f = buildtree(ASSIGN, a->n_left, a->n_right); + nfree(a); + return f; + +bad: + uerror("bad argument to __buildtin_va_copy"); + return bcon(0); +} + +NODE * +powerpc_builtin_return_address(NODE *f, NODE *a, TWORD t) +{ + int nframes; + int i = 0; + + if (a == NULL || a->n_op != ICON) + goto bad; + + nframes = a->n_lval; + + tfree(f); + tfree(a); + + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = SPREG; + + do { + f = block(UMUL, f, NIL, PTR+VOID, 0, 0); + } while (i++ < nframes); + + f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0); + f = buildtree(UMUL, f, NIL); + + return f; +bad: + uerror("bad argument to __builtin_return_address"); + return bcon(0); +} + +NODE * +powerpc_builtin_frame_address(NODE *f, NODE *a, TWORD t) +{ + int nframes; + int i = 0; + + if (a == NULL || a->n_op != ICON) + goto bad; + + nframes = a->n_lval; + + tfree(f); + tfree(a); + + if (nframes == 0) { + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = FPREG; + } else { + f = block(REG, NIL, NIL, PTR+VOID, 0, 0); + regno(f) = SPREG; + do { + f = block(UMUL, f, NIL, PTR+VOID, 0, 0); + } while (i++ < nframes); + f = block(PLUS, f, bcon(24), INCREF(PTR+VOID), 0, 0); + f = buildtree(UMUL, f, NIL); + } + + return f; +bad: + uerror("bad argument to __builtin_frame_address"); + return bcon(0); +} + +void +pass1_lastchance(struct interpass *ip) +{ +} diff --git a/lang/pcc/pcc/arch/powerpc/local2.c b/lang/pcc/pcc/arch/powerpc/local2.c new file mode 100644 index 000000000..70db56b03 --- /dev/null +++ b/lang/pcc/pcc/arch/powerpc/local2.c @@ -0,0 +1,1517 @@ +/* $Id: local2.c,v 1.28 2015/01/04 19:17:23 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" /* for cftnsp */ +#include "pass2.h" +#include +#include +#include + +#if defined(MACHOABI) +#define EXPREFIX "_" +#else +#define EXPREFIX "" +#endif + +#define LOWREG 0 +#define HIREG 1 + +char *rnames[] = { + REGPREFIX "r0", REGPREFIX "r1", + REGPREFIX "r2", REGPREFIX "r3", + REGPREFIX "r4", REGPREFIX "r5", + REGPREFIX "r6", REGPREFIX "r7", + REGPREFIX "r8", REGPREFIX "r9", + REGPREFIX "r10", REGPREFIX "r11", + REGPREFIX "r12", REGPREFIX "r13", + REGPREFIX "r14", REGPREFIX "r15", + REGPREFIX "r16", REGPREFIX "r17", + REGPREFIX "r18", REGPREFIX "r19", + REGPREFIX "r20", REGPREFIX "r21", + REGPREFIX "r22", REGPREFIX "r23", + REGPREFIX "r24", REGPREFIX "r25", + REGPREFIX "r26", REGPREFIX "r27", + REGPREFIX "r28", REGPREFIX "r29", + REGPREFIX "r30", REGPREFIX "r31", + "r4\0r3\0", "r5\0r4\0", "r6\0r5\0", "r7\0r6\0", + "r8\0r7\0", "r9\0r8\0", "r10r9\0", "r15r14", "r17r16", + "r19r18", "r21r20", "r23r22", "r25r24", "r27r26", + "r29r28", "r31r30", + REGPREFIX "f0", REGPREFIX "f1", + REGPREFIX "f2", REGPREFIX "f3", + REGPREFIX "f4", REGPREFIX "f5", + REGPREFIX "f6", REGPREFIX "f7", + REGPREFIX "f8", REGPREFIX "f9", + REGPREFIX "f10", REGPREFIX "f11", + REGPREFIX "f12", REGPREFIX "f13", + REGPREFIX "f14", REGPREFIX "f15", + REGPREFIX "f16", REGPREFIX "f17", + REGPREFIX "f18", REGPREFIX "f19", + REGPREFIX "f20", REGPREFIX "f21", + REGPREFIX "f22", REGPREFIX "f23", + REGPREFIX "f24", REGPREFIX "f25", + REGPREFIX "f26", REGPREFIX "f27", + REGPREFIX "f28", REGPREFIX "f29", + REGPREFIX "f30", REGPREFIX "f31", +}; + +static int argsize(NODE *p); + +static int p2calls; +static int p2temps; /* TEMPs which aren't autos yet */ +static int p2framesize; +static int p2maxstacksize; + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +static TWORD ftype; + +/* + * Print out the prolog assembler. + */ +void +prologue(struct interpass_prolog *ipp) +{ + int addto; + +#ifdef PCC_DEBUG + if (x2debug) + printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%lx, autos=%d, tmpnum=%d, lblnum=%d\n", + ipp->ipp_ip.type, + ipp->ipp_ip.lineno, + ipp->ipp_name, + ipp->ipp_vis, + ipp->ipp_type, + ipp->ipp_regs[0], + ipp->ipp_autos, + ipp->ip_tmpnum, + ipp->ip_lblnum); +#endif + + ftype = ipp->ipp_type; + + addto = p2framesize; + + if (p2calls != 0 || kflag) { + /* get return address (not required for leaf function) */ + printf("\tmflr %s\n", rnames[R0]); + printf("\tstw %s,8(%s)\n", rnames[R0], rnames[R1]); + } + /* save registers R30 and R31 */ + printf("\tstmw %s,-8(%s)\n", rnames[R30], rnames[R1]); +#ifdef FPREG + printf("\tmr %s,%s\n", rnames[FPREG], rnames[R1]); +#endif + /* create the new stack frame */ + if (addto > 32767) { + printf("\tlis %s,%d\n", rnames[R0], (-addto) >> 16); + printf("\tori %s,%s,%d\n", rnames[R0], + rnames[R0], (-addto) & 0xffff); + printf("\tstwux %s,%s,%s\n", rnames[R1], + rnames[R1], rnames[R0]); + } else { + printf("\tstwu %s,-%d(%s)\n", rnames[R1], addto, rnames[R1]); + } + + if (kflag) { +#if defined(ELFABI) + printf("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n"); + printf("\tmflr %s\n", rnames[GOTREG]); +#elif defined(MACHOABI) + printf("\tbcl 20,31,L%s$pb\n", ipp->ipp_name + 1); + printf("L%s$pb:\n", ipp->ipp_name + 1); + printf("\tmflr %s\n", rnames[GOTREG]); +#endif + } + +} + + +void +eoftn(struct interpass_prolog *ipp) +{ + +#ifdef PCC_DEBUG + if (x2debug) + printf("eoftn:\n"); +#endif + + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + + /* struct return needs special treatment */ + if (ftype == STRTY || ftype == UNIONTY) + cerror("eoftn"); + + /* unwind stack frame */ + printf("\tlwz %s,0(%s)\n", rnames[R1], rnames[R1]); + if (p2calls != 0 || kflag) { + printf("\tlwz %s,8(%s)\n", rnames[R0], rnames[R1]); + printf("\tmtlr %s\n", rnames[R0]); + } + printf("\tlmw %s,-8(%s)\n", rnames[R30], rnames[R1]); + printf("\tblr\n"); +} + +/* + * add/sub/... + * + * Param given: + */ +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case PLUS: + str = "addw"; + break; + case MINUS: + str = "subw"; + break; + case AND: + str = "and"; + break; + case OR: + str = "or"; + break; + case ER: + str = "xor"; + break; + default: + comperr("hopcode2: %d", o); + str = 0; /* XXX gcc */ + } + printf("%s%c", str, f); +} + +/* + * Return type size in bytes. Used by R2REGS, arg 2 to offset(). + */ +int +tlen(NODE *p) +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(SZSHORT/SZCHAR); + + case DOUBLE: + return(SZDOUBLE/SZCHAR); + + case INT: + case UNSIGNED: + case LONG: + case ULONG: + return(SZINT/SZCHAR); + + case LONGLONG: + case ULONGLONG: + return SZLONGLONG/SZCHAR; + + default: + if (!ISPTR(p->n_type)) + comperr("tlen type %d not pointer"); + return SZPOINT(p->n_type)/SZCHAR; + } +} + +/* + * Emit code to compare two longlong numbers. + */ +static void +twollcomp(NODE *p) +{ + int o = p->n_op; + int s = getlab2(); + int e = p->n_label; + int cb1, cb2; + + if (o >= ULE) + o -= (ULE-LE); + switch (o) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 4, cb2 += 4; + if (p->n_op >= ULE) + expand(p, 0, "\tcmplw UL,UR" COM "compare 64-bit values (upper)\n"); + else + expand(p, 0, "\tcmpw UL,UR" COM "compare 64-bit values (upper)\n"); + if (cb1) cbgen(cb1, s); + if (cb2) cbgen(cb2, e); + if (p->n_op >= ULE) + expand(p, 0, "\tcmplw AL,AR" COM "(and lower)\n"); + else + expand(p, 0, "\tcmpw AL,AR" COM "(and lower)\n"); + cbgen(p->n_op, e); + deflab(s); +} + +static void +shiftop(NODE *p) +{ + NODE *r = p->n_right; + TWORD ty = p->n_type; + + if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) { + expand(p, INBREG, "\tsrwi A1,AL,32-AR" COM "64-bit left-shift\n"); + expand(p, INBREG, "\tslwi U1,UL,AR\n"); + expand(p, INBREG, "\tor U1,U1,A1\n"); + expand(p, INBREG, "\tslwi A1,AL,AR\n"); + } else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) { + expand(p, INBREG, "\tli A1,0" COM "64-bit left-shift\n"); + if (r->n_lval == 32) + expand(p, INBREG, "\tmr U1,AL\n"); + else + expand(p, INBREG, "\tslwi U1,AL,AR-32\n"); + } else if (p->n_op == LS && r->n_op == ICON) { + expand(p, INBREG, "\tli A1,0" COM "64-bit left-shift\n"); + expand(p, INBREG, "\tli U1,0\n"); + } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) { + expand(p, INBREG, "\tslwi U1,UL,32-AR" COM "64-bit right-shift\n"); + expand(p, INBREG, "\tsrwi A1,AL,AR\n"); + expand(p, INBREG, "\tor A1,A1,U1\n"); + if (ty == LONGLONG) + expand(p, INBREG, "\tsrawi U1,UL,AR\n"); + else + expand(p, INBREG, "\tsrwi U1,UL,AR\n"); + } else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) { + if (ty == LONGLONG) + expand(p, INBREG, "\tli U1,-1" COM "64-bit right-shift\n"); + else + expand(p, INBREG, "\tli U1,0" COM "64-bit right-shift\n"); + if (r->n_lval == 32) + expand(p, INBREG, "\tmr A1,UL\n"); + else if (ty == LONGLONG) + expand(p, INBREG, "\tsrawi A1,UL,AR-32\n"); + else + expand(p, INBREG, "\tsrwi A1,UL,AR-32\n"); + } else if (p->n_op == RS && r->n_op == ICON) { + expand(p, INBREG, "\tli A1,0" COM "64-bit right-shift\n"); + expand(p, INBREG, "\tli U1,0\n"); + } +} + +/* + * Structure assignment. + */ +static void +stasg(NODE *p) +{ + NODE *l = p->n_left; + int val = l->n_lval; + + /* R3 = dest, R4 = src, R5 = len */ + printf("\tli %s,%d\n", rnames[R5], attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); + if (l->n_op == OREG) { + printf("\taddi %s,%s,%d\n", rnames[R3], rnames[regno(l)], val); + } else if (l->n_op == NAME) { +#if defined(ELFABI) + printf("\tli %s,", rnames[R3]); + adrput(stdout, l); + printf("@ha\n"); + printf("\taddi %s,%s,", rnames[R3], rnames[R3]); + adrput(stdout, l); + printf("@l\n"); +#elif defined(MACHOABI) + printf("\tli %s,ha16(", rnames[R3]); + adrput(stdout, l); + printf(")\n"); + printf("\taddi %s,%s,lo16(", rnames[R3], rnames[R3]); + adrput(stdout, l); + printf(")\n"); +#endif + } + if (kflag) { +#if defined(ELFABI) + printf("\tbl %s@got(30)\n", EXPREFIX "memcpy"); +#elif defined(MACHOABI) + printf("\tbl L%s$stub\n", EXPREFIX "memcpy"); + addstub(&stublist, EXPREFIX "memcpy"); +#endif + } else { + printf("\tbl %s\n", EXPREFIX "memcpy"); + } +} + +static void +fpemul(NODE *p) +{ + NODE *l = p->n_left; + char *ch = NULL; + + if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3"; + else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3"; + else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3"; + + else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3"; + else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3"; + else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3"; + + else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3"; + else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3"; + else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3"; + + else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3"; + else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3"; + else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3"; + + else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2"; + else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2"; + else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2"; + + else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2"; + else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2"; + else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2"; + + else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2"; + else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2"; + else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2"; + + else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2"; + else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2"; + else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2"; + + else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2"; + else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2"; + else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2"; + + else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2"; + else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2"; + else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2"; + + else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2"; + else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2"; + else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2"; + + else if (p->n_op == SCONV && p->n_type == FLOAT) { + if (l->n_type == DOUBLE) ch = "truncdfsf2"; + else if (l->n_type == LDOUBLE) ch = "truncdfsf2"; + else if (l->n_type == ULONGLONG) ch = "floatunsdisf"; + else if (l->n_type == LONGLONG) ch = "floatdisf"; + else if (l->n_type == LONG) ch = "floatsisf"; + else if (l->n_type == ULONG) ch = "floatunsisf"; + else if (l->n_type == INT) ch = "floatsisf"; + else if (l->n_type == UNSIGNED) ch = "floatunsisf"; + } else if (p->n_op == SCONV && p->n_type == DOUBLE) { + if (l->n_type == FLOAT) ch = "extendsfdf2"; + else if (l->n_type == LDOUBLE) ch = "truncdfdf2"; + else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; + else if (l->n_type == LONGLONG) ch = "floatdidf"; + else if (l->n_type == LONG) ch = "floatsidf"; + else if (l->n_type == ULONG) ch = "floatunssidf"; + else if (l->n_type == INT) ch = "floatsidf"; + else if (l->n_type == UNSIGNED) ch = "floatunssidf"; + } else if (p->n_op == SCONV && p->n_type == LDOUBLE) { + if (l->n_type == FLOAT) ch = "extendsfdf2"; + else if (l->n_type == DOUBLE) ch = "extenddfdf2"; + else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; + else if (l->n_type == LONGLONG) ch = "floatdidf"; + else if (l->n_type == LONG) ch = "floatsidf"; + else if (l->n_type == ULONG) ch = "floatunssidf"; + else if (l->n_type == INT) ch = "floatsidf"; + else if (l->n_type == UNSIGNED) ch = "floatunsidf"; + } else if (p->n_op == SCONV && p->n_type == ULONGLONG) { + if (l->n_type == FLOAT) ch = "fixunssfdi"; + else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; + else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; + } else if (p->n_op == SCONV && p->n_type == LONGLONG) { + if (l->n_type == FLOAT) ch = "fixsfdi"; + else if (l->n_type == DOUBLE) ch = "fixdfdi"; + else if (l->n_type == LDOUBLE) ch = "fixdfdi"; + } else if (p->n_op == SCONV && p->n_type == LONG) { + if (l->n_type == FLOAT) ch = "fixsfdi"; + else if (l->n_type == DOUBLE) ch = "fixdfdi"; + else if (l->n_type == LDOUBLE) ch = "fixdfdi"; + } else if (p->n_op == SCONV && p->n_type == ULONG) { + if (l->n_type == FLOAT) ch = "fixunssfdi"; + else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; + else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; + } else if (p->n_op == SCONV && p->n_type == INT) { + if (l->n_type == FLOAT) ch = "fixsfsi"; + else if (l->n_type == DOUBLE) ch = "fixdfsi"; + else if (l->n_type == LDOUBLE) ch = "fixdfsi"; + } else if (p->n_op == SCONV && p->n_type == UNSIGNED) { + if (l->n_type == FLOAT) ch = "fixunssfsi"; + else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; + else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; + } + + if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op); + + if (kflag) { +#if defined(ELFABI) + printf("\tbl __%s%s@got(30)" COM "soft-float\n", EXPREFIX, ch); +#elif defined(MACHOABI) + char buf[32]; + printf("\tbl L__%s%s$stub" COM "soft-float\n", EXPREFIX, ch); + snprintf(buf, 32, "__%s%s", EXPREFIX, ch); + addstub(&stublist, buf); +#endif + } else { + printf("\tbl __%s%s" COM "soft-float\n", EXPREFIX, ch); + } + + if (p->n_op >= EQ && p->n_op <= GT) + printf("\tcmpwi %s,0\n", rnames[R3]); +} + +/* + * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines + */ + +static void +emul(NODE *p) +{ + char *ch = NULL; + + if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3"; + else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG || + DEUNSIGN(p->n_type) == INT)) + ch = "ashlsi3"; + + else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3"; + else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT)) + ch = "lshrsi3"; + + else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3"; + else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT)) + ch = "ashrsi3"; + + else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3"; + else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT)) + ch = "divsi3"; + + else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3"; + else if (p->n_op == DIV && (p->n_type == ULONG || + p->n_type == UNSIGNED)) + ch = "udivsi3"; + + else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3"; + else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT)) + ch = "modsi3"; + + else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3"; + else if (p->n_op == MOD && (p->n_type == ULONG || + p->n_type == UNSIGNED)) + ch = "umodsi3"; + + else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3"; + else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT)) + ch = "mulsi3"; + + else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2"; + else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2"; + + else ch = 0, comperr("ZE"); + if (kflag) { +#if defined(ELFABI) + printf("\tbl __%s%s@got(30)" COM "emulated op\n", EXPREFIX, ch); +#elif defined(MACHOABI) + char buf[32]; + printf("\tbl L__%s%s$stub" COM "emulated op\n", EXPREFIX, ch); + snprintf(buf, 32, "__%s%s", EXPREFIX, ch); + addstub(&stublist, buf); +#endif + } else { + printf("\tbl __%s%s" COM "emulated operation\n", EXPREFIX, ch); + } +} + +/* + * Floating-point conversions (int -> float/double & float/double -> int) + */ + +static void +ftoi(NODE *p) +{ + NODE *l = p->n_left; + + printf(COM "start conversion float/(l)double to int\n"); + + if (l->n_op != OREG) { + expand(p, 0, "\tstw AL,-4"); + printf("(%s)\n", rnames[SPREG]); + if (l->n_type == FLOAT) + expand(p, 0, "\tlfs A2,"); + else + expand(p, 0, "\tlfd A2,\n"); + printf("-4(%s)\n", rnames[SPREG]); + } else { + if (l->n_type == FLOAT) + expand(p, 0, "\tlfs A2,AL\n"); + else + expand(p, 0, "\tlfd A2,AL\n"); + } + + expand(p, 0, "\tfctiwz A2,A2\n"); + expand(p, 0, "\tstfd A2,"); + printf("-8(%s)\n", rnames[SPREG]); + expand(p, 0, "\tlwz A1,"); + printf("-4(%s)\n", rnames[SPREG]); + + printf(COM "end conversion\n"); +} + +static void +ftou(NODE *p) +{ + static int lab = 0; + NODE *l = p->n_left; + int lab1 = getlab2(); + int lab2 = getlab2(); + + printf(COM "start conversion of float/(l)double to unsigned\n"); + + if (lab == 0) { + lab = getlab2(); + expand(p, 0, "\t.data\n"); + printf(LABFMT ":\t.long 0x41e00000\n\t.long 0\n", lab); + expand(p, 0, "\t.text\n"); + } + + if (l->n_op != OREG) { + expand(p, 0, "\tstw AL,"); + printf("-4(%s)\n", rnames[SPREG]); + if (l->n_type == FLOAT) + expand(p, 0, "\tlfs A3,"); + else + expand(p, 0, "\tlfd A3,"); + printf("-4(%s)\n", rnames[SPREG]); + + } else { + if (l->n_type == FLOAT) + expand(p, 0, "\tlfs A3,AL\n"); + else + expand(p, 0, "\tlfd A3,AL\n"); + } + +#if 0 + if (kflag) { + expand(p, 0, "\taddis A1,"); + printf("%s,ha16(", rnames[R31]); + printf(LABFMT, lab); + printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); + expand(p, 0, "\tlfd A2,lo16("); + printf(LABFMT, lab); + printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); + expand(p, 0, "(A1)\n"); + } else { + expand(p, 0, "\tlfd A2,"); + printf(LABFMT "\n", lab); + } +#endif + +#if defined(ELFABI) + + expand(p, 0, "\taddis A1,"); + printf("%s," LABFMT "@ha\n", rnames[R31], lab); + expand(p, 0, "\tlfd A2,"); + printf(LABFMT "@l", lab); + expand(p, 0, "(A1)\n"); + +#elif defined(MACHOABI) + + expand(p, 0, "\taddis A1,"); + printf("%s,ha16(", rnames[R31]); + printf(LABFMT, lab); + if (kflag) + printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); + printf(")\n"); + expand(p, 0, "\tlfd A2,lo16("); + printf(LABFMT, lab); + if (kflag) + printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); + expand(p, 0, ")(A1)\n"); + +#endif + + expand(p, 0, "\tfcmpu cr7,A3,A2\n"); + printf("\tcror 30,29,30\n"); + printf("\tbeq cr7,"LABFMT "\n", lab1); + + expand(p, 0, "\tfctiwz A2,A3\n"); + expand(p, 0, "\tstfd A2,"); + printf("-8(%s)\n", rnames[SPREG]); + expand(p, 0, "\tlwz A1,"); + printf("-4(%s)\n", rnames[SPREG]); + printf("\tba " LABFMT "\n", lab2); + + deflab(lab1); + + expand(p, 0, "\tfsub A2,A3,A2\n"); + expand(p, 0, "\tfctiwz A2,A2\n"); + expand(p, 0, "\tstfd A2,"); + printf("-8(%s)\n", rnames[SPREG]); + expand(p, 0, "\tlwz A1,"); + printf("-4(%s)\n", rnames[SPREG]); + expand(p, 0, "\txoris A1,A1,0x8000\n"); + + deflab(lab2); + + printf(COM "end conversion\n"); +} + +static void +itof(NODE *p) +{ + static int labu = 0; + static int labi = 0; + int lab; + NODE *l = p->n_left; + + printf(COM "start conversion (u)int to float/(l)double\n"); + + if (labi == 0 && l->n_type == INT) { + labi = getlab2(); + expand(p, 0, "\t.data\n"); + printf(LABFMT ":\t.long 0x43300000\n\t.long 0x80000000\n", labi); + expand(p, 0, "\t.text\n"); + } else if (labu == 0 && l->n_type == UNSIGNED) { + labu = getlab2(); + expand(p, 0, "\t.data\n"); + printf(LABFMT ":\t.long 0x43300000\n\t.long 0x00000000\n", labu); + expand(p, 0, "\t.text\n"); + } + + if (l->n_type == INT) { + expand(p, 0, "\txoris A1,AL,0x8000\n"); + lab = labi; + } else { + lab = labu; + } + expand(p, 0, "\tstw A1,"); + printf("-4(%s)\n", rnames[SPREG]); + expand(p, 0, "\tlis A1,0x4330\n"); + expand(p, 0, "\tstw A1,"); + printf("-8(%s)\n", rnames[SPREG]); + expand(p, 0, "\tlfd A3,"); + printf("-8(%s)\n", rnames[SPREG]); + +#if 0 + if (kflag) { + expand(p, 0, "\taddis A1,"); + printf("%s,ha16(", rnames[R31]); + printf(LABFMT, lab); + printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); + expand(p, 0, "\tlfd A2,lo16("); + printf(LABFMT, lab); + printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); + expand(p, 0, "(A1)\n"); + } else { + expand(p, 0, "\tlfd A2,"); + printf(LABFMT "\n", lab); + } +#endif + +#if defined(ELFABI) + + expand(p, 0, "\taddis A1,"); + printf("%s," LABFMT "@ha\n", rnames[R31], lab); + expand(p, 0, "\tlfd A2,"); + printf(LABFMT "@l", lab); + expand(p, 0, "(A1)\n"); + +#elif defined(MACHOABI) + + expand(p, 0, "\taddis A1,"); + printf("%s,ha16(", rnames[R31]); + printf(LABFMT, lab); + if (kflag) + printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); + printf(")\n"); + expand(p, 0, "\tlfd A2,lo16("); + printf(LABFMT, lab); + if (kflag) + printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); + expand(p, 0, ")(A1)\n"); + +#endif + + expand(p, 0, "\tfsub A3,A3,A2\n"); + if (p->n_type == FLOAT) + expand(p, 0, "\tfrsp A3,A3\n"); + + printf(COM "end conversion\n"); +} + + +static void +fpconv(NODE *p) +{ + NODE *l = p->n_left; + +#ifdef PCC_DEBUG + if (p->n_op != SCONV) + cerror("fpconv 1"); +#endif + + if (DEUNSIGN(l->n_type) == INT) + itof(p); + else if (p->n_type == INT) + ftoi(p); + else if (p->n_type == UNSIGNED) + ftou(p); + else + cerror("unhandled floating-point conversion"); + +} + +void +zzzcode(NODE *p, int c) +{ + switch (c) { + + case 'C': /* floating-point conversions */ + fpconv(p); + break; + + case 'D': /* long long comparision */ + twollcomp(p); + break; + + case 'E': /* print out emulated ops */ + emul(p); + break; + + case 'F': /* print out emulate floating-point ops */ + fpemul(p); + break; + + case 'O': /* 64-bit left and right shift operators */ + shiftop(p); + break; + + case 'Q': /* emit struct assign */ + stasg(p); + break; + + default: + comperr("zzzcode %c", c); + } +} + +/*ARGSUSED*/ +int +rewfld(NODE *p) +{ + return(1); +} + +int canaddr(NODE *); +int +canaddr(NODE *p) +{ + int o = p->n_op; + + if (o == NAME || o == REG || o == ICON || o == OREG || + (o == UMUL && shumul(p->n_left, SOREG))) + return(1); + return 0; +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + CONSZ val; + int shft; + + if (p->n_op == ASSIGN) + p = p->n_left; + + if (features(FEATURE_BIGENDIAN)) + shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval); + else + shft = UPKFOFF(p->n_rval); + + switch (**cp) { + case 'S': + printf("%d", UPKFSZ(p->n_rval)); + break; + case 'H': + printf("%d", shft); + break; + case 'M': + case 'N': + val = (CONSZ)1 << UPKFSZ(p->n_rval); + --val; + val <<= shft; + printf(CONFMT, (**cp == 'M' ? val : ~val) & 0xffffffff); + break; + default: + comperr("fldexpand"); + } + return 1; +} + +/* + * Does the bitfield shape match? + */ +int +flshape(NODE *p) +{ + int o = p->n_op; + + if (o == OREG || o == REG || o == NAME) + return SRDIR; /* Direct match */ + if (o == UMUL && shumul(p->n_left, SOREG)) + return SROREG; /* Convert into oreg */ + return SRREG; /* put it into a register */ +} + +/* INTEMP shapes must not contain any temporary registers */ +/* XXX should this go away now? */ +int +shtemp(NODE *p) +{ + printf("; shtemp\n"); + return 0; +#if 0 + int r; + + if (p->n_op == STARG ) + p = p->n_left; + + switch (p->n_op) { + case REG: + return (!istreg(regno(p))); + + case OREG: + r = regno(p); + if (R2TEST(r)) { + if (istreg(R2UPK1(r))) + return(0); + r = R2UPK2(r); + } + return (!istreg(r)); + + case UMUL: + p = p->n_left; + return (p->n_op != UMUL && shtemp(p)); + } + + if (optype(p->n_op) != LTYPE) + return(0); + return(1); +#endif +} + +void +adrcon(CONSZ val) +{ + printf( CONFMT, val); +} + +void +conput(FILE *fp, NODE *p) +{ + int val = p->n_lval; + + switch (p->n_op) { + case ICON: + if (p->n_name[0] != '\0') { + fprintf(fp, "%s", p->n_name); + if (val) + fprintf(fp, "+%d", val); + } else { + if (GCLASS(p->n_type) == CLASSB) + fprintf(fp, CONFMT, p->n_lval >> 32); + else + fprintf(fp, "%d", val); + } + return; + + default: + comperr("illegal conput, p %p", p); + } +} + +/*ARGSUSED*/ +void +insput(NODE *p) +{ + comperr("insput"); +} + +/* + * Print lower or upper name of 64-bit register. + */ +static void +reg64name(int reg, int hi) +{ + int idx; + int off = 0; + + idx = (reg > R14R15 ? (2*(reg - R14R15) + R14) : (reg - R3R4 + R3)); + + if ((hi == HIREG && !features(FEATURE_BIGENDIAN)) || + (hi == LOWREG && features(FEATURE_BIGENDIAN))) + off = 1; + + printf("%s" , rnames[idx + off]); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + size /= SZCHAR; + switch (p->n_op) { + case REG: + reg64name(regno(p), HIREG); + break; + + case NAME: + case OREG: + if (features(FEATURE_BIGENDIAN)) + printf("%d", (int)p->n_lval); + else + printf("%d", (int)(p->n_lval + 4)); + printf("(%s)", rnames[regno(p)]); + break; + + case ICON: + printf(CONFMT, p->n_lval >> 32); + break; + + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *io, NODE *p) +{ + /* output an address, with offsets, from p */ + + if (p->n_op == FLD) + p = p->n_left; + + switch (p->n_op) { + + case NAME: + if (p->n_name[0] != '\0') { + fputs(p->n_name, io); + if (p->n_lval != 0) + fprintf(io, "+" CONFMT, p->n_lval); + } else + fprintf(io, CONFMT, p->n_lval); + return; + + case OREG: + if (DEUNSIGN(p->n_type) == LONGLONG && + features(FEATURE_BIGENDIAN)) + fprintf(io, "%d", (int)(p->n_lval + 4)); + else + fprintf(io, "%d", (int)p->n_lval); + fprintf(io, "(%s)", rnames[regno(p)]); + return; + + case ICON: + /* addressable value of the constant */ + conput(io, p); + return; + + case REG: + if (GCLASS(regno(p)) == CLASSB) + reg64name(regno(p), LOWREG); + else + fprintf(io, "%s", rnames[regno(p)]); +#if 0 + switch (p->n_type) { + case DOUBLE: + case LDOUBLE: + if (features(FEATURE_HARDFLOAT)) { + fprintf(io, "%s", rnames[regno(p)]); + break; + } + /* FALL-THROUGH */ + case LONGLONG: + case ULONGLONG: + reg64name(regno(p), LOWREG); + break; + default: + fprintf(io, "%s", rnames[regno(p)]); + } +#endif + return; + + default: + comperr("illegal address, op %d, node %p", p->n_op, p); + return; + + } +} + +/* + * these mnemonics match the order of the preprocessor decls + * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT + */ + +static char * +ccbranches[] = { + "beq", /* branch if equal */ + "bne", /* branch if not-equal */ + "ble", /* branch if less-than-or-equal */ + "blt", /* branch if less-than */ + "bge", /* branch if greater-than-or-equal */ + "bgt", /* branch if greater-than */ + /* what should these be ? */ + "ble", /* branch if less-than-or-equal */ + "blt", /* branch if less-than */ + "bge", /* branch if greater-than-or-equal */ + "bgt", /* branch if greater-than */ + +}; + + +/* printf conditional and unconditional branches */ +void +cbgen(int o, int lab) +{ + if (o < EQ || o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf("\t%s " LABFMT "\n", ccbranches[o-EQ], lab); +} + +static int +argsize(NODE *p) +{ + TWORD t = p->n_type; + + if (t < LONGLONG || t == FLOAT || t > BTMASK) + return 4; + if (t == LONGLONG || t == ULONGLONG) + return 8; + if (t == DOUBLE || t == LDOUBLE) + return 8; + if (t == STRTY || t == UNIONTY) + return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + comperr("argsize"); + return 0; +} + +static int +calc_args_size(NODE *p) +{ + int n = 0; + + if (p->n_op == CM) { + n += calc_args_size(p->n_left); + n += calc_args_size(p->n_right); + return n; + } + + n += argsize(p); + + return n; +} + + +static void +fixcalls(NODE *p, void *arg) +{ + int n = 0; + + switch (p->n_op) { + case STCALL: + case CALL: + n = calc_args_size(p->n_right); + if (n > p2maxstacksize) + p2maxstacksize = n; + /* FALLTHROUGH */ + case USTCALL: + case UCALL: + ++p2calls; + break; + case TEMP: + p2temps += argsize(p); + break; + } +} + +/* + * Must store floats in memory if there are two function calls involved. + */ +static int +storefloat(struct interpass *ip, NODE *p) +{ + int l, r; + + switch (optype(p->n_op)) { + case BITYPE: + l = storefloat(ip, p->n_left); + r = storefloat(ip, p->n_right); + if (p->n_op == CM) + return 0; /* arguments, don't care */ + if (callop(p->n_op)) + return 1; /* found one */ +#define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \ + (p)->n_type == LDOUBLE) + if (ISF(p->n_left) && ISF(p->n_right) && l && r) { + /* must store one. store left */ + struct interpass *nip; + TWORD t = p->n_left->n_type; + NODE *ll; + int off; + + off = (freetemp(szty(t))); + ll = mklnode(OREG, off, SPREG, t); + nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t)); + p->n_left = mklnode(OREG, off, SPREG, t); + DLIST_INSERT_BEFORE(ip, nip, qelem); + } + return l|r; + + case UTYPE: + l = storefloat(ip, p->n_left); + if (callop(p->n_op)) + l = 1; + return l; + default: + return 0; + } +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + p2calls = 0; + p2temps = 0; + p2maxstacksize = 0; + + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + walkf(ip->ip_node, fixcalls, 0); + storefloat(ip, ip->ip_node); + } + + if (p2maxstacksize < NARGREGS*SZINT/SZCHAR) + p2maxstacksize = NARGREGS*SZINT/SZCHAR; + + p2framesize = ARGINIT/SZCHAR; /* stack ptr / return addr */ + p2framesize += 8; /* for R31 and R30 */ + p2framesize += p2maxautooff; /* autos */ + p2framesize += p2temps; /* TEMPs that aren't autos */ + if (p2calls != 0) + p2framesize += p2maxstacksize; /* arguments to functions */ + p2framesize += (ALSTACK/SZCHAR - 1); /* round to 16-byte boundary */ + p2framesize &= ~(ALSTACK/SZCHAR - 1); + +#if 0 + printf("!!! MYREADER\n"); + printf("!!! p2maxautooff = %d\n", p2maxautooff); + printf("!!! p2autooff = %d\n", p2autooff); + printf("!!! p2temps = %d\n", p2temps); + printf("!!! p2calls = %d\n", p2calls); + printf("!!! p2maxstacksize = %d\n", p2maxstacksize); +#endif + + if (x2debug) + printip(ipole); +} + +/* + * Remove some PCONVs after OREGs are created. + */ +static void +pconv2(NODE *p, void *arg) +{ + NODE *q; + + if (p->n_op == PLUS) { + if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { + if (p->n_right->n_op != ICON) + return; + if (p->n_left->n_op != PCONV) + return; + if (p->n_left->n_left->n_op != OREG) + return; + q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + /* + * This will be converted to another OREG later. + */ + } + } +} + +void +mycanon(NODE *p) +{ + walkf(p, pconv2, 0); +} + +void +myoptim(struct interpass *ip) +{ +#ifdef PCC_DEBUG + if (x2debug) { + printf("myoptim\n"); + } +#endif +} + +/* + * Move data between registers. While basic registers aren't a problem, + * we have to handle the special case of overlapping composite registers. + * It might just be easier to modify the register allocator so that + * moves between overlapping registers isn't possible. + */ +void +rmove(int s, int d, TWORD t) +{ + switch (t) { + case LDOUBLE: + case DOUBLE: + if (features(FEATURE_HARDFLOAT)) { + printf("\tfmr %s,%s" COM "rmove\n", + rnames[d], rnames[s]); + break; + } + /* FALL-THROUGH */ + case LONGLONG: + case ULONGLONG: + if (s == d+1) { + /* dh = sl, copy low word first */ + printf("\tmr "); + reg64name(d, LOWREG); + printf(","); + reg64name(s, LOWREG); + printf("\n"); + printf("\tmr "); + reg64name(d, HIREG); + printf(","); + reg64name(s, HIREG); + printf("\n"); + } else { + /* copy high word first */ + printf("\tmr "); + reg64name(d, HIREG); + printf(","); + reg64name(s, HIREG); + printf("\n"); + printf("\tmr "); + reg64name(d, LOWREG); + printf(","); + reg64name(s, LOWREG); + printf("\n"); + } + break; + case FLOAT: + if (features(FEATURE_HARDFLOAT)) { + printf("\tfmr %s,%s" COM "rmove\n", + rnames[d], rnames[s]); + break; + } + /* FALL-THROUGH */ + default: + printf("\tmr %s,%s" COM "rmove\n", rnames[d], rnames[s]); + } +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + * + * On PowerPC, we have: + * + * 32 32-bit registers (2 reserved) + * 16 64-bit pseudo registers + * 32 floating-point registers + */ +int +COLORMAP(int c, int *r) +{ + int num = 0; + + switch (c) { + case CLASSA: + num += r[CLASSA]; + num += 2*r[CLASSB]; + return num < 30; + case CLASSB: + num += 2*r[CLASSB]; + num += r[CLASSA]; + return num < 16; + case CLASSC: + return num < 32; + case CLASSD: + return r[CLASSD] < DREGCNT; + } + return 0; /* XXX gcc */ +} + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + if (t == LONGLONG || t == ULONGLONG) + return CLASSB; + if (t == FLOAT || t == DOUBLE || t == LDOUBLE) { + if (features(FEATURE_HARDFLOAT)) + return CLASSC; + if (t == FLOAT) + return CLASSA; + else + return CLASSB; + } + return CLASSA; +} + +int +retreg(int t) +{ + int c = gclass(t); + if (c == CLASSB) + return R3R4; + else if (c == CLASSC) + return F1; + return R3; +} + +/* + * Calculate argument sizes. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + +#ifdef PCC_DEBUG + if (x2debug) + printf("lastcall:\n"); +#endif + + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + + for (p = p->n_right; p->n_op == CM; p = p->n_left) + size += argsize(p->n_right); + size += argsize(p); + op->n_qual = size; /* XXX */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + int o = p->n_op; + + switch (shape) { + case SFUNCALL: + if (o == STCALL || o == USTCALL) + return SRREG; + break; + case SPCON: + if (o == ICON && p->n_name[0] == 0 && (p->n_lval & ~0x7fff) == 0) + return SRDIR; + break; + } + return SRNOPE; +} + +static int fset = FEATURE_BIGENDIAN | FEATURE_HARDFLOAT; + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ + if (strcasecmp(str, "big-endian") == 0) { + fset |= FEATURE_BIGENDIAN; + } else if (strcasecmp(str, "little-endian") == 0) { + fset &= ~FEATURE_BIGENDIAN; + } else if (strcasecmp(str, "soft-float") == 0) { + fset &= ~FEATURE_HARDFLOAT; + } else if (strcasecmp(str, "hard-float") == 0) { + fset |= FEATURE_HARDFLOAT; + } else { + fprintf(stderr, "unknown m option '%s'\n", str); + exit(1); + } +} + +int +features(int mask) +{ + return ((fset & mask) == mask); +} +/* + * Do something target-dependent for xasm arguments. + * Supposed to find target-specific constraints and rewrite them. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + return 0; +} diff --git a/lang/pcc/pcc/arch/powerpc/macdefs.h b/lang/pcc/pcc/arch/powerpc/macdefs.h new file mode 100644 index 000000000..72cc2b648 --- /dev/null +++ b/lang/pcc/pcc/arch/powerpc/macdefs.h @@ -0,0 +1,407 @@ +/* $Id: macdefs.h,v 1.18 2016/03/05 15:53:04 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Machine-dependent defines for both passes. + */ + +/* + * Convert (multi-)character constant to integer. + */ +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +/* + * Storage space requirements + */ +#define SZCHAR 8 +#define SZBOOL 32 +#define SZINT 32 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#ifdef ELFABI +#define SZLDOUBLE 96 +#else +#define SZLDOUBLE 128 +#endif +#define SZLONG 32 +#define SZSHORT 16 +#define SZLONGLONG 64 +#define SZPOINT(t) 32 + +/* + * Alignment constraints + */ +#define ALCHAR 8 +#define ALBOOL 32 +#define ALINT 32 +#define ALFLOAT 32 +#define ALDOUBLE 32 +#ifdef ELFABI +#define ALLDOUBLE 32 +#else +#define ALLDOUBLE 128 +#endif +#define ALLONG 32 +#ifdef ELFABI +#define ALLONGLONG 64 +#else +#define ALLONGLONG 32 +#endif +#define ALSHORT 16 +#define ALPOINT 32 +#define ALSTRUCT 32 +#define ALSTACK (16*SZCHAR) + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT -1 +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffff +#define MIN_LONG MIN_INT +#define MAX_LONG MAX_INT +#define MAX_ULONG MAX_UNSIGNED +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +#define CHAR_UNSIGNED +#define BOOL_TYPE INT /* what used to store _Bool */ + +/* + * Use large-enough types. + */ +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" /* format for printing constants */ +#if defined(ELFABI) +#define LABFMT ".L%d" /* format for printing labels */ +#define REGPREFIX "%" /* format for printing registers */ +#elif defined(MACHOABI) +#define LABFMT "L%d" /* format for printing labels */ +#define REGPREFIX +#else +#error undefined ABI +#endif +#define STABLBL "LL%d" /* format for stab (debugging) labels */ + +#ifdef MACHOABI +#define STAB_LINE_ABSOLUTE /* S_LINE fields use absolute addresses */ +#endif + +#undef FIELDOPS /* no bit-field instructions */ +#define TARGET_ENDIAN TARGET_BE +#define MYINSTRING +#define MYALIGN + +/* Definitions mostly used in pass2 */ + +#define BYTEOFF(x) ((x)&03) + +#define szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \ + DEUNSIGN(t) == LONGLONG) ? 2 : 1) + +/* + * The PPC register definition are taken from apple docs. + * + * The classes used are: + * A - general registers + * B - 64-bit register pairs + * C - floating-point registers + */ + +#define R0 0 /* scratch register */ +#define R1 1 /* stack base pointer */ +#define R2 2 +#define R3 3 /* return register / argument 0 */ +#define R4 4 /* return register (for longlong) / argument 1 */ +#define R5 5 /* scratch register / argument 2 */ +#define R6 6 /* scratch register / argument 3 */ +#define R7 7 /* scratch register / argument 4 */ +#define R8 8 /* scratch register / argument 5 */ +#define R9 9 /* scratch register / argument 6 */ +#define R10 10 /* scratch register / argument 7 */ +#define R11 11 /* scratch register */ +#define R12 12 /* scratch register */ +#define R13 13 +#define R14 14 +#define R15 15 +#define R16 16 +#define R17 17 +#define R18 18 +#define R19 19 +#define R20 20 +#define R21 21 +#define R22 22 +#define R23 23 +#define R24 24 +#define R25 25 +#define R26 26 +#define R27 27 +#define R28 28 +#define R29 29 +#define R30 30 +#define R31 31 + +#define R3R4 32 +#define R4R5 33 +#define R5R6 34 +#define R6R7 35 +#define R7R8 36 +#define R8R9 37 +#define R9R10 38 +#define R14R15 39 +#define R16R17 40 +#define R18R19 41 +#define R20R21 42 +#define R22R23 43 +#define R24R25 44 +#define R26R27 45 +#define R28R29 46 +#define R30R31 47 + +#define F0 48 /* scratch register */ +#define F1 49 /* return value 0 / argument 0 */ +#define F2 50 /* return value 1 / argument 1 */ +#define F3 51 /* return value 2 / argument 2 */ +#define F4 52 /* return value 3 / argument 3 */ +#define F5 53 /* argument 4 */ +#define F6 54 /* argument 5 */ +#define F7 55 /* argument 6 */ +#define F8 56 /* argument 7 */ +#define F9 57 /* argument 8 */ +#define F10 58 /* argument 9 */ +#define F11 59 /* argument 10 */ +#define F12 60 /* argument 11 */ +#define F13 61 /* argument 12 */ +#define F14 62 +#define F15 63 +#define F16 64 +#define F17 65 +#define F18 66 +#define F19 67 +#define F20 68 +#define F21 69 +#define F22 70 +#define F23 71 +#define F24 72 +#define F25 73 +#define F26 74 +#define F27 75 +#define F28 76 +#define F29 77 +#define F30 78 +#define F31 79 + +#define NUMCLASS 3 +#define MAXREGS 64 /* XXX cannot have more than 64 */ + +#define RSTATUS \ + 0, /* R0 */ \ + 0, /* R1 */ \ + SAREG|TEMPREG, /* R2 */ \ + SAREG|TEMPREG, /* R3 */ \ + SAREG|TEMPREG, /* R4 */ \ + SAREG|TEMPREG, /* R5 */ \ + SAREG|TEMPREG, /* R6 */ \ + SAREG|TEMPREG, /* R7 */ \ + SAREG|TEMPREG, /* R8 */ \ + SAREG|TEMPREG, /* R9 */ \ + SAREG|TEMPREG, /* R10 */ \ + SAREG|TEMPREG, /* R11 */ \ + SAREG|TEMPREG, /* R12 */ \ + SAREG, /* R13 */ \ + SAREG, /* R14 */ \ + SAREG, /* R15 */ \ + SAREG, /* R16 */ \ + SAREG, /* R17 */ \ + SAREG, /* R18 */ \ + SAREG, /* R19 */ \ + SAREG, /* R20 */ \ + SAREG, /* R21 */ \ + SAREG, /* R22 */ \ + SAREG, /* R23 */ \ + SAREG, /* R24 */ \ + SAREG, /* R25 */ \ + SAREG, /* R26 */ \ + SAREG, /* R27 */ \ + SAREG, /* R28 */ \ + SAREG, /* R29 */ \ + SAREG, /* R30 */ \ + SAREG, /* R31 */ \ + \ + SBREG|TEMPREG, /* R3R4 */ \ + SBREG|TEMPREG, /* R4R5 */ \ + SBREG|TEMPREG, /* R5R6 */ \ + SBREG|TEMPREG, /* R6R7 */ \ + SBREG|TEMPREG, /* R7R8 */ \ + SBREG|TEMPREG, /* R8R9 */ \ + SBREG|TEMPREG, /* R9R10 */ \ + \ + SBREG, /* R14R15 */ \ + SBREG, /* R16R17 */ \ + SBREG, /* R18R19 */ \ + SBREG, /* R20R21 */ \ + SBREG, /* R22R23 */ \ + SBREG, /* R24R25 */ \ + SBREG, /* R26R2k */ \ + SBREG, /* R28R29 */ \ + SBREG, /* R30R31 */ \ + \ + SCREG|TEMPREG, /* F0 */ \ + SCREG|TEMPREG, /* F1 */ \ + SCREG|TEMPREG, /* F2 */ \ + SCREG|TEMPREG, /* F3 */ \ + SCREG|TEMPREG, /* F4 */ \ + SCREG|TEMPREG, /* F5 */ \ + SCREG|TEMPREG, /* F6 */ \ + SCREG|TEMPREG, /* F7 */ \ + SCREG|TEMPREG, /* F8 */ \ + SCREG|TEMPREG, /* F9 */ \ + SCREG|TEMPREG, /* F10 */ \ + SCREG|TEMPREG, /* F11 */ \ + SCREG|TEMPREG, /* F12 */ \ + SCREG|TEMPREG, /* F13 */ \ + SCREG, /* F14 */ \ + SCREG, /* F15 */ \ + +#define ROVERLAP \ + { -1 }, { -1 }, { -1 }, \ + { R3R4, -1 }, { R3R4, R4R5, -1 }, \ + { R4R5, R5R6, -1 }, { R5R6, R6R7, -1 }, \ + { R6R7, R7R8, -1 }, { R7R8, R8R9, -1 }, \ + { R8R9, R9R10, -1 }, { R9R10, -1 }, \ + { -1 }, { -1 }, { -1 }, \ + { R14R15, -1 }, { R14R15, -1 }, \ + { R16R17, -1 }, { R16R17, -1 }, \ + { R18R19, -1 }, { R18R19, -1 }, \ + { R20R21, -1 }, { R20R21, -1 }, \ + { R22R23, -1 }, { R22R23, -1 }, \ + { R24R25, -1 }, { R24R25, -1 }, \ + { R26R27, -1 }, { R26R27, -1 }, \ + { R28R29, -1 }, { R28R29, -1 }, \ + { R30R31, -1 }, { R30R31, -1 }, \ + \ + { R3, R4, R4R5, -1 }, { R4, R5, R3R4, R5R6, -1 }, \ + { R5, R6, R4R5, R6R7, -1 }, { R6, R7, R5R6, R7R8, -1 }, \ + { R7, R8, R6R7, R8R9, -1 }, { R8, R9, R7R8, R8R9, -1 }, \ + { R9, R10, R8R9, -1 }, \ + { R14, R15, -1 }, { R16, R17, -1 }, \ + { R18, R19, -1 }, { R20, R21, -1 }, \ + { R22, R23, -1 }, { R24, R25, -1 }, \ + { R26, R27, -1 }, { R28, R29, -1 }, \ + { R30, R31, -1 }, \ + \ + { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, \ + +/* + * According to the ABI documents, there isn't really a frame pointer; + * all references to data on the stack (autos and parameters) are + * indexed relative to the stack pointer. However, pcc isn't really + * capable of running in this manner, and expects a frame pointer. + */ +#define SPREG R1 /* stack pointer */ +#define FPREG R30 /* frame pointer */ +#define GOTREG R31 /* global offset table (PIC) */ + +#ifdef FPREG +#define ARGINIT (24*8) /* # bits above fp where arguments start */ +#define AUTOINIT (8*8) /* # bits above fp where automatics start */ +#define BACKAUTO /* stack grows negatively for automatics */ +#define BACKTEMP /* stack grows negatively for temporaries */ +#else +#define ARGINIT (24*8) /* # bits above fp where arguments start */ +#define AUTOINIT (56*8) /* # bits above fp where automatics start */ +#endif + +/* Return a register class based on the type of the node */ +#define PCLASS(p) (1 << gclass((p)->n_type)) + +#define GCLASS(x) ((x) < 32 ? CLASSA : ((x) < 48 ? CLASSB : CLASSC)) +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define RETREG(x) retreg(x) + +int COLORMAP(int c, int *r); +int retreg(int ty); + +#define SHSTR (MAXSPECIAL+1) /* short struct */ +#define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */ +#define SPCON (MAXSPECIAL+3) /* positive constant */ + +int features(int f); +#define FEATURE_BIGENDIAN 0x00010000 +#define FEATURE_PIC 0x00020000 +#define FEATURE_HARDFLOAT 0x00040000 + +struct stub { + struct { struct stub *q_forw, *q_back; } link; + char *name; +}; +extern struct stub stublist; +extern struct stub nlplist; +void addstub(struct stub *list, char *name); + +#define TARGET_STDARGS +#define TARGET_BUILTINS \ + { "__builtin_stdarg_start", powerpc_builtin_stdarg_start }, \ + { "__builtin_va_arg", powerpc_builtin_va_arg }, \ + { "__builtin_va_end", powerpc_builtin_va_end }, \ + { "__builtin_va_copy", powerpc_builtin_va_copy }, \ + { "__builtin_frame_address", powerpc_builtin_frame_address }, \ + { "__builtin_return_address", powerpc_builtin_return_address }, + +#define NODE struct node +struct node; +NODE *powerpc_builtin_stdarg_start(NODE *f, NODE *a, unsigned int); +NODE *powerpc_builtin_va_arg(NODE *f, NODE *a, unsigned int); +NODE *powerpc_builtin_va_end(NODE *f, NODE *a, unsigned int); +NODE *powerpc_builtin_va_copy(NODE *f, NODE *a, unsigned int); +NODE *powerpc_builtin_frame_address(NODE *f, NODE *a, unsigned int); +NODE *powerpc_builtin_return_address(NODE *f, NODE *a, unsigned int); +#undef NODE + +#define NARGREGS 8 + +#ifdef ELFABI +#define COM " # " +#else +#define COM " ; " +#endif diff --git a/lang/pcc/pcc/arch/powerpc/order.c b/lang/pcc/pcc/arch/powerpc/order.c new file mode 100644 index 000000000..61782cdf6 --- /dev/null +++ b/lang/pcc/pcc/arch/powerpc/order.c @@ -0,0 +1,408 @@ +/* $Id: order.c,v 1.8 2009/01/07 11:44:03 gmcgarry Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 + +# include "pass2.h" + +#include + +int canaddr(NODE *); + +/* + * Check size of offset in OREG. Called by oregok() to see if an + * OREG can be generated. + * + * returns 0 if it can, 1 otherwise. + */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ +#if 0 + if (off >= 32767 || off <= -32768) + printf("; notoff %lld TOO BIG!\n", off); +#endif + if (cp && cp[0]) return 1; + return (off >= 32768 || off <= -32769); +} + +/* + * Generate instructions for an OREG. + * Called by swmatch(). + */ +void +offstar(NODE *p, int shape) +{ + NODE *r; + + if (x2debug) + printf("offstar(%p)\n", p); + + if (isreg(p)) + return; /* Is already OREG */ + + r = p->n_right; + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( r->n_op == ICON ){ + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + } + (void)geninsn(p, INAREG); +} + +/* + * Unable to convert to OREG (notoff() returned failure). Output + * suitable instructions to replace OREG. + */ +void +myormake(NODE *q) +{ + NODE *p; + + if (x2debug) + printf("myormake(%p)\n", q); + + p = q->n_left; + + /* + * This handles failed OREGs conversions, due to the offset + * being too large for an OREG. + */ + if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + if (isreg(p->n_right) == 0) + (void)geninsn(p->n_right, INAREG); + (void)geninsn(p, INAREG); + } else if (p->n_op == REG) { + q->n_op = OREG; + q->n_lval = p->n_lval; + q->n_rval = p->n_rval; + tfree(p); + } +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Turns currently anything into OREG on x86 */ + if (shape & SOREG) + return SROREG; + return SRNOPE; +} + +/* + * Rewrite operations on binary operators (like +, -, etc...). + * Called as a result of table lookup. + */ +int +setbin(NODE *p) +{ + + if (x2debug) + printf("setbin(%p)\n", p); + return 0; + +} + +/* setup for assignment operator */ +int +setasg(NODE *p, int cookie) +{ + if (x2debug) + printf("setasg(%p)\n", p); + return(0); +} + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + if (x2debug) + printf("nspecial: op=%d, visit=0x%x: %s", q->op, q->visit, q->cstring); + + switch (q->op) { + + /* soft-float stuff */ + case RS: + case LS: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R3R4 }, + { NRIGHT, R5 }, + { NRES, R3R4 }, + { 0 }, + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R3 }, + { NRIGHT, R4 }, + { NRES, R3 }, + { 0 }, + }; + return s; + } + + cerror("nspecial LS/RS"); + break; + + case UMINUS: + case SCONV: + if (q->lshape == SBREG && q->rshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R3R4 }, + { NRES, R3 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG && q->rshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R3 }, + { NRES, R3R4 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG && q->rshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R3 }, + { NRES, R3 }, + { 0 } + }; + return s; + } else if (q->lshape == SBREG && q->rshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R3R4 }, + { NRES, R3R4 }, + { 0 } + }; + return s; + } else if (q->lshape == SCREG && q->rshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, F1 }, + { NEVER, F0 }, /* stomped on */ + { NRES, R3R4 }, + { 0 } + }; + return s; + } else if (q->lshape == SBREG && q->rshape == SCREG) { + static struct rspecial s[] = { + { NLEFT, R3R4 }, + { NEVER, F0 }, /* stomped on */ + { NRES, F1 }, + { 0 } + }; + return s; + } else { + static struct rspecial s[] = { + { NOLEFT, R0 }, + { 0 } }; + return s; + } + + break; + + case OPLOG: + if (q->lshape == SBREG) { + static struct rspecial s[] = { + { NLEFT, R3R4 }, + { NRIGHT, R5R6 }, + { NRES, R3 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NLEFT, R3 }, + { NRIGHT, R4 }, + { NRES, R3 }, + { 0 } + }; + return s; + } + + cerror("nspecial oplog"); + break; + + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + if (q->lshape == SBREG && + (q->ltype & (TDOUBLE|TLDOUBLE|TLONGLONG|TULONGLONG))) { + static struct rspecial s[] = { + { NLEFT, R3R4 }, + { NRIGHT, R5R6 }, + { NRES, R3R4 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG && q->ltype & TFLOAT) { + static struct rspecial s[] = { + { NLEFT, R3 }, + { NRIGHT, R4 }, + { NRES, R3 }, + { 0 } + }; + return s; + } else if (q->lshape == SAREG) { + static struct rspecial s[] = { + { NOLEFT, R0 }, + { 0 } }; + return s; + } + + cerror("nspecial mul"); + break; + + case STASG: + { + static struct rspecial s[] = { + { NEVER, R3 }, + { NRIGHT, R4 }, + { NEVER, R5 }, + { 0 } }; + return s; + } + break; + + case OPLTYPE: + { + if (q->visit & SAREG) { + static struct rspecial s[] = { + { NEVER, R0 }, + { 0 } }; + return s; + } + } + break; + + case ASSIGN: + if (q->lshape & SNAME) { + static struct rspecial s[] = { + { NEVER, R0 }, + { 0 } }; + return s; + } else if (q->rshape & SNAME) { + static struct rspecial s[] = { + { NOLEFT, R0 }, + { 0 } }; + return s; + } else if (q->lshape & SOREG) { + static struct rspecial s[] = { + { NOLEFT, R0 }, + { 0 } }; + return s; + } else if (q->rshape & SOREG) { + static struct rspecial s[] = { + { NORIGHT, R0 }, + { 0 } }; + return s; + } + /* fallthough */ + + case UMUL: + case AND: + case OR: + case ER: + { + static struct rspecial s[] = { + { NOLEFT, R0 }, + { 0 } }; + return s; + } + + default: + break; + } + + comperr("nspecial entry %d: %s", q - table, q->cstring); + return 0; /* XXX gcc */ +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; /* nothing differs on x86 */ +} + +/* + * Set registers "live" at function calls (like arguments in registers). + * This is for liveness analysis of registers. + */ +int * +livecall(NODE *p) +{ + static int r[] = { R10, R9, R8, R7, R6, R5, R4, R3, R30, R31, -1 }; + int num = 1; + + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return &r[8-0]; + + for (p = p->n_right; p->n_op == CM; p = p->n_left) + num += szty(p->n_right->n_type); + num += szty(p->n_right->n_type); + + num = (num > 8 ? 8 : num); + + return &r[8 - num]; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + if ((op->visit & FEATURE_PIC) != 0) + return (kflag != 0); + return features(op->visit & 0xffff0000); +} diff --git a/lang/pcc/pcc/arch/powerpc/table.c b/lang/pcc/pcc/arch/powerpc/table.c new file mode 100644 index 000000000..5f81d776a --- /dev/null +++ b/lang/pcc/pcc/arch/powerpc/table.c @@ -0,0 +1,1806 @@ +/* $Id: table.c,v 1.18 2010/11/26 17:06:31 ragge Exp $ */ +/*- + * Copyright (c) 2007 Gregory McGarry + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * A template has five logical sections: + * + * 1) subtree (operator); goal to achieve (cookie) + * 2) left node descendent of operator (node class; type) + * 3) right node descendent of operator (node class; type) + * 4) resource requirements (number of scratch registers); + * subtree rewriting rule + * 5) emitted instructions + */ + +#include "pass2.h" + +#define TUWORD TUNSIGNED|TULONG +#define TSWORD TINT|TLONG +#define TWORD TUWORD|TSWORD + +#if defined(ELFABI) +#define HA16(x) # x "@ha" +#define LO16(x) # x "@l" +#elif defined(MACHOABI) +#define HA16(x) "ha16(" # x ")" +#define LO16(x) "lo16(" # x ")" +#else +#error undefined ABI +#endif + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are not necessary */ +{ PCONV, INAREG, + SAREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + 0, RLEFT, + COM "pointer conversion\n", }, + +/* + * Conversions of integral types + */ + +{ SCONV, INAREG, + SAREG, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + 0, RLEFT, + COM "convert between (u)char and (u)char\n", }, + +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RLEFT, + COM "convert between (u)short and (u)short\n", }, + +{ SCONV, INAREG, + SAREG, TPOINT|TWORD, + SAREG, TWORD, + 0, RLEFT, + COM "convert a pointer/word to an int\n", }, + +{ SCONV, INAREG, + SAREG, TPOINT, + SAREG, TPOINT, + 0, RLEFT, + COM "convert pointers\n", }, + +{ SCONV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RLEFT, + COM "convert (u)longlong to (u)longlong\n", }, + +{ SCONV, INAREG, + SAREG, TCHAR, + SAREG, TSHORT|TSWORD, + NASL|NAREG, RESC1, + " extsb A1,AL" COM "convert char to short/int\n", }, + +{ SCONV, INAREG, + SAREG, TUCHAR, + SAREG, TSHORT|TSWORD, + 0, RLEFT, + COM "convert uchar to short/int\n", }, + +{ SCONV, INAREG, + SAREG, TUCHAR, + SAREG, TUSHORT|TUWORD, + 0, RLEFT, + COM "convert uchar to ushort/unsigned\n", }, + +/* XXX is this necessary? */ +{ SCONV, INAREG, + SAREG, TCHAR, + SAREG, TUSHORT|TUWORD, + NSPECIAL|NAREG|NASL, RESC1, + " extsb A1,AL" COM "convert char to ushort/unsigned\n", }, + +{ SCONV, INBREG | FEATURE_BIGENDIAN, + SAREG, TUCHAR|TUSHORT|TUNSIGNED, + SBREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " mr U1,AL" COM "convert uchar/ushort/uint to (u)longlong\n" + " li A1,0\n", }, + +{ SCONV, INBREG, + SAREG, TUCHAR|TUSHORT|TUNSIGNED, + SBREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " mr A1,AL" COM "convert uchar/ushort/uint to (u)longlong\n" + " li U1,0\n", }, + +{ SCONV, INBREG | FEATURE_BIGENDIAN, + SAREG, TCHAR|TSHORT|TSWORD, + SBREG, TULONGLONG|TLONGLONG, + NBREG, RESC1, + " mr U1,AL" COM "convert char/short/int to ulonglong\n" + " srawi A1,AL,31\n", }, + +{ SCONV, INBREG, + SAREG, TCHAR|TSHORT|TSWORD, + SBREG, TULONGLONG|TLONGLONG, + NBREG, RESC1, + " mr A1,AL" COM "convert char/short/int to ulonglong\n" + " srawi U1,AL,31\n", }, + +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT, + SAREG, TCHAR|TUCHAR, + NSPECIAL|NAREG|NASL, RESC1, + " andi. A1,AL,255" COM "convert (u)short to (u)char\n", }, + +/* XXX is this really necessary? */ +{ SCONV, INAREG, + SAREG, TSHORT, + SAREG, TWORD, + NAREG|NASL, RESC1, + " extsh A1,AL" COM "convert short to int\n", }, + +{ SCONV, INAREG, + SAREG, TUSHORT, + SAREG, TWORD, + NSPECIAL|NAREG|NASL, RESC1, + COM "convert ushort to word\n", }, + +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1, + " andi. A1,AL,255" COM "convert (u)int to (u)char\n", }, + +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TSHORT|TUSHORT, + NAREG|NASL|NSPECIAL, RESC1, + " andi. A1,AL,65535" COM "convert (u)int to (u)short\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TCHAR|TUCHAR, + NAREG|NSPECIAL, RESC1, + " andi. A1,AL,255" COM "(u)longlong to (u)char\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TSHORT|TUSHORT, + NAREG|NSPECIAL, RESC1, + " andi. A1,AL,65535" COM "(u)longlong to (u)short\n", }, + +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TWORD, + NAREG, RESC1, + " mr A1,AL" COM "convert (u)longlong to (u)int/long\n", }, + +/* conversions on load from memory */ + +{ SCONV, INAREG, + SOREG, TCHAR, + SAREG, TWORD, + NASL|NAREG|NSPECIAL, RESC1, + " lbz A1,AL" COM "convert char to int/long\n" + " extsb A1,A1\n", }, + +{ SCONV, INAREG, + SOREG, TUCHAR, + SAREG, TWORD, + NASL|NAREG|NSPECIAL, RESC1, + " lbz A1,AL" COM "convert uchar to int/long\n", }, + +{ SCONV, INAREG, + SOREG, TSHORT, + SAREG, TWORD, + NASL|NAREG|NSPECIAL, RESC1, + " lha A1,AL" COM "convert short to int/long\n", }, + +{ SCONV, INAREG, + SOREG, TUSHORT, + SAREG, TWORD, + NASL|NAREG|NSPECIAL, RESC1, + " lhz A1,AL" COM "convert ushort to int/long\n", }, + +{ SCONV, INAREG, + SOREG, TLONGLONG|TULONGLONG, + SAREG, TCHAR|TUCHAR, + NAREG|NSPECIAL, RESC1, + " lwz A1,AL" COM "(u)longlong to (u)char\n" + " andi. A1,A1,255\n", }, + +{ SCONV, INAREG, + SOREG, TLONGLONG|TULONGLONG, + SAREG, TSHORT|TUSHORT, + NAREG|NSPECIAL, RESC1, + " lwz A1,AL" COM "(u)longlong to (u)short\n" + " andi. A1,A1,65535\n", }, + +{ SCONV, INAREG, + SOREG, TLONGLONG|TULONGLONG, + SAREG, TWORD, + NAREG|NSPECIAL, RESC1, + " lwz A1,AL" COM "(u)longlong to (u)int\n", }, + +/* + * floating-point conversions + * + * There doesn't appear to be an instruction to move values between + * the floating-point registers and the general-purpose registers. + * So values are bounced into memory... + */ + +{ SCONV, INCREG | FEATURE_HARDFLOAT, + SCREG, TFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + COM "convert float to (l)double\n", }, + +/* soft-float */ +{ SCONV, INBREG, + SAREG, TFLOAT, + SBREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_HARDFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TFLOAT, + NCREG, RESC1, + " frsp A1,AL" COM "convert (l)double to float\n", }, + +/* soft-float */ +{ SCONV, INAREG, + SBREG, TDOUBLE|TLDOUBLE, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_HARDFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + COM "convert (l)double to (l)double\n", }, + +/* soft-float */ +{ SCONV, INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + 0, RLEFT, + COM "convert (l)double to (l)double (soft-float)\n", }, + +{ SCONV, INCREG | FEATURE_HARDFLOAT, + SAREG, TWORD, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + 2*NCREG|NAREG, RESC3, + "ZC", }, + +/* soft-float */ +{ SCONV, INAREG, + SAREG, TWORD, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +/* soft-float */ +{ SCONV, INBREG, + SAREG, TWORD, + SBREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INAREG | FEATURE_HARDFLOAT, + SOREG, TFLOAT|TDOUBLE|TLDOUBLE, + SAREG, TWORD, + 2*NCREG|NAREG, RESC1, + "ZC", }, + +/* soft-float */ +{ SCONV, INAREG, + SAREG, TFLOAT, + SAREG, TWORD, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +/* soft-float */ +{ SCONV, INAREG, + SBREG, TDOUBLE|TLDOUBLE, + SAREG, TWORD, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ SCONV, INCREG | FEATURE_HARDFLOAT, + SBREG, TLONGLONG|TULONGLONG, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + NSPECIAL|NCREG, RESC1, + "ZF", }, + +/* soft-float */ +{ SCONV, INAREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +/* soft-float */ +{ SCONV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ SCONV, INBREG | FEATURE_HARDFLOAT, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +/* soft-float */ +{ SCONV, INBREG, + SAREG, TFLOAT, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +/* soft-float */ +{ SCONV, INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +/* + * Subroutine calls. + */ + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " bl CL" COM "call (args, no result) to scon\n", }, + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " bl CL" COM "call (no args, no result) to scon\n", }, + +{ CALL, INAREG, + SCON, TANY, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result) to scon\n", }, + +{ UCALL, INAREG, + SCON, TANY, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result) to scon\n", }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result) to scon\n", }, + +{ UCALL, INBREG, + SCON, TANY, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result) to scon\n", }, + +{ CALL, INCREG | FEATURE_HARDFLOAT, + SCON, TANY, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + NCREG|NCSL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result) to scon\n", }, + +{ UCALL, INCREG | FEATURE_HARDFLOAT, + SCON, TANY, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + NCREG|NCSL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result) to scon\n", }, + +{ CALL, INAREG, + SCON, TANY, + SAREG, TFLOAT, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result) to scon\n", }, + +{ UCALL, INAREG, + SCON, TANY, + SAREG, TFLOAT, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result) to scon\n", }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, TDOUBLE|TLDOUBLE, + NBREG|NBSL, RESC1, /* should be 0 */ + " bl CL" COM "call (args, result) to scon\n", }, + +{ UCALL, INBREG, + SCON, TANY, + SBREG, TDOUBLE|TLDOUBLE, + NBREG|NBSL, RESC1, /* should be 0 */ + " bl CL" COM "call (no args, result) to scon\n", }, + + + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " mtctr AL" COM "call (args, no result) to reg\n" + " bctrl\n", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " mtctr AL" COM "call (no args, no result) to reg\n" + " bctrl\n", }, + +{ CALL, INAREG, + SAREG, TANY, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG, RESC1, + " mtctr AL" COM "call (args, result) to reg\n" + " bctrl\n", }, + +{ UCALL, INAREG, + SAREG, TANY, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG, RESC1, + " mtctr AL" COM "call (no args, result) to reg\n" + " bctrl\n", }, + +/* struct return */ +{ USTCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " bl CL\n", }, + +{ USTCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL\n", }, + +{ USTCALL, INAREG, + SAREG, TANY, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG, RESC1, + " mtctr AL" + " bctrl\n", }, + +{ STCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " bl CL\n", }, + +{ STCALL, INAREG, + SCON, TANY, + SANY, TANY, + NAREG|NASL, RESC1, /* should be 0 */ + " bl CL\n", }, + +{ STCALL, INAREG, + SAREG, TANY, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " mtctr AL" + " bctrl\n", }, + +/* + * The next rules handle all binop-style operators. + */ + +/* XXX AL cannot be R0 */ +{ PLUS, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TANY, + NAREG|NASL|NSPECIAL, RESC1, + " addi A1,AL,AR" COM "addition of constant\n", }, + +/* XXX AL cannot be R0 */ +{ PLUS, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TANY, + NAREG|NASL|NSPECIAL, RESC1|RESCC, + " addic. A1,AL,AR" COM "addition of constant\n", }, + +{ PLUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SSCON, TANY, + NBREG|NBSL, RESC1, + " addic A1,AL,AR" COM "64-bit addition of constant\n" + " addze U1,UL\n", }, + +{ PLUS, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1, + " add A1,AL,AR\n", }, + +{ PLUS, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1|RESCC, + " add. A1,AL,AR\n", }, + +{ PLUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " addc A1,AL,AR" COM "64-bit add\n" + " adde U1,UL,UR\n", }, + +{ PLUS, INCREG | FEATURE_HARDFLOAT, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " fadds A1,AL,AR" COM "float add\n", }, + +{ PLUS, INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ PLUS, INCREG | FEATURE_HARDFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG|NCSL, RESC1, + " fadd A1,AL,AR" COM "(l)double add\n", }, + +/* soft-float */ +{ PLUS, INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NBREG|NBSL, RESC1, + "ZF", }, + +{ MINUS, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TANY, + NAREG|NASL|NSPECIAL, RESC1, + " addi A1,AL,-AR\n", }, + +{ MINUS, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TANY, + NAREG|NASL|NSPECIAL, RESC1|RESCC, + " addic. A1,AL,-AR\n", }, + +{ MINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SSCON, TANY, + NBREG|NBSL, RESC1, + " addic A1,AL,-AR\n" + " addme U1,UL\n", }, + +{ MINUS, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1, + " subf A1,AR,AL\n", }, + +{ MINUS, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1|RESCC, + " subf. A1,AR,AL\n", }, + +{ MINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " subfc A1,AR,AL" COM "64-bit subtraction\n" + " subfe U1,UR,UL\n", }, + +{ MINUS, INCREG | FEATURE_HARDFLOAT, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG, RESC1, + " fsubs A1,AL,AR\n", }, + +{ MINUS, INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ MINUS, INCREG | FEATURE_HARDFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG|NCSL, RESC1, + " fsub A1,AL,AR" COM "(l)double sub\n", }, + +/* soft-float */ +{ MINUS, INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NBREG|NBSL, RESC1, + "ZF", }, + + +/* + * The next rules handle all shift operators. + */ + +{ LS, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " slw A1,AL,AR" COM "left shift\n", }, + +{ LS, INAREG|FORCC, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " slw. A1,AL,AR" COM "left shift\n", }, + +{ LS, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SCON, TANY, + NAREG|NASL, RESC1, + " slwi A1,AL,AR" COM "left shift by constant\n", }, + +{ LS, INAREG|FORCC, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SCON, TANY, + NAREG|NASL, RESC1, + " slwi. A1,AL,AR" COM "left shift by constant\n", }, + +{ LS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCON, TANY, + NBREG, RESC1, + "ZO", }, + +{ LS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TANY, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ RS, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " srw A1,AL,AR" COM "right shift\n", }, + +{ RS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " sraw A1,AL,AR" COM "arithmetic right shift\n", }, + +{ RS, INAREG|FORCC, + SAREG, TUWORD|TUSHORT|TUCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " srw. A1,AL,AR" COM "right shift\n", }, + +{ RS, INAREG|FORCC, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " sraw. A1,AL,AR" COM "arithmetic right shift\n", }, + +{ RS, INAREG, + SAREG, TUWORD|TUSHORT|TUCHAR, + SCON, TANY, + NAREG|NASL, RESC1, + " srwi A1,AL,AR" COM "right shift by constant\n", }, + +{ RS, INAREG, + SAREG, TSWORD|TSHORT|TCHAR, + SCON, TANY, + NAREG|NASL, RESC1, + " srawi A1,AL,AR" COM "arithmetic right shift by constant\n", }, + +{ RS, INAREG|FORCC, + SAREG, TUWORD|TUSHORT|TUCHAR, + SCON, TANY, + NAREG|NASL, RESC1, + " srwi. A1,AL,AR" COM "right shift by constant\n", }, + +{ RS, INAREG|FORCC, + SAREG, TSWORD|TSHORT|TCHAR, + SCON, TANY, + NAREG|NASL, RESC1, + " srawi. A1,AL,AR" COM "right shift by constant\n", }, + +{ RS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCON, TANY, + NBREG, RESC1, + "ZO" }, + +{ RS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SAREG, TANY, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +/* + * The next rules takes care of assignments. "=". + */ + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TANY, + 0, RDEST, + " li AL,AR\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONGLONG|TULONGLONG, + SSCON, TANY, + 0, RDEST, + " li AL,AR\n" + " li UL,UR\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SCON, TANY, + 0, RDEST, + " lis AL," HA16(AR) "\n" + " addi AL,AL," LO16(AR) "\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONGLONG|TULONGLONG, + SCON, TANY, + 0, RDEST, + " lis AL," HA16(AR) "\n" + " addi AL,AL," LO16(AR) "\n" + " lis UL," HA16(UR) "\n" + " addi UL,UL," LO16(UR) "\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SOREG, TWORD|TPOINT, + NSPECIAL, RDEST, + " lwz AL,AR" COM "assign oreg to reg\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SNAME, TWORD|TPOINT, + NSPECIAL, RDEST, + " lis AL," HA16(AR) COM "assign sname to reg\n" + " lwz AL," LO16(AR) "(AL)\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONGLONG|TULONGLONG, + SOREG, TLONGLONG|TULONGLONG, + NSPECIAL, RDEST, + " lwz AL,AR" COM "assign llong to reg\n" + " lwz UL,UR\n" }, + +{ ASSIGN, FOREFF|INAREG, + SBREG, TLONGLONG|TULONGLONG, + SNAME, TLONGLONG|TULONGLONG, + NSPECIAL, RDEST, + " lis AL," HA16(AR) COM "assign 64-bit sname to reg\n" + " lwz AL," LO16(AR) "(AL)\n" + " lis UL," HA16(UR) "\n" + " lwz UL," LO16(UR) "(UL)\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONGLONG|TULONGLONG, + SOREG, TSWORD, + NSPECIAL, RDEST, + " lwz AL,AR" COM "load int/pointer into llong\n" + " srawi UL,AR,31\n" }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONGLONG|TULONGLONG, + SOREG, TUNSIGNED|TPOINT, + NSPECIAL, RDEST, + " lwz AL,AR" COM "load uint/pointer into (u)llong\n" + " li UL,0\n" }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TUCHAR, + SOREG, TUCHAR, + NSPECIAL, RDEST, + " lbz AL,AR\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TUCHAR, + SNAME, TUCHAR, + NSPECIAL, RDEST, + " lis AL," HA16(AR) COM "assign uchar sname to reg\n" + " lbz AL," LO16(AR) "(AL)\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TCHAR, + SOREG, TCHAR, + NSPECIAL, RDEST, + " lbz AL,AR\n" + " extsb AL,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TCHAR, + SNAME, TCHAR, + NSPECIAL, RDEST, + " lis AL," HA16(AR) COM "assign char sname to reg\n" + " lbz AL," LO16(AR) "(AL)\n" + " extsb AL,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SOREG, TSHORT, + NSPECIAL, RDEST, + " lha AL,AR\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT, + SOREG, TUSHORT, + NSPECIAL, RDEST, + " lhz AL,AR\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD, + SNAME, TSHORT, + NSPECIAL, RDEST, + " lis AL," HA16(AR) "\n" + " lha AL," LO16(AR) "(AL)\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD, + SNAME, TUSHORT, + NSPECIAL, RDEST, + " lis AL," HA16(AR) "\n" + " lhz AL," LO16(AR) "(AL)\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + NSPECIAL, RDEST, + " stw AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SNAME, TWORD|TPOINT, + SAREG, TWORD|TPOINT, + NAREG|NSPECIAL, RDEST, + " lis A1," HA16(AL) COM "assign reg to sname\n" + " stw AR," LO16(AL) "(A1)\n", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL, RDEST, + " stw AR,AL" COM "store 64-bit value\n" + " stw UR,UL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SNAME, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NSPECIAL, RDEST, + " lis A1," HA16(AL) COM "assign reg to 64-bit sname\n" + " stw AR," LO16(AL) "(A1)\n" + " lis U1," HA16(UL) "\n" + " stw UR," LO16(UL) "(U1)\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + NSPECIAL, RDEST, + " stb AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SNAME, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + NAREG|NSPECIAL, RDEST, + " lis A1," HA16(AL) "\n" + " stb AR," LO16(AL) "(A1)\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + NSPECIAL, RDEST, + " sth AR,AL\n", }, + +{ ASSIGN, FOREFF|INAREG, + SNAME, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + NAREG|NSPECIAL, RDEST, + " lis A1," HA16(AL) "\n" + " sth AR," LO16(AL) "(A1)\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, RDEST, + " mr AL,AR" COM "assign AR to AL\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RDEST, + " mr AL,AR" COM "assign UR:AR to UL:AL\n" + " mr UL,UR\n", }, + +{ ASSIGN, FOREFF|INAREG, + SFLD, TANY, + SAREG, TANY, + 3*NAREG, RDEST, + " lis A3," HA16(M) COM "bit-field assignment\n" + " addi A3,A3," LO16(M) "\n" + " lwz A2,AL\n" + " slwi A1,AR,H\n" + " and A1,A1,A3\n" + " not A3,A3\n" + " and A2,A2,A3\n" + " or A2,A2,A1\n" + " stw A2,AL\n" + "F mr AD,AR\n" + "F slwi AD,AD,32-S\n" + "F srwi AD,AD,32-S\n", }, + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG, TPTRTO|TANY, + NSPECIAL, RDEST, + "ZQ", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, + SOREG, TFLOAT, + SCREG, TFLOAT, + 0, RDEST, + " stfs AR,AL" COM "store float\n", }, + +/* soft-float */ +{ ASSIGN, FOREFF|INAREG, + SOREG, TFLOAT, + SAREG, TFLOAT, + 0, RDEST, + " stw AR,AL" COM "store float (soft-float)\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, + SNAME, TFLOAT, + SCREG, TFLOAT, + NAREG, RDEST, + " lis A1," HA16(AL) "\n" + " stfs AR," LO16(AL) "(A1)\n", }, + +/* soft-float */ +{ ASSIGN, FOREFF|INAREG, + SNAME, TFLOAT, + SAREG, TFLOAT, + NAREG, RDEST, + " lis A1," HA16(AL) "\n" + " stw AR," LO16(AL) "(A1)\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, + SCREG, TFLOAT, + SOREG, TFLOAT, + 0, RDEST, + " lfs AL,AR" COM "load float\n", }, + +/* soft-float */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TFLOAT, + SOREG, TFLOAT, + 0, RDEST, + " lwz AL,AR" COM "load float (soft-float)\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, + SCREG, TFLOAT, + SNAME, TFLOAT, + NAREG, RDEST, + " lis A1," HA16(AR) "\n" + " lfs AL," LO16(AR) "(A1)\n", }, + +/* soft-float */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TFLOAT, + SNAME, TFLOAT, + NAREG, RDEST, + " lis A1," HA16(AR) "\n" + " lwz AL," LO16(AR) "(A1)\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, + SCREG, TFLOAT, + SCREG, TFLOAT, + 0, RDEST, + " fmr AL,AR" COM "assign AR to AL\n", }, + +/* soft-float */ +{ ASSIGN, FOREFF|INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + 0, RDEST, + " mr AL,AR" COM "assign AR to AL\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, + SOREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " stfd AR,AL" COM "store (l)double\n", }, + +/* soft-float */ +{ ASSIGN, FOREFF|INBREG, + SOREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " stw AR,AL" COM "store (l)double (soft-float)\n" + " stw UR,UL\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, + SNAME, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NAREG, RDEST, + " lis A1," HA16(AL) "\n" + " stfd AR," LO16(AL) "(A1)\n", }, + +/* soft-float */ +{ ASSIGN, FOREFF|INBREG, + SNAME, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + NAREG, RDEST, + " lis A1," HA16(AL) "\n" + " stw AR," LO16(AL) "(A1)\n" + " lis A1," HA16(UL) "\n" + " stw UR," LO16(UL) "(A1)\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + SOREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " lfd AL,AR" COM "load (l)double\n", }, + +/* soft-float */ +{ ASSIGN, FOREFF|INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SOREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " lwz AL,AR" COM "load (l)double (soft-float)\n" + " lwz UL,UR\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + SNAME, TDOUBLE|TLDOUBLE, + NAREG, RDEST, + " lis A1," HA16(AR) "\n" + " lfd AL," LO16(AR) "(A1)\n", }, + +/* soft-float */ +{ ASSIGN, FOREFF|INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SNAME, TDOUBLE|TLDOUBLE, + NAREG, RDEST, + " lis A1," HA16(AR) "\n" + " lwz AL," LO16(AR) "(A1)\n" + " lis A1," HA16(UR) "\n" + " lwz UL," LO16(UR) "(A1)\n", }, + +{ ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " fmr AL,AR" COM "assign AR to AL\n", }, + +/* soft-float */ +{ ASSIGN, FOREFF|INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + 0, RDEST, + " mr AL,AR" COM "assign AR to AL\n" + " mr UL,UR\n", }, + +/* + * DIV/MOD/MUL + */ + +{ DIV, INAREG, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + NAREG|NASL, RESC1, + " divwu A1,AL,AR\n", }, + +{ DIV, INAREG|FORCC, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + NAREG|NASL, RESC1|RESCC, + " divwu. A1,AL,AR\n", }, + +{ DIV, INAREG, + SAREG, TWORD|TSHORT|TCHAR, + SAREG, TWORD|TSHORT|TCHAR, + NAREG|NASL, RESC1, + " divw A1,AL,AR\n", }, + +{ DIV, INAREG|FORCC, + SAREG, TWORD|TSHORT|TCHAR, + SAREG, TWORD|TSHORT|TCHAR, + NAREG|NASL, RESC1|RESCC, + " divw. A1,AL,AR\n", }, + +{ DIV, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ DIV, INCREG | FEATURE_HARDFLOAT, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG|NCSR, RESC1, + " fdivs A1,AL,AR" COM "float divide\n", }, + +/* soft-float */ +{ DIV, INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ DIV, INCREG | FEATURE_HARDFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG|NCSR, RESC1, + " fdiv A1,AL,AR" COM "(l)double divide\n", }, + +/* soft-float */ +{ DIV, INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +{ MOD, INAREG, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + NAREG, RESC1, + " divwu A1,AL,AR" COM "unsigned modulo\n" + " mullw A1,A1,AR\n" + " subf A1,A1,AL\n", }, + +{ MOD, INAREG, + SAREG, TWORD|TSHORT|TCHAR, + SAREG, TWORD|TSHORT|TCHAR, + NAREG, RESC1, + " divw A1,AL,AR" COM "signed modulo\n" + " mullw A1,A1,AR\n" + " subf A1,A1,AL\n", }, + +{ MOD, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NSPECIAL|NBREG, RESC1, + "ZE", }, + +{ MUL, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TANY, + NAREG|NASL, RESC1, + " mulli A1,AL,AR\n", }, + +{ MUL, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SSCON, TANY, + NAREG|NASL, RESC1|RESCC, + " mulli. A1,AL,AR\n", }, + +{ MUL, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " mullw A1,AL,AR\n", }, + +{ MUL, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1|RESCC, + " mullw. A1,AL,AR\n", }, + +{ MUL, INBREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NBREG, RESC1, + " mullw A1,AL,AR\n" + " mulhw U1,AL,AR\n", }, + +{ MUL, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " mullw A1,AL,AR\n" + " mulhw U1,AL,AR\n", }, + +{ MUL, INCREG | FEATURE_HARDFLOAT, + SCREG, TFLOAT, + SCREG, TFLOAT, + NCREG|NCSR, RESC1, + " fmuls A1,AL,AR" COM "float multiply\n", }, + +/* soft-float */ +{ MUL, INAREG, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL|NAREG, RESC1, + "ZF", }, + +{ MUL, INCREG | FEATURE_HARDFLOAT, + SCREG, TDOUBLE|TLDOUBLE, + SCREG, TDOUBLE|TLDOUBLE, + NCREG|NCSR, RESC1, + " fmul A1,AL,AR" COM "(l)double multiply\n", }, + +/* soft-float */ +{ MUL, INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + NSPECIAL|NBREG, RESC1, + "ZF", }, + +/* + * Indirection operators. + */ + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TWORD|TPOINT, + NAREG|NSPECIAL, RESC1, + " lwz A1,AL" COM "word load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TCHAR, + NAREG|NSPECIAL, RESC1, + " lbz A1,AL" COM "char load\n" + " extsb A1,A1\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TUCHAR, + NAREG|NSPECIAL, RESC1, + " lbz A1,AL" COM "uchar load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TSHORT, + NAREG|NSPECIAL, RESC1, + " lha A1,AL" COM "short load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TUSHORT, + NAREG|NSPECIAL, RESC1, + " lhz A1,AL" COM "ushort load\n", }, + +{ UMUL, INBREG, + SANY, TANY, + SOREG|SNAME, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " lwz A1,AL" COM "64-bit load\n" + " lwz U1,UL\n", }, + +{ UMUL, INCREG | FEATURE_HARDFLOAT, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NCREG, RESC1, + " lfs A1,AL" COM "float load\n", }, + +{ UMUL, INAREG, + SANY, TANY, + SOREG|SNAME, TFLOAT, + NAREG, RESC1, + " lwz A1,AL" COM "float load (soft-float)\n", }, + +{ UMUL, INCREG | FEATURE_HARDFLOAT, + SANY, TANY, + SOREG|SNAME, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " lfd A1,AL" COM "(l)double load\n", }, + +{ UMUL, INBREG, + SANY, TANY, + SOREG|SNAME, TDOUBLE|TLDOUBLE, + NSPECIAL|NBREG, RESC1, + " lwz A1,AL" COM "(l)double load (soft-float)\n" + " lwz U1,UL\n", }, + +#if 0 +{ UMUL, INAREG, + SANY, TANY, + SAREG, TWORD|TPOINT, + NAREG, RESC1, + " lwz A1,(AL)" COM "word load\n", }, +#endif + +/* + * Logical/branching operators + */ + +/* compare with constant */ +{ OPLOG, FORCC, + SAREG, TSWORD|TSHORT|TCHAR, + SSCON, TANY, + 0, RESCC, + " cmpwi AL,AR\n", }, + +/* compare with constant */ +{ OPLOG, FORCC, + SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, + SSCON, TANY, + 0, RESCC, + " cmplwi AL,AR\n", }, + +/* compare with register */ +{ OPLOG, FORCC, + SAREG, TSWORD|TSHORT|TCHAR, + SAREG, TSWORD|TSHORT|TCHAR, + 0, RESCC, + " cmpw AL,AR\n", }, + +/* compare with register */ +{ OPLOG, FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + 0, RESCC, + " cmplw AL,AR\n", }, + +/* compare with register */ +{ OPLOG, FORCC, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + 0, RESCC, + "ZD", }, + +/* compare with register */ +{ OPLOG, FORCC | FEATURE_HARDFLOAT, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + 0, RESCC, + " fcmpu 0,AL,AR\n", }, + +/* soft-float */ +{ OPLOG, FORCC, + SAREG, TFLOAT, + SAREG, TFLOAT, + NSPECIAL, RESCC, + "ZF\n", }, + +/* soft-float */ +{ OPLOG, FORCC, + SBREG, TDOUBLE|TLDOUBLE, + SBREG, TDOUBLE|TLDOUBLE, + NSPECIAL, RESCC, + "ZF", }, + +{ OPLOG, FORCC, + SANY, TANY, + SANY, TANY, + REWRITE, 0, + "diediedie!", }, + +/* AND/OR/ER */ +{ AND, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1|RESCC, + " and A1,AL,AR\n", }, + +{ AND, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1, + " and. A1,AL,AR\n", }, + +/* AR must be positive */ +{ AND, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SPCON, TANY, + NAREG|NASL|NSPECIAL, RESC1|RESCC, + " andi. A1,AL,AR\n", }, + +{ AND, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " and A1,AL,AR" COM "64-bit and\n" + " and U1,UL,UR\n" }, + +{ AND, INBREG|FORCC, + SBREG, TLONGLONG|TULONGLONG, + SPCON, TANY, + NBREG|NBSL, RESC1|RESCC, + " andi. A1,AL,AR" COM "64-bit and with constant\n" + " li U1,0\n" }, + +{ OR, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1, + " or A1,AL,AR\n", }, + +{ OR, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1|RESCC, + " or. A1,AL,AR\n", }, + +{ OR, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SPCON, TANY, + NAREG|NASL, RESC1, + " ori A1,AL,AR\n", }, + +{ OR, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SPCON, TANY, + NAREG|NASL, RESC1|RESCC, + " ori. A1,AL,AR\n", }, + +{ OR, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " or A1,AL,AR" COM "64-bit or\n" + " or U1,UL,UR\n" }, + +{ OR, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SPCON, TANY, + NBREG|NBSL, RESC1, + " ori A1,AL,AR" COM "64-bit or with constant\n" }, + +{ OR, INBREG|FORCC, + SBREG, TLONGLONG|TULONGLONG, + SPCON, TANY, + NBREG|NBSL, RESC1|RESCC, + " ori. A1,AL,AR" COM "64-bit or with constant\n" }, + +{ ER, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1, + " xor A1,AL,AR\n", }, + +{ ER, INAREG|FORCC, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL|NSPECIAL, RESC1|RESCC, + " xor. A1,AL,AR\n", }, + +{ ER, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SPCON, TANY, + NAREG|NASL|NSPECIAL, RESC1, + " xori A1,AL,AR\n", }, + +{ ER, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SBREG, TLONGLONG|TULONGLONG, + NBREG|NBSL, RESC1, + " xor A1,AL,AR" COM "64-bit xor\n" + " xor U1,UL,UR\n" }, + +{ ER, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SPCON, TANY, + NBREG|NBSL, RESC1, + " xori A1,AL,AR" COM "64-bit xor with constant\n" }, + +/* + * Jumps. + */ +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " b LL\n", }, + +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " mtctr AL\n" + " bctr\n", }, + +/* + * Convert LTYPE to reg. + */ + +#if defined(ELFABI) +{ OPLTYPE, INAREG | FEATURE_PIC, + SANY, TANY, + SNAME, TANY, + NAREG, RESC1, + " lwz A1,AL" COM "elfabi pic load\n", }, +#endif + +{ OPLTYPE, INBREG, + SANY, TANY, + SOREG, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " lwz A1,AL" COM "load llong from memory\n" + " lwz U1,UL\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SNAME, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " lis A1," HA16(AL) COM "load llong from sname\n" + " lwz A1," LO16(AL) "(A1)\n" + " lis U1," HA16(UL) "\n" + " lwz U1," LO16(UL) "(U1)\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG, TWORD|TPOINT, + NAREG, RESC1, + " lwz A1,AL" COM "load word from memory\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME, TWORD|TPOINT, + NAREG|NSPECIAL, RESC1, + " lis A1," HA16(AL) COM "load word from sname\n" + " lwz A1," LO16(AL) "(A1)\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG, TCHAR, + NAREG, RESC1, + " lbz A1,AL" COM "load char from memory\n" + " extsb A1,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME, TCHAR, + NAREG|NSPECIAL, RESC1, + " lis A1," HA16(AL) COM "load char from sname\n" + " lbz A1," LO16(AL) "(A1)\n" + " extsb A1,A1\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG, TUCHAR, + NAREG, RESC1, + " lbz A1,AL" COM "load uchar from memory\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME, TUCHAR, + NAREG|NSPECIAL, RESC1, + " lis A1," HA16(AL) COM "load uchar from sname\n" + " lbz A1," LO16(AL) "(A1)\n", }, + +/* load short from memory */ +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG, TSHORT, + NAREG, RESC1, + " lha A1,AL" COM "load short from memory\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG, TUSHORT, + NAREG, RESC1, + " lhz A1,AL" COM "load ushort from memory\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME, TSHORT, + NAREG|NSPECIAL, RESC1, + " lis A1," HA16(AL) COM "load short from sname\n" + " lha A1," LO16(AL) "(A1)\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME, TUSHORT, + NAREG|NSPECIAL, RESC1, + " lis A1," HA16(AL) COM "load ushort from sname\n" + " lhz A1," LO16(AL) "(A1)\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SSCON, TANY, + NAREG, RESC1, + " li A1,AL" COM "load 16-bit constant\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SSCON, TANY, + NBREG, RESC1, + " li A1,AL" COM "load 16-bit constant\n" + " li U1,UL\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON, TANY, + NAREG|NASL, RESC1, + " lis A1," HA16(AL) COM "load constant into register\n" + " addi A1,A1," LO16(AL) "\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SCON, TANY, + NBREG, RESC1, + " lis A1," HA16(AL) COM "load constant into register\n" + " addi A1,A1," LO16(AL) "\n" + " lis U1," HA16(UL) "\n" + " addi U1,U1," LO16(UL) "\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SAREG, TANY, + NAREG, RESC1, + " mr A1,AL" COM "load AL into A1\n" }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SBREG, TANY, + NBREG, RESC1, + " mr A1,AL" COM "load UL:AL into U1:A1\n" + " mr U1,UL\n", }, + +{ OPLTYPE, INCREG, + SANY, TANY, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " fmr A1,AL" COM "load AL into A1\n", }, + +{ OPLTYPE, INCREG | FEATURE_HARDFLOAT, + SANY, TANY, + SOREG, TFLOAT, + NCREG, RESC1, + " lfs A1,AL" COM "load float\n", }, + +/* soft-float */ +{ OPLTYPE, INAREG, + SANY, TANY, + SOREG, TFLOAT, + NAREG, RESC1, + " lwz A1,AL" COM "load float (soft-float)\n", }, + +{ OPLTYPE, INCREG | FEATURE_HARDFLOAT, + SANY, TANY, + SNAME, TFLOAT, + NCREG|NAREG, RESC2, + " lis A1," HA16(AL) COM "load sname\n" + " lfs A2," LO16(AL) "(A1)\n", }, + +/* soft-float */ +{ OPLTYPE, INAREG, + SANY, TANY, + SNAME, TFLOAT, + NAREG, RESC1, + " lis A1," HA16(AL) COM "load sname (soft-float)\n" + " lwz A1," LO16(AL) "(A1)\n", }, + +{ OPLTYPE, INCREG | FEATURE_HARDFLOAT, + SANY, TANY, + SOREG, TDOUBLE|TLDOUBLE, + NCREG, RESC1, + " lfd A1,AL" COM "load (l)double\n", }, + +/* soft-float */ +{ OPLTYPE, INBREG, + SANY, TANY, + SOREG, TDOUBLE|TLDOUBLE, + NBREG, RESC1, + " lwz A1,AL" COM "load (l)double (soft-float)\n" + " lwz U1,UL\n", }, + +{ OPLTYPE, INCREG | FEATURE_HARDFLOAT, + SANY, TANY, + SNAME, TDOUBLE|TLDOUBLE, + NCREG|NAREG, RESC2, + " lis A1," HA16(AL) COM "load sname\n" + " lfd A2," LO16(AL) "(A1)\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SNAME, TDOUBLE|TLDOUBLE, + NBREG, RESC1, + " lis A1," HA16(AL) COM "load sname (soft-float)\n" + " lwz A1," LO16(AL) "(A1)\n" + " lis U1," HA16(UL) "\n" + " lwz U1," LO16(UL) "(U1)\n", }, + + +/* + * Negate a word. + */ + +{ UMINUS, INAREG, + SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TANY, + NAREG|NASL, RESC1, + " neg A1,AL\n", }, + +{ UMINUS, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SANY, TANY, + NBREG|NBSL, RESC1, + " subfic A1,AL,0\n" + " subfze U1,UL\n", }, + +{ UMINUS, INCREG | FEATURE_HARDFLOAT, + SCREG, TFLOAT|TDOUBLE|TLDOUBLE, + SANY, TANY, + NCREG|NCSL, RESC1, + " fneg A1,AL\n", }, + +{ UMINUS, INAREG, + SAREG, TFLOAT, + SANY, TANY, + NAREG|NASL, RESC1, + " xoris A1,AL,0x8000" COM "(soft-float)\n", }, + +{ UMINUS, INBREG, + SBREG, TDOUBLE|TLDOUBLE, + SANY, TANY, + NBREG|NBSL, RESC1, + " xoris U1,UL,0x8000" COM "(soft-float)\n" + " mr A1,AL\n", }, + +{ COMPL, INAREG, + SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, + SANY, TANY, + NAREG|NASL, RESC1, + " not A1,AL\n", }, + +{ COMPL, INBREG, + SBREG, TLONGLONG|TULONGLONG, + SANY, TANY, + NBREG|NBSL, RESC1, + " not A1,AL\n" + " not U1,UL\n", }, + +/* + * Arguments to functions. + */ + +#if 0 +{ STARG, FOREFF, + SAREG|SOREG|SNAME|SCON, TANY, + SANY, TSTRUCT, + NSPECIAL|NAREG, 0, + "ZF", }, +#endif + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ FLD, DF(FLD), }, + +{ OPLEAF, DF(NAME), }, + +/* { INIT, DF(INIT), }, */ + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/sparc64/code.c b/lang/pcc/pcc/arch/sparc64/code.c new file mode 100644 index 000000000..b2b7b53c1 --- /dev/null +++ b/lang/pcc/pcc/arch/sparc64/code.c @@ -0,0 +1,272 @@ +/* $Id: code.c,v 1.23 2015/07/24 07:57:01 ragge Exp $ */ + +/* + * Copyright (c) 2008 David Crawshaw + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "pass1.h" + +/* + * Print out assembler segment name. + */ +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + case DATA: + case LDATA: name = ".data"; break; + case STRNG: + case RDATA: name = ".section .rodata"; break; + case UDATA: break; + case PICLDATA: + case PICDATA: + case PICRDATA: + case TLSDATA: + case TLSUDATA: + case CTORS: + case DTORS: + uerror("FIXME: unknown section"); + case NMSEG: + printf("\t.section %s,\"a%c\",@progbits\n", name, + cftnsp ? 'x' : 'w'); + return; + } + printf("\t%s\n", name); +} + + +void +defloc(struct symtab *sp) +{ + TWORD t; + char *name; + + t = sp->stype; + + if ((name = sp->soname) == NULL) + name = exname(sp->sname); + + if (!ISFTN(t)) { + printf("\t.type %s,#object\n", name); + printf("\t.size %s," CONFMT "\n", name, + tsize(sp->stype, sp->sdf, sp->sap) / SZCHAR); + } + if (sp->sclass == EXTDEF) + printf("\t.global %s\n", name); + if (sp->slevel == 0) { + printf("%s:\n", name); + } else + printf(LABFMT ":\n", sp->soffset); +} + +void +efcode(void) +{ + /* XXX */ +} + +void +bfcode(struct symtab **sp, int cnt) +{ + int i, off; + NODE *p, *q; + struct symtab *sym; + + /* Process the first six arguments. */ + for (i=0; i < cnt && i < 6; i++) { + sym = sp[i]; + q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); + q->n_rval = RETREG_PRE(sym->stype) + i; + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + sym->soffset = regno(p); + sym->sflags |= STNODE; + p = buildtree(ASSIGN, p, q); + ecomp(p); + } + + /* Process the remaining arguments. */ + for (off = V9RESERVE; i < cnt; i++) { + sym = sp[i]; + p = tempnode(0, sym->stype, sym->sdf, sym->sap); + off = ALIGN(off, (tlen(p) - 1)); + sym->soffset = off * SZCHAR; + off += tlen(p); + p = buildtree(ASSIGN, p, nametree(sym)); + sym->soffset = regno(p->n_left); + sym->sflags |= STNODE; + ecomp(p); + } +} + +void +ejobcode(int flag) +{ +} + +void +bjobcode(void) +{ + astypnames[USHORT] = astypnames[SHORT] = "\t.half"; + astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; + astypnames[LONG] = astypnames[ULONG] = + astypnames[LONGLONG] = astypnames[ULONGLONG] = "\t.xword"; +} + +/* + * The first six 64-bit arguments are saved in the registers O0 to O5, + * which become I0 to I5 after the "save" instruction moves the register + * window. Arguments 7 and up must be saved on the stack to %sp+BIAS+176. + * + * For a pretty picture, see Figure 3-16 in the SPARC Compliance Def 2.4. + */ +static NODE * +moveargs(NODE *p, int *regp, int *stacksize) +{ + NODE *r, *q; + + if (p->n_op == CM) { + p->n_left = moveargs(p->n_left, regp, stacksize); + r = p->n_right; + } else { + r = p; + } + + /* XXX more than six FP args can and should be passed in registers. */ + if (*regp > 5 && r->n_op != STARG) { + /* We are storing the stack offset in n_rval. */ + r = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap); + /* Make sure we are appropriately aligned. */ + *stacksize = ALIGN(*stacksize, (tlen(r) - 1)); + r->n_rval = *stacksize; + *stacksize += tlen(r); + } else if (r->n_op == STARG) + cerror("op STARG in moveargs"); + else { + q = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap); + + /* + * The first six non-FP arguments go in the registers O0 - O5. + * Float arguments are stored in %fp1, %fp3, ..., %fp29, %fp31. + * Double arguments are stored in %fp0, %fp2, ..., %fp28, %fp30. + * A non-fp argument still increments register, eg. + * test(int a, int b, float b) + * takes %o0, %o1, %fp5. + */ + if (q->n_type == FLOAT) + q->n_rval = F0 + (*regp++ * 2) + 1; + else if (q->n_type == DOUBLE) + q->n_rval = D0 + *regp++; + else if (q->n_type == LDOUBLE) + cerror("long double support incomplete"); + else + q->n_rval = O0 + (*regp)++; + + r = buildtree(ASSIGN, q, r); + } + + if (p->n_op == CM) { + p->n_right = r; + return p; + } + + return r; +} + +NODE * +funcode(NODE *p) +{ + NODE *r, *l; + int reg = 0, stacksize = 0; + + r = l = 0; + + p->n_right = moveargs(p->n_right, ®, &stacksize); + + /* + * This is a particularly gross and inefficient way to handle + * argument overflows. First, we calculate how much stack space + * we need in moveargs(). Then we assign it by moving %sp, make + * the function call, and then move %sp back. + * + * What we should be doing is getting the maximum of all the needed + * stacksize values to the prologue and doing it all in the "save" + * instruction. + */ + if (stacksize != 0) { + stacksize = V9STEP(stacksize); /* 16-bit alignment. */ + + r = block(REG, NIL, NIL, INT, 0, 0); + r->n_lval = 0; + r->n_rval = SP; + r = block(MINUS, r, bcon(stacksize), INT, 0, 0); + + l = block(REG, NIL, NIL, INT, 0, 0); + l->n_lval = 0; + l->n_rval = SP; + r = buildtree(ASSIGN, l, r); + + p = buildtree(COMOP, r, p); + + r = block(REG, NIL, NIL, INT, 0, 0); + r->n_lval = 0; + r->n_rval = SP; + r = block(PLUS, r, bcon(stacksize), INT, 0, 0); + + l = block(REG, NIL, NIL, INT, 0, 0); + l->n_lval = 0; + l->n_rval = SP; + r = buildtree(ASSIGN, l, r); + + p = buildtree(COMOP, p, r); + + } + return p; +} + +void +fldty(struct symtab *p) +{ +} + +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + +/* + * Return "canonical frame address". + */ +NODE * +builtin_cfa(const struct bitable *bt, NODE *a) +{ + uerror("missing %s", __func__); + return bcon(0); +} + +NODE * +builtin_frame_address(const struct bitable *bt, NODE *a) +{ + uerror("missing %s", __func__); + return bcon(0); +} + +NODE * +builtin_return_address(const struct bitable *bt, NODE *a) +{ + uerror("missing %s", __func__); + return bcon(0); +} diff --git a/lang/pcc/pcc/arch/sparc64/local.c b/lang/pcc/pcc/arch/sparc64/local.c new file mode 100644 index 000000000..507dc5e9f --- /dev/null +++ b/lang/pcc/pcc/arch/sparc64/local.c @@ -0,0 +1,281 @@ +/* $Id: local.c,v 1.34 2011/06/23 13:41:25 ragge Exp $ */ + +/* + * Copyright (c) 2008 David Crawshaw + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "pass1.h" + +NODE * +clocal(NODE *p) +{ + struct symtab *sp; + int op; + NODE *r, *l; + + op = p->n_op; + sp = p->n_sp; + l = p->n_left; + r = p->n_right; + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal in: %p, %s\n", p, copst(op)); + fwalk(p, eprint, 0); + } +#endif + + switch (op) { + + case NAME: + if (sp->sclass == PARAM || sp->sclass == AUTO) { + /* + * Use a fake structure reference to + * write out frame pointer offsets. + */ + l = block(REG, NIL, NIL, PTR+STRTY, 0, 0); + l->n_lval = 0; + l->n_rval = FP; + r = p; + p = stref(block(STREF, l, r, 0, 0, 0)); + } + break; + case PCONV: /* Remove what PCONVs we can. */ + if (l->n_op == SCONV) + break; + + if (l->n_op == ICON || (ISPTR(p->n_type) && ISPTR(l->n_type))) { + l->n_type = p->n_type; + l->n_qual = p->n_qual; + l->n_df = p->n_df; + l->n_ap = p->n_ap; + nfree(p); + p = l; + } + break; + + case SCONV: + /* Remove redundant conversions. */ + if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && + tsize(p->n_type, p->n_df, p->n_ap) == + tsize(l->n_type, l->n_df, l->n_ap) && + p->n_type != FLOAT && p->n_type != DOUBLE && + l->n_type != FLOAT && l->n_type != DOUBLE && + l->n_type != DOUBLE && p->n_type != LDOUBLE) { + if (l->n_op == NAME || l->n_op == UMUL || + l->n_op == TEMP) { + l->n_type = p->n_type; + nfree(p); + p = l; + break; + } + } + + /* Convert floating point to int before to char or short. */ + if ((l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE) + && (DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT)) { + p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left->n_type = INT; + break; + } + + /* Transform constants now. */ + if (l->n_op != ICON) + break; + + if (ISPTR(p->n_type)) { + l->n_type = p->n_type; + nfree(p); + p = l; + break; + } + + switch (p->n_type) { + case BOOL: l->n_lval = (l->n_lval != 0); break; + case CHAR: l->n_lval = (char)l->n_lval; break; + case UCHAR: l->n_lval = l->n_lval & 0377; break; + case SHORT: l->n_lval = (short)l->n_lval; break; + case USHORT: l->n_lval = l->n_lval & 0177777; break; + case UNSIGNED: l->n_lval = l->n_lval & 0xffffffff; break; + case INT: l->n_lval = (int)l->n_lval; break; + case ULONG: + case ULONGLONG: l->n_lval = l->n_lval; break; + case LONG: + case LONGLONG: l->n_lval = (long long)l->n_lval; break; + case FLOAT: + case DOUBLE: + case LDOUBLE: + l->n_op = FCON; + l->n_dcon = l->n_lval; + break; + case VOID: + break; + default: + cerror("sconv type unknown %d", p->n_type); + } + + l->n_type = p->n_type; + nfree(p); + p = l; + break; + + case FORCE: + /* Put attached value into the return register. */ + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + p->n_left->n_rval = RETREG_PRE(p->n_type); + break; + } + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal out: %p, %s\n", p, copst(op)); + fwalk(p, eprint, 0); + } +#endif + + return p; +} + +void +myp2tree(NODE *p) +{ + struct symtab *sp; + + if (p->n_op != FCON) + return; + + sp = tmpalloc(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->slevel = 1; + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + + defloc(sp); + ninval(0, tsize(p->n_type, p->n_df, p->n_ap), p); + + p->n_op = NAME; + p->n_lval = 0; + p->n_sp = sp; +} + +int +andable(NODE *p) +{ + return 1; +} + +int +cisreg(TWORD t) +{ + /* SPARCv9 registers are all 64-bits wide. */ + return 1; +} + +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + cerror("spalloc"); +} + +int +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; int i; long long l; } u; + + switch (p->n_type) { + case FLOAT: + u.f = (float)p->n_dcon; + printf("\t.long %d\n", u.i); + break; + case DOUBLE: + u.d = (double)p->n_dcon; + printf("\t.xword %lld\n", u.l); + break; + default: + return 0; + } + return 1; +} + +char * +exname(char *p) +{ + return p ? p : ""; +} + +TWORD +ctype(TWORD type) +{ + switch (BTYPE(type)) { + case LONGLONG: + MODTYPE(type,LONG); + break; + case ULONGLONG: + MODTYPE(type,ULONG); + + } + return type; +} + +void +calldec(NODE *p, NODE *q) +{ +} + +void +extdec(struct symtab *q) +{ +} + +void +defzero(struct symtab *sp) +{ + int off; + char *name; + + if ((name = sp->soname) == NULL) + name = exname(sp->sname); + off = tsize(sp->stype, sp->sdf, sp->sap); + SETOFF(off,SZCHAR); + off /= SZCHAR; + + if (sp->sclass == STATIC) + printf("\t.local %s\n", name); + if (sp->slevel == 0) + printf("\t.comm %s,%d\n", name, off); + else + printf("\t.comm " LABFMT ",%d\n", sp->soffset, off); +} + +int +mypragma(char *str) +{ + return 0; +} + +void +fixdef(struct symtab *sp) +{ +} + +void +pass1_lastchance(struct interpass *ip) +{ +} + diff --git a/lang/pcc/pcc/arch/sparc64/local2.c b/lang/pcc/pcc/arch/sparc64/local2.c new file mode 100644 index 000000000..6cd0a4431 --- /dev/null +++ b/lang/pcc/pcc/arch/sparc64/local2.c @@ -0,0 +1,425 @@ +/* $Id: local2.c,v 1.27 2015/01/04 19:17:23 ragge Exp $ */ + +/* + * Copyright (c) 2008 David Crawshaw + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "pass1.h" +#include "pass2.h" + + +char * +rnames[] = { + /* "\%g0", always zero, removed due to 31-element class limit */ + "\%g1", "\%g2", "\%g3", "\%g4", "\%g5", "\%g6", "\%g7", + "\%o0", "\%o1", "\%o2", "\%o3", "\%o4", "\%o5", "\%o6", "\%o7", + "\%l0", "\%l1", "\%l2", "\%l3", "\%l4", "\%l5", "\%l6", "\%l7", + "\%i0", "\%i1", "\%i2", "\%i3", "\%i4", "\%i5", "\%i6", "\%i7", + + "\%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" XXX removed due to 31-element class limit */ + + "\%f0", "\%f2", "\%f4", "\%f6", "\%f8", "\%f10", "\%f12", "\%f14", + "\%f16", "\%f18", "\%f20", "\%f22", "\%f24", "\%f26", "\%f28", "\%f30", + + "\%sp", "\%fp", +}; + +void +deflab(int label) +{ + printf(LABFMT ":\n", label); +} + +void +prologue(struct interpass_prolog *ipp) +{ + int i, stack; + + stack = V9RESERVE + V9STEP(p2maxautooff); + + for (i = ipp->ipp_regs[0]; i; i >>= 1) + if (i & 1) + stack += 16; + + /* TODO printf("\t.proc %d\n"); */ + if (SIMM13(stack)) + printf("\tsave %%sp,-%d,%%sp\n", stack); + else { + printf("\tsetx -%d,%%g4,%%g1\n", stack); + printf("\tsave %%sp,%%g1,%%sp\n"); + } +} + +void +eoftn(struct interpass_prolog *ipp) +{ + printf("\tret\n"); + printf("\trestore\n"); + printf("\t.type %s,#function\n", ipp->ipp_name); + printf("\t.size %s,(.-%s)\n", ipp->ipp_name, ipp->ipp_name); +} + +void +hopcode(int f, int o) +{ + char *str; + + switch (o) { + case EQ: str = "brz"; break; + case NE: str = "brnz"; break; + case ULE: + case LE: str = "brlez"; break; + case ULT: + case LT: str = "brlz"; break; + case UGE: + case GE: str = "brgez"; break; + case UGT: + case GT: str = "brgz"; break; + case PLUS: str = "add"; break; + case MINUS: str = "sub"; break; + case AND: str = "and"; break; + case OR: str = "or"; break; + case ER: str = "xor"; break; + default: + comperr("unknown hopcode: %d (with %c)", o, f); + return; + } + + printf("%s%c", str, f); +} + +int +tlen(NODE *p) +{ + switch (p->n_type) { + case CHAR: + case UCHAR: + return 1; + case SHORT: + case USHORT: + return (SZSHORT / SZCHAR); + case FLOAT: + return (SZFLOAT / SZCHAR); + case DOUBLE: + return (SZDOUBLE / SZCHAR); + case INT: + case UNSIGNED: + return (SZINT / SZCHAR); + case LONG: + case ULONG: + case LONGLONG: + case ULONGLONG: + return SZLONGLONG / SZCHAR; + default: + if (!ISPTR(p->n_type)) + comperr("tlen type unknown: %d"); + return SZPOINT(p->n_type) / SZCHAR; + } +} + +void +zzzcode(NODE * p, int c) +{ + char *str; + NODE *l, *r; + int sz; + l = p->n_left; + r = p->n_right; + + switch (c) { + + case 'A': /* Add const. */ + if (ISPTR(l->n_type) && l->n_rval == FP) + r->n_lval += V9BIAS; + + if (SIMM13(r->n_lval)) + expand(p, 0, "\tadd AL,AR,A1\t\t! add const\n"); + else + expand(p, 0, "\tsetx AR,A3,A2\t\t! add const\n" + "\tadd AL,A2,A1\n"); + break; + case 'B': /* Subtract const. */ + if (ISPTR(l->n_type) && l->n_rval == FP) + r->n_lval -= V9BIAS; + + if (SIMM13(r->n_lval)) + expand(p, 0, "\tsub AL,AR,A1\t\t! subtract const\n"); + else + expand(p, 0, "\tsetx AR,A3,A2\t\t! subtract const\n" + "\tsub AL,A2,A1\n"); + break; + case 'C': /* Load constant to register. */ + if (ISPTR(p->n_type)) + expand(p, 0, + "\tsethi %h44(AL),A1\t\t! load label\n" + "\tor A1,%m44(AL),A1\n" + "\tsllx A1,12,A1\n" + "\tor A1,%l44(AL),A1\n"); + else if (SIMM13(p->n_lval)) + expand(p, 0, "\tor %g0,AL,A1\t\t\t! load const\n"); + else + expand(p, 0, "\tsetx AL,A2,A1\t\t! load const\n"); + break; + case 'F': /* Floating-point comparison, cf. hopcode(). */ + switch (p->n_op) { + case EQ: str = "fbe"; break; + case NE: str = "fbne"; break; + case ULE: + case LE: str = "fbule"; break; + case ULT: + case LT: str = "fbul"; break; + case UGE: + case GE: str = "fbuge"; break; + case UGT: + case GT: str = "fbug"; break; + /* XXX + case PLUS: str = "add"; break; + case MINUS: str = "sub"; break; + case AND: str = "and"; break; + case OR: str = "or"; break; + case ER: str = "xor"; break;*/ + default: + comperr("unknown float code: %d", p->n_op); + return; + } + printf(str); + break; + + case 'Q': /* Structure assignment. */ + /* TODO Check if p->n_stsize is small and use a few ldx's + to move the struct instead of memcpy. The equiv. + could be done on all the architectures. */ + sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + if (l->n_rval != O0) + printf("\tmov %s,%s\n", rnames[l->n_rval], rnames[O0]); + if (SIMM13(sz)) + printf("\tor %%g0,%d,%%o2\n", sz); + else + printf("\tsetx %d,%%g1,%%o2\n", sz); + printf("\tcall memcpy\t\t\t! struct assign (dest, src, len)\n"); + printf("\tnop\n"); + break; + default: + cerror("unknown zzzcode call: %c", c); + } +} + +int +rewfld(NODE * p) +{ + return (1); +} + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + printf("XXX fldexpand called\n"); /* XXX */ + return 1; +} + +int +flshape(NODE * p) +{ + return SRREG; +} + +int +shtemp(NODE * p) +{ + return 0; +} + + +void +adrcon(CONSZ val) +{ +} + +void +conput(FILE * fp, NODE * p) +{ + if (p->n_op != ICON) { + comperr("conput got bad op: %s", copst(p->n_op)); + return; + } + + if (p->n_name[0] != '\0') { + fprintf(fp, "%s", p->n_name); + if (p->n_lval > 0) + fprintf(fp, "+"); + if (p->n_lval) + fprintf(fp, CONFMT, p->n_lval); + } else + fprintf(fp, CONFMT, p->n_lval); +} + +void +insput(NODE * p) +{ + comperr("insput"); +} + +void +upput(NODE *p, int size) +{ + comperr("upput"); +} + +void +adrput(FILE * io, NODE * p) +{ + int64_t off; + + if (p->n_op == FLD) { + printf("adrput a FLD\n"); + p = p->n_left; + } + + if (p->n_op == UMUL && p->n_right == 0) + p = p->n_left; + + off = p->n_lval; + + switch (p->n_op) { + case NAME: + if (p->n_name[0] != '\0') + fputs(p->n_name, io); + if (off > 0) + fprintf(io, "+"); + if (off != 0) + fprintf(io, CONFMT, (long long int)off); + return; + case OREG: + fprintf(io, "%s", rnames[p->n_rval]); + if (p->n_rval == FP) + off += V9BIAS; + if (p->n_rval == SP) + off += V9BIAS + V9RESERVE; + if (off > 0) + fprintf(io, "+"); + if (off) + fprintf(io, CONFMT, (CONSZ)off); + return; + case ICON: + /* addressable value of the constant */ + conput(io, p); + return; + case REG: + fputs(rnames[p->n_rval], io); + return; + case FUNARG: + /* We do something odd and store the stack offset in n_rval. */ + fprintf(io, "%d", V9BIAS + V9RESERVE + p->n_rval); + return; + default: + comperr("bad address, %s, node %p", copst(p->n_op), p); + return; + } +} + +void +cbgen(int o, int lab) +{ +} + +void +myreader(struct interpass * ipole) +{ +} + +void +mycanon(NODE * p) +{ +} + +void +myoptim(struct interpass * ipole) +{ +} + +void +rmove(int s, int d, TWORD t) +{ + printf("\t"); + + if (t == FLOAT) printf("fmovs"); + else if (t == DOUBLE) printf("fmovd"); + else printf("mov"); + + printf(" %s,%s\t\t\t! rmove()\n", rnames[s], rnames[d]); +} + +int +gclass(TWORD t) +{ + if (t == FLOAT) + return CLASSB; + if (t == DOUBLE) + return CLASSC; + return CLASSA; +} + +void +lastcall(NODE *p) +{ +} + +int +special(NODE *p, int shape) +{ + return SRNOPE; +} + +void mflags(char *str) +{ +} + +int +COLORMAP(int c, int *r) +{ + int num=0; + + switch (c) { + case CLASSA: + num += r[CLASSA]; + return num < 32; + case CLASSB: + num += r[CLASSB]; + num += 2*r[CLASSC]; + return num < 32;; + case CLASSC: + num += r[CLASSC]; + num += 2*r[CLASSB]; + return num < 17; + case CLASSD: + return 0; + default: + comperr("COLORMAP: unknown class: %d", c); + return 0; + } +} +/* + * Do something target-dependent for xasm arguments. + * Supposed to find target-specific constraints and rewrite them. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + return 0; +} diff --git a/lang/pcc/pcc/arch/sparc64/macdefs.h b/lang/pcc/pcc/arch/sparc64/macdefs.h new file mode 100644 index 000000000..7bc894619 --- /dev/null +++ b/lang/pcc/pcc/arch/sparc64/macdefs.h @@ -0,0 +1,266 @@ +/* $Id: macdefs.h,v 1.18 2016/03/05 15:53:04 ragge Exp $ */ + +/* + * Copyright (c) 2008 David Crawshaw + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +/* + * Many arithmetic instructions take 'reg_or_imm' in SPARCv9, where imm + * means we can use a signed 13-bit constant (simm13). This gives us a + * shortcut for small constants, instead of loading them into a register. + * Special handling is required because 13 bits lies between SSCON and SCON. + */ +#define SIMM13(val) (val < 4096 && val > -4097) + +/* + * The SPARCv9 ABI specifies a stack bias of 2047 bits. This means that the + * end of our call space is %fp+V9BIAS, working back towards %sp+V9BIAS+176. + */ +#define V9BIAS 2047 + +/* + * The ABI requires that every frame reserve 176 bits for saving registers + * in the case of a spill. The stack size must be 16-bit aligned. + */ +#define V9RESERVE 176 +#define V9STEP(x) ALIGN(x, 0xf) +#define ALIGN(x, y) ((x & y) ? (x + y) & ~y : x) + + +#define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +#define ARGINIT (7*8) /* XXX */ +#define AUTOINIT (0) + +/* Type sizes */ +#define SZCHAR 8 +#define SZBOOL 32 +#define SZINT 32 +#define SZFLOAT 32 +#define SZDOUBLE 64 +#define SZLDOUBLE 64 +#define SZLONG 64 +#define SZSHORT 16 +#define SZLONGLONG 64 +#define SZPOINT(t) 64 + +/* Type alignments */ +#define ALCHAR 8 +#define ALBOOL 32 +#define ALINT 32 +#define ALFLOAT 32 +#define ALDOUBLE 64 +#define ALLDOUBLE 64 +#define ALLONG 64 +#define ALLONGLONG 64 +#define ALSHORT 16 +#define ALPOINT 64 +#define ALSTRUCT 32 +#define ALSTACK 64 + +/* Min/max values. */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT -1 +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffff +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL +#define MIN_LONG MIN_LONGLONG +#define MAX_LONG MAX_LONGLONG +#define MAX_ULONG MAX_ULONGLONG + +#define BOOL_TYPE INT + +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; +typedef long long OFFSZ; + +#define CONFMT "%lld" +#define LABFMT "L%d" +#define STABLBL "LL%d" + +#define BACKAUTO /* Stack grows negatively for automatics. */ +#define BACKTEMP /* Stack grows negatively for temporaries. */ + +#undef FIELDOPS +#define TARGET_ENDIAN TARGET_BE + +#define BYTEOFF(x) ((x)&03) + +#define szty(t) ((ISPTR(t) || (t) == DOUBLE || \ + (t) == LONG || (t) == ULONG || \ + (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) + + +/* Register names. */ + +#define MAXREGS (31 + 31 + 16 + 2) +#define NUMCLASS 4 + +//define G0 -1 +#define G1 0 +#define G2 1 +#define G3 2 +#define G4 3 +#define G5 4 +#define G6 5 +#define G7 6 +#define O0 7 +#define O1 8 +#define O2 9 +#define O3 10 +#define O4 11 +#define O5 12 +#define O6 13 +#define O7 14 +#define L0 15 +#define L1 16 +#define L2 17 +#define L3 18 +#define L4 19 +#define L5 20 +#define L6 21 +#define L7 22 +#define I0 23 +#define I1 24 +#define I2 25 +#define I3 26 +#define I4 27 +#define I5 28 +#define I6 29 +#define I7 30 + +#define F0 31 +#define F1 32 +#define F2 33 +#define F3 34 +#define F4 35 +#define F5 36 +#define F6 37 +#define F7 38 +#define F8 39 +#define F9 40 +#define F10 41 +#define F11 42 +#define F12 43 +#define F13 44 +#define F14 45 +#define F15 46 +#define F16 47 +#define F17 48 +#define F18 49 +#define F19 50 +#define F20 51 +#define F21 52 +#define F22 53 +#define F23 54 +#define F24 55 +#define F25 56 +#define F26 57 +#define F27 58 +#define F28 59 +#define F29 60 +#define F30 61 +//define F31 XXX +#define D0 62 +#define D1 63 +#define D2 64 +#define D3 65 +#define D4 66 +#define D5 67 +#define D6 68 +#define D7 69 +#define D8 70 +#define D9 71 +#define D10 72 +#define D11 73 +#define D12 74 +#define D13 75 +#define D14 76 +#define D15 77 + +#define SP 78 +#define FP 79 + +#define FPREG FP + +#define RETREG(x) ((x)==DOUBLE ? D0 : (x)==FLOAT ? F1 : O0) +#define RETREG_PRE(x) ((x)==DOUBLE ? D0 : (x)==FLOAT ? F1 : I0) + +#define RSTATUS \ + /* global */ \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + /* out */ \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + /* local */ \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + /* in */ \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + /* 32-bit floating point */ \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, /*, SBREG */ \ + /* 64-bit floating point */ \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ + /* sp */ SDREG, \ + /* fp */ SDREG + +#define ROVERLAP \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ + { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ +/* 32-bit floating point */ \ + { D0, -1 }, { D0, -1 }, { D1, -1 }, { D1, -1 }, \ + { D2, -1 }, { D2, -1 }, { D3, -1 }, { D3, -1 }, \ + { D4, -1 }, { D4, -1 }, { D5, -1 }, { D5, -1 }, \ + { D6, -1 }, { D6, -1 }, { D7, -1 }, { D7, -1 }, \ + { D8, -1 }, { D8, -1 }, { D9, -1 }, { D9, -1 }, \ + { D10, -1 }, { D10, -1 }, { D11, -1 }, { D11, -1 }, \ + { D12, -1 }, { D12, -1 }, { D13, -1 }, { D13, -1 }, \ + { D14, -1 }, { D14, -1 }, { D15, -1 }, /* { D15, -1 }, */ \ +/* 64-bit floating point */ \ + { F0, F1, -1 }, { F2, F3, -1 }, { F4, F5, -1 }, \ + { F6, F7, -1 }, { F8, F9, -1 }, { F10, F11, -1 }, \ + { F12, F13, -1 }, { F14, F15, -1 }, { F16, F17, -1 }, \ + { F18, F19, -1 }, { F20, F21, -1 }, { F22, F23, -1 }, \ + { F24, F25, -1 }, { F26, F27, -1 }, { F28, F29, -1 }, \ + { F30, /* F31, */ -1 }, \ + { -1 }, \ + { -1 } + +#define GCLASS(x) (x <= I7 ? CLASSA : \ + (x <= F30 ? CLASSB : \ + (x <= D15 ? CLASSC : \ + (x == SP || x == FP ? CLASSD : 0)))) +#define PCLASS(p) (1 << gclass((p)->n_type)) +#define DECRA(x,y) (((x) >> (y*7)) & 127) +#define ENCRA(x,y) ((x) << (7+y*7)) +#define ENCRD(x) (x) + +int COLORMAP(int c, int *r); diff --git a/lang/pcc/pcc/arch/sparc64/order.c b/lang/pcc/pcc/arch/sparc64/order.c new file mode 100644 index 000000000..8a6916aa2 --- /dev/null +++ b/lang/pcc/pcc/arch/sparc64/order.c @@ -0,0 +1,117 @@ +/* $Id: order.c,v 1.7 2011/06/05 08:54:42 plunky Exp $ */ + +/* + * Copyright (c) 2008 David Crawshaw + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "pass2.h" + +/* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + return !SIMM13(off); +} + +/* + * Turn a UMUL-referenced node into OREG. + */ +void +offstar(NODE *p, int shape) +{ + if (x2debug) + printf("offstar(%p)\n", p); + + if (p->n_op == PLUS || p->n_op == MINUS) { + if (p->n_right->n_op == ICON && SIMM13(p->n_right->n_lval)) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + } + (void)geninsn(p, INAREG); +} + +void +myormake(NODE *q) +{ +} + +int +shumul(NODE *p, int shape) +{ + if (shape & SOREG) + return SROREG; + return SRNOPE; +} + +int +setbin(NODE *p) +{ + return 0; +} + +int +setasg(NODE *p, int cookie) +{ + return 0; +} + +int +setuni(NODE *p, int cookie) +{ + return 0; +} + +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + case STASG: { + static struct rspecial s[] = { + { NEVER, O0 }, + { NRIGHT, O1 }, + { NEVER, O2 }, + { 0 } + }; + return s; + } + } + + comperr("unknown nspecial %d: %s", q - table, q->cstring); + return 0; /* XXX */ +} + +int +setorder(NODE *p) +{ + return 0; +} + +int * +livecall(NODE *p) +{ + static int ret[] = { O0, O1, O2, O3, O4, O5, O6, O7, -1 }; + return ret; +} + +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/sparc64/table.c b/lang/pcc/pcc/arch/sparc64/table.c new file mode 100644 index 000000000..d6eb524e9 --- /dev/null +++ b/lang/pcc/pcc/arch/sparc64/table.c @@ -0,0 +1,965 @@ +/* $Id: table.c,v 1.29 2011/06/05 08:54:42 plunky Exp $ */ + +/* + * Copyright (c) 2008 David Crawshaw + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "pass2.h" + +#define TS64 TLONG|TLONGLONG +#define TU64 TULONG|TULONGLONG|TPOINT +#define T64 TS64|TU64 + +struct optab table[] = { + +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* empty */ + +{ PCONV, INAREG, + SAREG, T64|TINT, + SAREG, T64, + 0, RLEFT, + " ! convert between word and pointer\n", }, + +/* Conversions. */ + +{ SCONV, INAREG, + SAREG, T64|TUNSIGNED, + SAREG, TINT, + NAREG|NASL, RESC1, + " sra AL,0,A1 \t\t! (u)int64/32 -> (u)int32\n", }, + +{ SCONV, INAREG, + SAREG, T64|TINT|TUNSIGNED, + SAREG, TSHORT, + NAREG|NASL, RESC1, + " sll AL,16,A1 \t\t! (u)int64/32 -> int16\n" + " sra AL,16,A1\n" + " sra AL, 0,A1\n", }, + +{ SCONV, INAREG, + SAREG, T64|TINT|TUNSIGNED, + SAREG, TUSHORT, + NAREG|NASL, RESC1, + " sll AL,16,A1 \t\t! (u)int64/32 -> uint16\n" + " srl AL,16,A1\n", }, + +{ SCONV, INAREG, + SAREG, T64|TINT|TUNSIGNED|TSHORT|TUSHORT, + SAREG, TCHAR, + NAREG|NASL, RESC1, + " sll AL,24,A1 \t\t! (u)int64/32/16 -> int8\n" + " sra AL,24,A1\n" + " sra AL, 0,A1\n", }, + +{ SCONV, INAREG, + SAREG, T64|TINT|TUNSIGNED|TSHORT|TUSHORT, + SAREG, TUCHAR, + NAREG|NASL, RESC1, + " and AL,0xff,A1 \t\t! (u)int64/32/16 -> uint8\n", }, + +{ SCONV, INAREG, + SAREG, T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, /* TCHAR|TUCHAR added to handle char -> long (among others) */ + SAREG, T64, + 0, RLEFT, + " \t\t! (u)int64...8 -> (u)int64\n", }, + +{ SCONV, INAREG, + SAREG, TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG, TINT, + 0, RLEFT, + " \t\t! (u)int16/8 -> int32\n", }, + +{ SCONV, INAREG, + SAREG, T64|TINT|TSHORT|TCHAR, + SAREG, TUNSIGNED, + 0, RLEFT, + " srl AL, 0,A1 \t\t! int32/16/8 -> uint32\n", }, + +{ SCONV, INAREG, + SAREG, TUSHORT|TUCHAR, + SAREG, TUNSIGNED, + 0, RLEFT, + " \t\t! uint16/8 -> uint32\n", }, + +{ SCONV, INBREG, + SBREG, TINT|TUNSIGNED, + SBREG, TFLOAT, + NBREG|NASL, RESC1, + " fitos AL,A1 \t\t! (u)int32 -> float\n", }, + +{ SCONV, INBREG, + SBREG, T64, + SBREG, TFLOAT, + NBREG|NASL, RESC1, + " fxtos AL,A1 \t\t! (u)int64 -> float\n", }, + +{ SCONV, INCREG, + SCREG, TINT|TUNSIGNED, + SCREG, TDOUBLE, + NCREG|NASL, RESC1, + " fitod AL,A1 \t\t! (u)int32 -> double\n", }, + +{ SCONV, INCREG, + SCREG, T64, + SCREG, TDOUBLE, + NCREG|NASL, RESC1, + " fxtod AL,A1 \t\t! (u)int64 -> double\n", }, + + +/* Floating-point conversions must be stored and loaded. */ + +{ SCONV, INAREG, + SOREG, TFLOAT, + SAREG, TINT, + NAREG|(2*NBREG), RESC1, + " ld [AL],A2 \t\t! float -> int32\n" + " nop\n" + " fmovs A2,A3\n" + " fstoi A2,A2\n" + " st A2,[AL]\n" + " nop\n" + " ld [AL],A1\n" + " nop\n" + " st A3,[AL]\n" + " nop\n", }, + +{ SCONV, INAREG, + SOREG, TDOUBLE, + SAREG, TINT, + NAREG|(2*NCREG), RESC1, + " ld [AL],A2 \t\t! double -> int32\n" + " nop\n" + " fmovd A2,A3\n" + " fdtoi A2,A2\n" + " std A2,[AL]\n" + " nop\n" + " ldd [AL],A1\n" + " nop\n" + " std A3,[AL]\n" + " nop\n", }, + +{ SCONV, INBREG, + SOREG, T64|TUNSIGNED, + SBREG, TFLOAT, + NBREG, RESC1, + " ld [AL],A1 \t\t! int64 -> float\n" + " fxtos A1,A1\n", }, + +{ SCONV, INBREG, + SOREG, TINT|TSHORT|TCHAR, + SBREG, TFLOAT, + NBREG, RESC1, + " ld [AL],A1 \t\t! int32/16/8 -> float\n" + " fitos A1,A1\n", }, // XXX need 'lds', 'ldh', etc + +{ SCONV, INCREG, + SOREG, T64|TUNSIGNED, + SCREG, TDOUBLE, + NCREG, RESC1, + " ldd [AL],A1 \t\t! (u)int64 -> double\n" + " fxtod A1,A1\n", }, + +{ SCONV, INCREG, + SOREG, TINT|TSHORT|TCHAR, + SCREG, TDOUBLE, + NCREG, RESC1, + " ld [AL],A1 \t\t! int32/16/8 -> double\n" + " fitod A1,A1\n", }, // XXX need 'lds' 'ldh' 'ld', etc. + +{ SCONV, INBREG, + SCREG, TDOUBLE, + SBREG, TFLOAT, + NBREG, RESC1, + " fdtos AL,A1 \t\t! double -> float\n",}, + +{ SCONV, INCREG, + SBREG, TFLOAT, + SCREG, TDOUBLE, + NCREG, RESC1, + " fstod AL,A1 \t\t! float -> double\n",}, + +{ SCONV, INAREG, + SBREG, TFLOAT, + SAREG, TINT, + NAREG|NBREG, RESC1, + " fstoi AL,A2 \t\t! float -> int\n" + " st A2,[%fp+2047]\n" + " nop\n" + " ld [%fp+2047],A1\n" + " nop\n",}, + +{ SCONV, INAREG, + SCREG, TDOUBLE, + SAREG, TINT, + NAREG|NCREG, RESC1, + " fdtoi AL,A2 \t\t! double -> int\n" + " st A2,[%fp+2047]\n" + " nop\n" + " ld [%fp+2047],A1\n" + " nop\n",}, + + +/* Multiplication and division */ + +{ MUL, INAREG, + SAREG, TANY, + SAREG, TANY, + NAREG|NASR|NASL, RESC1, + " mulx AL,AR,A1 ! multiply\n", }, + +{ MUL, INBREG, + SBREG, TFLOAT, + SBREG, TFLOAT, + NBREG|NBSR|NBSL, RESC1, + " fmuls AL,AR,A1 ! multiply float\n", }, + +{ MUL, INCREG, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG|NCSR|NCSL, RESC1, + " fmuld AL,AR,A1 ! multiply double\n", }, + +{ DIV, INAREG, + SAREG, TUNSIGNED|TUSHORT|TUCHAR|TU64, + SAREG, TUNSIGNED|TUSHORT|TUCHAR|TU64, + NAREG|NASR|NASL, RESC1, + " udivx AL,AR,A1 ! unsigned division\n", }, + +{ DIV, INAREG, + SAREG, TINT|TSHORT|TCHAR|TS64, + SAREG, TINT|TSHORT|TCHAR|TS64, + NAREG|NASR|NASL, RESC1, + " sdivx AL,AR,A1 ! signed division\n", }, + +{ DIV, INBREG, + SBREG, TFLOAT, + SBREG, TFLOAT, + NBREG|NBSR|NBSL, RESC1, + " fdivs AL,AR,A1 ! divide float\n", }, + +{ DIV, INCREG, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG|NCSR|NCSL, RESC1, + " fdivd AL,AR,A1 ! divide double\n", }, + +{ MOD, INAREG, + SAREG, TUNSIGNED|TUSHORT|TUCHAR|TU64, + SAREG, TUNSIGNED|TUSHORT|TUCHAR|TU64, + NAREG, RESC1, + " udivx AL,AR,A1 ! unsigned modulo\n" + " mulx A1,AR,A1\n" + " sub AL,A1,A1\n", }, + +{ MOD, INAREG, + SAREG, TINT|TSHORT|TCHAR|TS64, + SAREG, TINT|TSHORT|TCHAR|TS64, + NAREG, RESC1, + " sdivx AL,AR,A1 ! signed modulo\n" + " mulx A1,AR,A1\n" + " sub AL,A1,A1\n", }, + +{ PLUS, INAREG, + SAREG, TANY, + SAREG, TANY, + NAREG|NASL, RESC1, + " add AL,AR,A1\n", }, + +{ PLUS, INBREG, + SBREG, TFLOAT, + SBREG, TFLOAT, + NBREG|NBSL, RESC1, + " fadds AL,AR,A1\n", }, + +{ PLUS, INCREG, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG|NCSL, RESC1, + " faddd AL,AR,A1\n", }, + +{ PLUS, INAREG, + SAREG, TANY, + SCON, TANY, + (3*NAREG), RESC1, + "ZA", }, + +{ MINUS, INAREG, + SAREG, TANY, + SAREG, TANY, + NAREG|NASL, RESC1, + " sub AL,AR,A1\n", }, + +{ MINUS, INBREG, + SBREG, TANY, + SBREG, TANY, + NBREG|NBSL|NBSR, RESC1, + " fsubs AL,AR,A1\n", }, + +{ MINUS, INCREG, + SCREG, TANY, + SCREG, TANY, + NCREG|NCSL|NBSR, RESC1, + " fsubd AL,AR,A1\n", }, + +{ MINUS, INAREG, + SAREG, TANY, + SCON, TANY, + (3*NAREG), RESC1, + "ZB", }, + +{ UMINUS, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, + " sub %g0,AL,A1\n", }, + +{ UMINUS, INBREG, + SBREG, TANY, + SANY, TANY, + NBREG|NBSL, RESC1, + " fsubs %g0,AL,A1\n", }, + +{ UMINUS, INCREG, + SCREG, TANY, + SANY, TANY, + NCREG|NCSL, RESC1, + " fsubd %g0,AL,A1\n", }, + +/* Shifts */ + +{ RS, INAREG, + SAREG, TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG|SCON, TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " srl AL,AR,A1 ! shift right\n", }, + +{ RS, INAREG, + SAREG, T64, + SAREG|SCON, T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " srlx AL,AR,A1 ! shift right\n", }, + +{ LS, INAREG, + SAREG, TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, + SAREG|SCON, TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " sll AL,AR,A1 ! shift left\n", }, + +{ LS, INAREG, + SAREG, T64, + SAREG|SCON, TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " sllx AL,AR,A1 ! shift left\n", }, + +{ COMPL, INAREG, + SAREG, TANY, + SANY, TANY, + NAREG|NASL, RESC1, + " not AL,A1 ! complement\n", }, + +/* Assignments */ + +{ ASSIGN, FOREFF|INAREG, /* FIXME: Remove [,] here and add them in adrput instead. */ + SAREG|SOREG, TINT|TUNSIGNED, + SAREG, TINT|TUNSIGNED, + 0, RDEST, + " stw AR,[AL] ! store (u)int32\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + 0, RDEST, + " sth AR,[AL] ! store (u)int16\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + 0, RDEST, + " stb AR,[AL] ! store (u)int8\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SOREG, T64, + SAREG, T64, + 0, RDEST, + " stx AR,[AL] ! store (u)int64\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG, TFLOAT, + SBREG, TFLOAT, + 0, RDEST, + " st AR,[AL] ! store float\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INBREG, + SOREG, TINT, + SBREG, TINT, + 0, RDEST, + " st AR,[AL] ! store int from fp address\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INCREG, + SOREG, TDOUBLE, + SCREG, TDOUBLE, + 0, RDEST, + " std AR,[AL] ! store double\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INCREG, + SOREG, TINT, + SCREG, TINT, + 0, RDEST, + " st AR,[AL] ! store int from fp address\n" + " nop\n", }, + + +{ ASSIGN, FOREFF|INAREG, + SNAME, TINT|TUNSIGNED, + SAREG, TINT|TUNSIGNED, + NAREG, RDEST, + " sethi %h44(AL),A1 \t! store (u)int32 into sname\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " stw AR,[A1+%l44(AL)]\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SNAME, TSHORT|TUSHORT, + SAREG, TSHORT|TUSHORT, + NAREG, RDEST, + " sethi %h44(AL),A1 \t! store (u)int16 into sname\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " sth AR,[A1+%l44(AL)]\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SNAME, TCHAR|TUCHAR, + SAREG, TCHAR|TUCHAR, + NAREG, RDEST, + " sethi %h44(AL),A1 \t! store (u)int8 into sname\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " stb AR,[A1+%l44(AL)]\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SNAME, T64, + SAREG, T64, + NAREG, RDEST, + " sethi %h44(AL),A1 \t! store (u)int64 into sname\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " stx AR,[A1+%l44(AL)]\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INBREG, + SNAME, TFLOAT|TINT, + SBREG, TFLOAT|TINT, + NAREG, RDEST, + " sethi %h44(AL),A1 \t! store float into sname\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " st AR,[A1+%l44(AL)]\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INCREG, + SNAME, TDOUBLE, + SCREG, TDOUBLE, + NAREG, RDEST, + " sethi %h44(AL),A1 \t! store double into sname\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " std AR,[A1+%l44(AL)]\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INCREG, + SNAME, TINT, + SCREG, TINT, + NAREG, RDEST, + " sethi %h44(AL),A1 \t! store int into sname\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " st AR,[A1+%l44(AL)]\n" + " nop\n", }, + +{ ASSIGN, FOREFF|INAREG, + SAREG, TANY, + SAREG, TANY, + 0, RDEST, + " mov AR,AL ! register move\n", }, + +{ ASSIGN, FOREFF|INBREG, + SBREG, TANY, + SBREG, TANY, + 0, RDEST, + " fmovs AR,AL ! move float\n", }, + +{ ASSIGN, FOREFF|INCREG, + SCREG, TANY, + SCREG, TANY, + 0, RDEST, + " fmovd AR,AL ! move double\n", }, + +/* Structure assignment. */ + +{ STASG, INAREG|FOREFF, + SOREG|SNAME, TANY, + SAREG, TPTRTO|TANY, + NSPECIAL, RDEST, + "ZQ", }, + +/* Comparisons. */ + +{ EQ, FORCC, + SAREG, TANY, + SAREG, TANY, + 0, RESCC, + " cmp AL,AR ! eq\n" + " be LC\n" + " nop\n", }, + +{ NE, FORCC, + SAREG, TANY, + SAREG, TANY, + 0, RESCC, + " cmp AL,AR ! ne\n" + " bne LC\n" + " nop\n", }, + +{ OPLOG, FORCC, + SAREG, TANY, + SZERO, TANY, + 0, RESCC, + " O AL,LC\n" + " nop\n", }, + +{ OPLOG, FORCC, + SAREG, TANY, + SAREG, TANY, + NAREG|NASL, RESCC, + " sub AL,AR,A1 ! oplog\n" + " O A1,LC\n" + " nop\n", }, + +{ OPLOG, FORCC, + SAREG, TANY, + SCCON, TANY, + NAREG|NASL, RESCC, + " sub AL,AR,A1 ! oplog sccon\n" + " O A1,LC\n" + " nop\n", }, + +{ OPLOG, FORCC, + SBREG, TFLOAT, + SBREG, TFLOAT, + NBREG, RESCC, + " fcmps AL,AR ! oplog float\n" + " ZF LC\n", }, + +{ OPLOG, FORCC, + SOREG, TFLOAT, + SBREG, TFLOAT, + NBREG, RESCC, + " ld [AL], A1 ! oplog float oreg\n" + " nop\n" + " fcmps A1,AR\n" + " ZF LC\n", }, + +{ OPLOG, FORCC, + SCREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESCC, + " fcmpd AL,AR ! oplog double\n" + " ZF LC\n", }, + +{ OPLOG, FORCC, + SOREG, TDOUBLE, + SCREG, TDOUBLE, + NCREG, RESCC, + " ldd [AL], A1 ! oplog double oreg\n" + " nop\n" + " fcmpd A1,AR\n" + " ZF LC\n", }, + + +/* Load constants to register. */ + +{ OPLTYPE, INAREG, + SCON, TANY, + SNAME, T64, + NAREG, RESC1, + " sethi %h44(AL),A1\t ! load const (u)int64 to reg\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " ldx [A1+%l44(AL)],A1\n" + " nop\n", }, +{ OPLTYPE, INAREG, + SCON, TANY, + SNAME, TINT, + NAREG, RESC1, + " sethi %h44(AL),A1\t ! load const int32 to reg\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " ldsw [A1+%l44(AL)],A1\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SCON, TANY, + SNAME, TUNSIGNED, + NAREG, RESC1, + " sethi %h44(AL),A1\t! load const uint32 to reg\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " lduw [A1+%l44(AL)],A1\n" + " nop\n", }, +{ OPLTYPE, INAREG, + SCON, TANY, + SNAME, TSHORT, + NAREG, RESC1, + " sethi %h44(AL),A1\t! load const int16 to reg\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " ldsh [A1+%l44(AL)],A1\n" + " nop\n", }, +{ OPLTYPE, INAREG, + SCON, TANY, + SNAME, TUSHORT, + NAREG, RESC1, + " sethi %h44(AL),A1\t ! load const uint16 to reg\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " lduh [A1+%l44(AL)],A1\n" + " nop\n", }, +{ OPLTYPE, INAREG, + SCON, TANY, + SNAME, TCHAR, + NAREG, RESC1, + " sethi %h44(AL),A1\t\t! load const int8 to reg\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " ldsb [A1+%l44(AL)],A1\n" + " nop\n", }, +{ OPLTYPE, INAREG, + SCON, TANY, + SNAME, TUCHAR, + NAREG, RESC1, + " sethi %h44(AL),A1\t! load const uint8 to reg\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " ldub [A1+%l44(AL)],A1\n" + " nop\n", }, + +{ OPLTYPE, INBREG, + SBREG, TANY, + SNAME, TANY, + NAREG|NBREG, RESC2, + " sethi %h44(AL),A1\t\t! load const to fp reg\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " ld [A1+%l44(AL)],A2\n" + " nop\n", }, + +{ OPLTYPE, INCREG, + SCREG, TANY, + SNAME, TANY, + NAREG|NCREG, RESC2, + " sethi %h44(AL),A1\t\t! load const to fp reg\n" + " or A1,%m44(AL),A1\n" + " sllx A1,12,A1\n" + " ldd [A1+%l44(AL)],A2\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SCON, TANY, + (2*NAREG), RESC1, + "ZC" }, + +/* Convert LTYPE to reg. */ + +{ OPLTYPE, INAREG, + SAREG, TANY, + SOREG, TCHAR, + NAREG, RESC1, + " ldsb [AL],A1 ! load int8 to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SAREG, TANY, + SOREG, TUCHAR, + NAREG, RESC1, + " ldub [AL],A1 ! load uint8 to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SAREG, TANY, + SOREG, TSHORT, + NAREG, RESC1, + " ldsh [AL],A1 ! load int16 to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SAREG, TANY, + SOREG, TUSHORT, + NAREG, RESC1, + " lduh [AL],A1 ! load uint16 to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SAREG, TANY, + SOREG, TINT, + NAREG, RESC1, + " ldsw [AL],A1 ! load int32 to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SAREG, TANY, + SOREG, TUNSIGNED, + NAREG, RESC1, + " lduw [AL],A1 ! load uint32 to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SAREG, TANY, + SOREG, T64, + NAREG, RESC1, + " ldx [AL],A1 ! load (u)int64 to reg\n" + " nop\n", }, + +{ OPLTYPE, INAREG, + SANY, TANY, + SZERO, TANY, + NAREG, RESC1, + " mov \%g0,A1\t ! load 0 to reg\n", }, + +{ OPLTYPE, INBREG, + SBREG, TFLOAT, + SOREG, TFLOAT, + NBREG, RESC1, + " ld [AL],A1 ! load float to reg\n" + " nop\n", }, + +{ OPLTYPE, INCREG, + SCREG, TDOUBLE, + SOREG, TDOUBLE, + NCREG, RESC1, + " ldd [AL],A1 ! load double to reg\n" + " nop\n", }, + +/* Jumps. */ + +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " call LL ! goto LL\n" + " nop\n", }, + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " call CL ! void CL()\n" + " nop\n", }, + +{ UCALL, INAREG, + SCON, TANY, + SAREG, TANY, + NAREG, RESC1, + " call CL ! = CL()\n" + " nop\n", }, + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " call CL ! void CL(constant)\n" + " nop\n", }, + +{ CALL, INAREG, + SCON, TANY, + SAREG, TANY, + NAREG, RESC1, + " call CL ! = CL(constant)\n" + " nop\n", }, + +{ CALL, INBREG, + SCON, TANY, + SBREG, TFLOAT, + NBREG, RESC1, + " call CL ! = CL(constant)\n" + " nop\n", }, + +{ CALL, INCREG, + SCON, TANY, + SCREG, TDOUBLE, + NCREG, RESC1, + " call CL ! = CL(constant)\n" + " nop\n", }, + +{ CALL, INAREG, + SAREG, TANY, + SAREG, TANY, + NAREG, RESC1, + " call AL ! = AL(args)\n" + " nop\n", }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call AL ! void AL(args)\n" + " nop\n", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, + " call AL ! (*AL)()\n" + " nop\n", }, + +{ UCALL, INAREG, + SAREG, TANY, + SAREG, TANY, + NAREG, RESC1, + " call AL ! = (*AL)()\n" + " nop\n", }, + +{ CALL, INAREG, + SAREG, TANY, + SAREG, TANY, + NAREG, RESC1, + " call AL ! = (*AL)(args)\n" + " nop\n", }, + +/* Function arguments. */ + +{ FUNARG, FOREFF, + SAREG, T64, + SANY, TANY, + 0, 0, + " stx AL,[%sp+AR] \t! save func arg to stack\n" + " nop\n", }, + +{ FUNARG, FOREFF, + SAREG, TINT|TUNSIGNED, + SANY, TANY, + 0, 0, + " stw AL,[%sp+AR] \t! save func arg to stack\n" + " nop\n", }, + +{ FUNARG, FOREFF, + SAREG, TSHORT|TUSHORT, + SANY, TANY, + 0, 0, + " sth AL,[%sp+AR] \t! save func arg to stack\n" + " nop\n", }, + +{ FUNARG, FOREFF, + SAREG, TCHAR|TUCHAR, + SANY, TANY, + 0, 0, + " stb AL,[%sp+AR] \t! save func arg to stack\n" + " nop\n", }, + +{ FUNARG, FOREFF, + SBREG, TFLOAT, + SANY, TANY, + 0, 0, + " st AL,[%sp+AR] \t! save func arg to stack\n" + " nop\n", }, + +{ FUNARG, FOREFF, + SCREG, TDOUBLE, + SANY, TANY, + 0, 0, + " std AL,[%sp+AR] \t! save func arg to stack\n" + " nop\n", }, + + +/* Indirection. */ + +{ OPSIMP, INAREG, + SAREG, TANY, + SAREG, TANY, + NAREG|NASR|NASL, RESC1, + " O AL,AR,A1\n", }, + +{ UMUL, INAREG, + SAREG, T64, + SOREG, T64, + NAREG, RESC1, + " ldx [AL],A1 ! (u)int64 load\n" + " nop\n", }, +{ UMUL, INAREG, + SAREG, TINT, + SOREG, TINT, + NAREG, RESC1, + " ldsw [AL],A1 ! int32 load\n" + " nop\n", }, +{ UMUL, INAREG, + SAREG, TUNSIGNED, + SOREG, TUNSIGNED, + NAREG, RESC1, + " lduw [AL],A1 ! uint32 load\n" + " nop\n", }, +{ UMUL, INAREG, + SAREG, TCHAR, + SOREG, TCHAR, + NAREG, RESC1, + " ldsb [AL],A1 ! int8 load\n" + " nop\n", }, +{ UMUL, INAREG, + SAREG, TUCHAR, + SOREG, TUCHAR, + NAREG, RESC1, + " ldub [AL],A1 ! uint8 load\n" + " nop\n", }, +{ UMUL, INAREG, + SAREG, TSHORT, + SOREG, TSHORT, + NAREG, RESC1, + " ldsh [AL],A1 ! int16 load\n" + " nop\n", }, +{ UMUL, INAREG, + SAREG, TUSHORT, + SOREG, TUSHORT, + NAREG, RESC1, + " lduh [AL],A1 ! uint16 load\n" + " nop\n", }, + +{ UMUL, INBREG, + SAREG, TFLOAT, + SOREG, TFLOAT, + NBREG, RESC1, + " ld [AL],A1 ! load float\n" + " nop\n", }, + +{ UMUL, INCREG, + SAREG, TDOUBLE, + SOREG, TDOUBLE, + NCREG, RESC1, + " ldd [AL],A1 ! load double\n" + " nop\n", }, + +{ FREE,FREE,FREE,FREE,FREE,FREE,FREE,FREE, "ERR: printing free op\n" }, + +}; + +int tablesize = sizeof(table)/sizeof(table[0]); diff --git a/lang/pcc/pcc/arch/vax/code.c b/lang/pcc/pcc/arch/vax/code.c new file mode 100644 index 000000000..f2e715d02 --- /dev/null +++ b/lang/pcc/pcc/arch/vax/code.c @@ -0,0 +1,488 @@ +/* $Id: code.c,v 1.27 2015/10/12 18:07:13 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "pass1.h" + +#ifndef LANG_CXX +#define NODE P1ND +#undef NIL +#define NIL NULL +#define tfree p1tfree +#define talloc p1alloc +#define ccopy p1tcopy +#endif + +/* + * Print out assembler segment name. + */ +void +setseg(int seg, char *name) +{ + switch (seg) { + case PROG: name = ".text"; break; + + case DATA: + case LDATA: name = ".data"; break; + + case STRNG: + case RDATA: name = ".section .rodata"; break; + + case UDATA: break; + + case DTORS: + name = ".section .dtors,\"aw\",@progbits"; + break; + case CTORS: + name = ".section .ctors,\"aw\",@progbits"; + break; + + case TLSDATA: + case TLSUDATA: + uerror("FIXME: unsupported segment %d", seg); + break; + + case PICRDATA: + name = ".section .data.rel.ro.local,\"aw\",@progbits"; + break; + + case PICDATA: + name = ".section .data.rel,\"aw\",@progbits"; + break; + case PICLDATA: + name = ".section .data.rel.local,\"aw\",@progbits"; + break; + + case NMSEG: + printf("\t.section %s,\"a%c\",@progbits\n", name, + cftnsp ? 'x' : 'w'); + return; + } + printf("\t%s\n", name); +} + +/* + * Define everything needed to print out some data (or text). + * This means segment, alignment, visibility, etc. + */ +void +defloc(struct symtab *sp) +{ + char *name; + + name = getexname(sp); + + if (sp->sclass == EXTDEF) { + printf("\t.globl %s\n", name); + if (ISFTN(sp->stype)) { + printf("\t.type %s,@function\n", name); + } else { + printf("\t.type %s,@object\n", name); + printf("\t.size %s,%d\n", name, + (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR); + } + } + if (sp->slevel == 0) + printf("%s:\n", name); + else + printf(LABFMT ":\n", sp->soffset); +} + +static int strtemp; + +void +efcode(void) +{ + TWORD t; + NODE *p, *q; + + /* code for the end of a function */ + if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) + return; + + t = PTR+BTYPE(cftnsp->stype); + /* Create struct assignment */ + q = tempnode(strtemp, t, 0, cftnsp->sap); + q = buildtree(UMUL, q, NIL); + p = block(REG, NIL, NIL, t, 0, cftnsp->sap); + regno(p) = R0; + p = buildtree(UMUL, p, NIL); + p = buildtree(ASSIGN, q, p); + ecomp(p); + + /* put hidden arg in r0 on return */ + q = tempnode(strtemp, INT, 0, 0); + p = block(REG, NIL, NIL, INT, 0, 0); + regno(p) = R0; + ecomp(buildtree(ASSIGN, p, q)); +} + +void +bfcode(struct symtab **sp, int n) +{ + struct symtab *sp2; + NODE *p, *q; + int i, argbase, sz; + + if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { + /* Move return address into temporary */ + p = tempnode(0, INT, 0, 0); + strtemp = regno(p); + q = block(REG, 0, 0, INT, 0, 0); + regno(q) = R1; + ecomp(buildtree(ASSIGN, p, q)); + } + + /* correct arg alignment XXX should be done somewhere else */ + argbase = ARGINIT; + for (i = 0; i < n; i++) { + sp2 = sp[i]; + sz = tsize(sp2->stype, sp2->sdf, sp2->sap); + + SETOFF(sz, SZINT); + sp2->soffset = argbase; + argbase += sz; + } + + if (xtemps == 0) + return; + + /* put arguments in temporaries */ + for (i = 0; i < n; i++) { + if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY || + cisreg(sp[i]->stype) == 0) + continue; + if (cqual(sp[i]->stype, sp[i]->squal) & VOL) + continue; + sp2 = sp[i]; + p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap); + p = buildtree(ASSIGN, p, nametree(sp2)); + sp[i]->soffset = regno(p->n_left); + sp[i]->sflags |= STNODE; + ecomp(p); + } + +} + +void +ejobcode(int flag) +{ + /* called just before final exit */ + /* flag is 1 if errors, 0 if none */ +} + +void +bjobcode(void) +{ + astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; + astypnames[SHORT] = astypnames[USHORT] = "\t.word"; +} + +#if 0 +aobeg(void) +{ + /* called before removing automatics from stab */ +} + +aocode(struct symtab *p) +{ + /* called when automatic p removed from stab */ +} + +aoend(void) +{ + /* called after removing all automatics from stab */ +} +#endif + +void +fldty(struct symtab *p) +{ + /* fix up type of field p */ +} + +/* + * XXX - fix genswitch. + */ +int +mygenswitch(int num, TWORD type, struct swents **p, int n) +{ + return 0; +} + +#ifdef notyet +struct sw heapsw[SWITSZ]; /* heap for switches */ + +genswitch(register struct sw *p, int n) +{ + /* p points to an array of structures, each consisting + of a constant value and a label. + The first is >=0 if there is a default label; + its value is the label number + The entries p[1] to p[n] are the nontrivial cases + */ + register i; + register CONSZ j, range; + register dlab, swlab; + + range = p[n].sval-p[1].sval; + + if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ + + swlab = getlab(); + dlab = p->slab >= 0 ? p->slab : getlab(); + + /* already in r0 */ + printf(" casel r0,$%ld,$%ld\n", p[1].sval, range); + deflab1(swlab); + for( i=1,j=p[1].sval; i<=n; j++) { + printf(" .word " LABFMT "-" LABFMT "\n", + (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), + swlab); + } + + if( p->slab >= 0 ) branch( dlab ); + else deflab1(dlab); + return; + + } + + if( n>8 ) { /* heap switch */ + + heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); + makeheap(p, n, 1); /* build heap */ + + walkheap(1, n); /* produce code */ + + if( p->slab >= 0 ) + branch( dlab ); + else + deflab1(dlab); + return; + } + + /* debugging code */ + + /* out for the moment + if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); + */ + + /* simple switch code */ + + for( i=1; i<=n; ++i ){ + /* already in r0 */ + + printf( " cmpl r0,$" ); + printf( CONFMT, p[i].sval ); + printf( "\n jeql " LBLFMT "\n", p[i].slab ); + } + + if( p->slab>=0 ) branch( p->slab ); +} + +makeheap(register struct sw *p, int m, int n) +{ + register int q; + + q = select(m); + heapsw[n] = p[q]; + if( q>1 ) makeheap(p, q-1, 2*n); + if( q m ) break; + l = ((k = i/2 - 1) + 1)/2; + return( l + (m-k < l ? m-k : l)); +} + +walkheap(int start, int limit) +{ + int label; + + if( start > limit ) return; + printf(" cmpl r0,$%d\n", heapsw[start].sval); + printf(" jeql " LBLFMT "\n", heapsw[start].slab); + if( (2*start) > limit ) { + printf(" jbr " LBLFMT "\n", heapsw[0].slab); + return; + } + if( (2*start+1) <= limit ) { + label = getlab(); + printf(" jgtr " LBLFMT "\n", label); + } else + printf(" jgtr " LBLFMT "\n", heapsw[0].slab); + walkheap( 2*start, limit); + if( (2*start+1) <= limit ) { + deflab1(label); + walkheap( 2*start+1, limit); + } +} +#endif + +/* + * Called with a function call with arguments as argument. + * This is done early in buildtree() and only done once. + */ +NODE * +funcode(NODE *p) +{ + NODE *r, *l; + + /* Fix function call arguments. On vax, just add funarg */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) { + if (r->n_right->n_op != STARG) { + r->n_right = intprom(r->n_right); + r->n_right = block(FUNARG, r->n_right, NIL, + r->n_right->n_type, r->n_right->n_df, + r->n_right->n_ap); + } + } + if (r->n_op != STARG) { + l = talloc(); + *l = *r; + r->n_op = FUNARG; + r->n_left = l; + r->n_left = intprom(r->n_left); + r->n_type = r->n_left->n_type; + } + return p; +} + +/* + * Generate the builtin code for FFS. + */ +NODE * +builtin_ffs(const struct bitable *bt, NODE *a) +{ + NODE *p, *q, *r; + + p = tempnode(0, bt->rt, 0, 0); + r = block(XARG, ccopy(p), NIL, INT, 0, 0); + r->n_name = "=&r"; + q = block(XARG, a, NIL, INT, 0, 0); + q->n_name = "g"; + q = block(CM, r, q, INT, 0, 0); + q = block(XASM, q, block(ICON, 0, 0, STRTY, 0, 0), INT, 0, 0); + q->n_name = "ffs $0,$32,%1,%0;bneq 1f;mnegl $1,%0;1:;incl %0"; + p = block(COMOP, q, p, bt->rt, 0, 0); + return p; +} + +NODE * +builtin_ffsl(const struct bitable *bt, NODE *a) +{ + return builtin_ffs(bt, a); +} + +NODE * +builtin_ffsll(const struct bitable *bt, NODE *a) +{ + cerror("builtin_ffsll unimplemented"); + return NIL; +} + +NODE * +builtin_return_address(const struct bitable *bt, NODE *a) +{ + NODE *f; + int v; + + if (a->n_op != ICON) + goto bad; + v =a->n_lval; + tfree(a); + + if (v != 0) { + werror("unsupported argument"); + return xbcon(0, NULL, VOID|PTR); + } + + f = block(REG, NIL, NIL, INCREF(PTR+CHAR), 0, 0); + regno(f) = FPREG; + f = block(UMUL, + block(PLUS, f, + bcon(16), INCREF(PTR+CHAR), 0, 0), NIL, PTR+CHAR, 0, 0); + f = makety(f, PTR+VOID, 0, 0, 0); + + return f; +bad: + uerror("bad argument to __builtin_return_address"); + return bcon(0); +} + +NODE * +builtin_frame_address(const struct bitable *bt, NODE *a) +{ + int nframes; + NODE *f; + + if (a->n_op != ICON) + goto bad; + + nframes = a->n_lval; + + tfree(a); + + f = block(REG, NIL, NIL, PTR+CHAR, 0, 0); + regno(f) = FPREG; + + while (nframes--) { + f = block(UMUL, + block(PLUS, f, + bcon(12), INCREF(PTR+CHAR), 0, 0), + NIL, PTR+CHAR, 0, 0); + f = makety(f, PTR+CHAR, 0, 0, 0); + } + + return f; +bad: + uerror("bad argument to __builtin_frame_address"); + return bcon(0); +} + +/* + * Return "canonical frame address". + */ +NODE * +builtin_cfa(const struct bitable *bt, NODE *a) +{ + uerror("missing builtin_cfa"); + return bcon(0); +} + diff --git a/lang/pcc/pcc/arch/vax/local.c b/lang/pcc/pcc/arch/vax/local.c new file mode 100644 index 000000000..189af241f --- /dev/null +++ b/lang/pcc/pcc/arch/vax/local.c @@ -0,0 +1,379 @@ +/* $Id: local.c,v 1.31 2015/11/13 11:38:47 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "pass1.h" + +#ifndef LANG_CXX +#define NODE P1ND +#undef NIL +#define NIL NULL +#define nfree p1nfree +#define fwalk p1fwalk +#endif + +static void r1arg(NODE *p, NODE *q); + + +/* this file contains code which is dependent on the target machine */ + +NODE * +clocal(p) NODE *p; { + + /* this is called to do local transformations on + an expression tree preparitory to its being + written out in intermediate code. + */ + + /* the major essential job is rewriting the + automatic variables and arguments in terms of + REG and OREG nodes */ + /* conversion ops which are not necessary are also clobbered here */ + /* in addition, any special features (such as rewriting + exclusive or) are easily handled here as well */ + + register struct symtab *q; + register NODE *r, *l; + register int o; + register int ml; + + +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal(%p)\n", p); + if (xdebug>1) + fwalk(p, eprint, 0); + } +#endif + + switch( o = p->n_op ){ + + case NAME: + if((q = p->n_sp) == 0 ) { /* already processed; ignore... */ + return(p); + } + switch( q->sclass ){ + + case REGISTER: + case AUTO: + case PARAM: + /* fake up a structure reference */ + r = block( REG, NIL, NIL, PTR+STRTY, 0, 0 ); + r->n_lval = 0; + r->n_rval = (q->sclass==PARAM?ARGREG:FPREG); + p = stref( block( STREF, r, p, 0, 0, 0 ) ); + break; + } + break; + + case FORCE: + p->n_op = ASSIGN; + p->n_right = p->n_left; + p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); + p->n_left->n_rval = p->n_left->n_type == BOOL ? + RETREG(CHAR) : RETREG(p->n_type); + break; + + case SCONV: + l = p->n_left; + ml = p->n_type; +#if 0 + if (ml == INT && l->n_type == UNSIGNED) { + p = nfree(p); + break; + } +#endif + if (l->n_op == ICON) { + if (l->n_sp == 0) { + p->n_type = UNSIGNED; + concast(l, p->n_type); + } else if (ml != INT && ml != UNSIGNED) + break; + l->n_type = ml; + l->n_ap = 0; + p = nfree(p); + break; + } + break; + + case STCALL: + /* see if we have been here before */ + for (r = p->n_right; r->n_op == CM; r = r->n_left) + ; + if (r->n_op == ASSIGN) + break; + + /* FALLTHROUGH */ + case USTCALL: + /* Allocate buffer on stack to bounce via */ + /* create fake symtab here */ + q = getsymtab("77fake", STEMP); + q->stype = BTYPE(p->n_type); + q->sdf = p->n_df; + q->sap = p->n_ap; + q->soffset = NOOFFSET; + q->sclass = AUTO; + oalloc(q, &autooff); + r1arg(p, buildtree(ADDROF, nametree(q), 0)); + break; + } +#ifdef PCC_DEBUG + if (xdebug) { + printf("clocal end(%p)\n", p); + if (xdebug>1) + fwalk(p, eprint, 0); + } +#endif + + return(p); +} + +/* + * Add R1 with the dest address as arg to a struct return call. + */ +static void +r1arg(NODE *p, NODE *q) +{ + NODE *r; + + r = block(REG, NIL, NIL, PTR|VOID, 0, 0); + regno(r) = R1; + r = buildtree(ASSIGN, r, q); + if (p->n_op == USTCALL) { + p->n_op = STCALL; + p->n_right = r; + } else if (p->n_right->n_op != CM) { + p->n_right = block(CM, r, p->n_right, INT, 0, 0); + } else { + for (q = p->n_right; q->n_left->n_op == CM; q = q->n_left) + ; + q->n_left = block(CM, r, q->n_left, INT, 0, 0); + } +} + +void +myp2tree(NODE *p) +{ + struct symtab *sp; + + if ((cdope(p->n_op) & CALLFLG) && p->n_left->n_op == ADDROF && + p->n_left->n_left->n_op == NAME) { + NODE *q = p->n_left->n_left; + nfree(p->n_left); + p->n_left = q; + q->n_op = ICON; + } + + if (p->n_op != FCON) + return; + + sp = tmpalloc(sizeof(struct symtab)); + sp->sclass = STATIC; + sp->sap = 0; + sp->slevel = 1; /* fake numeric label */ + sp->soffset = getlab(); + sp->sflags = 0; + sp->stype = p->n_type; + sp->squal = (CON >> TSHIFT); + + defloc(sp); + inval(0, tsize(sp->stype, sp->sdf, sp->sap), p); + + p->n_op = NAME; + p->n_lval = 0; + p->n_sp = sp; + +} + +/* + * Can we take & of a NAME? + */ +int +andable(NODE *p) +{ + /* for now, delay name reference to table, for PIC code generation */ + /* functions are called by name, convert they in myp2tree */ + return 0; +} + +/* is an automatic variable of type t OK for a register variable */ +int +cisreg(TWORD t) +{ + return(1); /* all are now */ +} + +/* + * Allocate off bits on the stack. p is a tree that when evaluated + * is the multiply count for off, t is a storeable node where to write + * the allocated address. + */ +void +spalloc(NODE *t, NODE *p, OFFSZ off) +{ + NODE *sp; + + p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ + + /* sub the size from sp */ + sp = block(REG, NIL, NIL, p->n_type, 0, 0); + sp->n_lval = 0; + sp->n_rval = STKREG; + ecomp(buildtree(MINUSEQ, sp, p)); + + /* save the address of sp */ + sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); + sp->n_lval = 0; + sp->n_rval = STKREG; + t->n_type = sp->n_type; + ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ + +} + +char * +exname( p ) char *p; { + /* make a name look like an external name in the local machine */ + /* vad is elf now */ + if (p == NULL) + return ""; + return( p ); + } + +/* map types which are not defined on the local machine */ +TWORD +ctype(TWORD type) { + switch( BTYPE(type) ){ + + case LONG: + MODTYPE(type,INT); + break; + + case ULONG: + MODTYPE(type,UNSIGNED); + break; + + case LDOUBLE: /* for now */ + MODTYPE(type,DOUBLE); + } + return( type ); + } + +void +calldec(NODE *p, NODE *q) +{ +} + +void +extdec(struct symtab *q) +{ +} + +/* make a common declaration for id, if reasonable */ +void +defzero(struct symtab *sp) +{ + int off, al; + char *name; + + name = getexname(sp); + off = tsize(sp->stype, sp->sdf, sp->sap); + SETOFF(off,SZCHAR); + off /= SZCHAR; + al = talign(sp->stype, sp->sap)/SZCHAR; + + if (sp->sclass == STATIC) { + if (sp->slevel == 0) + printf("\t.local %s\n", name); + else + printf("\t.local " LABFMT "\n", sp->soffset); + } + if (sp->slevel == 0) { + printf("\t.comm %s,0%o,%d\n", name, off, al); + } else + printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); +} + +/* + * print out a constant node, may be associated with a label. + * Do not free the node after use. + * off is bit offset from the beginning of the aggregate + * fsz is the number of bits this is referring to + * XXX - floating point constants may be wrong if cross-compiling. + */ +int +ninval(CONSZ off, int fsz, NODE *p) +{ + union { float f; double d; long double l; int i[3]; } u; + + switch (p->n_type) { + case LDOUBLE: + u.i[2] = 0; + u.l = (long double)((union flt *)p->n_dcon)->fp; + printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]); + break; + case DOUBLE: + u.d = (double)((union flt *)p->n_dcon)->fp; + printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]); + break; + case FLOAT: + u.f = (float)((union flt *)p->n_dcon)->fp; + printf("\t.long\t0x%x\n", u.i[0]); + break; + default: + return 0; + } + return 1; + +} +/* + * Give target the opportunity of handling pragmas. + */ +int +mypragma(char *str) +{ + return 0; +} + +/* + * Called when a identifier has been declared, to give target last word. + */ +void +fixdef(struct symtab *sp) +{ +} + +void +pass1_lastchance(struct interpass *ip) +{ +} diff --git a/lang/pcc/pcc/arch/vax/local2.c b/lang/pcc/pcc/arch/vax/local2.c new file mode 100644 index 000000000..3bfeaced6 --- /dev/null +++ b/lang/pcc/pcc/arch/vax/local2.c @@ -0,0 +1,1455 @@ +/* $Id: local2.c,v 1.42 2015/01/04 19:17:23 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "pass2.h" +# include "ctype.h" +/* a lot of the machine dependent parts of the second pass */ + +static void prtype(NODE *n); +static void acon(NODE *p); + +/* + * Print out the prolog assembler. + * addto and regoff are already calculated. + */ +void +prologue(struct interpass_prolog *ipp) +{ + printf(" .word 0x%llx\n", (unsigned long long)ipp->ipp_regs[0]); + if (p2maxautooff) + printf(" subl2 $%d,%%sp\n", p2maxautooff); + if (pflag) { + int i = getlab2(); + printf("\tmovab\t" LABFMT ",%%r0\n", i); + printf("\tjsb\t__mcount\n"); + printf("\t.data\n"); + printf("\t.align 2\n"); + printf(LABFMT ":\t.long\t0\n", i); + printf("\t.text\n"); + } +} + +/* + * Called after all instructions in a function are emitted. + * Generates code for epilog here. + */ +void +eoftn(struct interpass_prolog *ipp) +{ + if (ipp->ipp_ip.ip_lbl == 0) + return; /* no code needs to be generated */ + printf(" ret\n"); +} + +struct hoptab { int opmask; char * opstring; } ioptab[] = { + + { PLUS, "add", }, + { MINUS, "sub", }, + { MUL, "mul", }, + { DIV, "div", }, + { OR, "bis", }, + { ER, "xor", }, + { AND, "bic", }, + { -1, "" }, +}; + +void +hopcode( f, o ){ + /* output the appropriate string from the above table */ + + register struct hoptab *q; + + for( q = ioptab; q->opmask>=0; ++q ){ + if( q->opmask == o ){ + printf( "%s", q->opstring ); +/* tbl + if( f == 'F' ) printf( "e" ); + else if( f == 'D' ) printf( "d" ); + tbl */ +/* tbl */ + switch( f ) { + case 'L': + case 'W': + case 'B': + case 'D': + case 'F': + printf("%c", tolower(f)); + break; + + } +/* tbl */ + return; + } + } + cerror( "no hoptab for %s", opst[o] ); + } + +char * +rnames[] = { /* keyed to register number tokens */ + + "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", + "%r6", "%r7", "%r8", "%r9", "%r10", "%r11", + "%ap", "%fp", "%sp", "%pc", + /* The concatenated regs has the name of the lowest */ + "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", + "%r6", "%r7", "%r8", "%r9", "%r10" + }; + +int +tlen(NODE *p) +{ + switch(p->n_type) { + case CHAR: + case UCHAR: + return(1); + + case SHORT: + case USHORT: + return(2); + + case DOUBLE: + case LONGLONG: + case ULONGLONG: + return(8); + + default: + return(4); + } +} + +void +prtype(NODE *n) +{ + static char pt[] = { 0, 0, 'b', 'b', 'w', 'w', 'l', 'l', 0, 0, + 'q', 'q', 'f', 'd' }; + TWORD t = n->n_type; + + if (ISPTR(t)) + t = UNSIGNED; + + if (t > DOUBLE || pt[t] == 0) + comperr("prtype: bad type"); + putchar(pt[t]); +} + +/* + * Emit conversions as given by the following table. Dest is always reg, + * if it should be something else let peephole optimizer deal with it. + * This code ensures type correctness in 32-bit registers. + * XXX is that necessary? + * + * From To + * char uchar short ushort int uint ll ull float double + * char movb movb cvtbw cvtbw cvtbl cvtbl A A cvtbf cvtbd + * uchar movb movb movzbw movzbw movzbl movzbl B B G G + * short movb movb movw movw cvtwl cvtwl C(A) C(A) cvtwf cvtwd + * ushrt movb movb movw movw movzwl movzwl D(B) D(B) H H + * int movb movb movw movw movl movl E E cvtlf cvtld + * uint movb movb movw movw movl movl F F I I + * ll movb movb movw movw movl movl movq movq J K + * ull movb movb movw movw movl movl movq movq L M + * float cvtfb cvtfb cvtfw cvtfw cvtfl cvtfl N O movf cvtfd + * doubl cvtdb cvtdb cvtdw cvtdw cvtdl cvtdl P Q cvtdf movd + * + * A: cvtbl + sign extend + * B: movzbl + zero extend + * G: movzbw + cvtwX + * H: movzwl + cvtwX + * I: cvtld + addX + * J: call __floatdisf + * K: call __floatdidf + * L: xxx + call __floatdisf + * M: xxx + call __floatdidf + * N: call __fixsfdi + * O: call __fixunssfdi + * P: call __fixdfdi + * Q: call __fixunsdfdi + */ + +#define MVD 1 /* mov + dest type */ +#define CVT 2 /* cvt + src type + dst type */ +#define MVZ 3 /* movz + src type + dst type */ +#define CSE 4 /* cvt + src type + l + sign extend upper */ +#define MZE 5 /* movz + src type + l + zero extend upper */ +#define MLE 6 /* movl + sign extend upper */ +#define MLZ 7 /* movl + zero extend upper */ +#define MZC 8 /* movz + cvt */ + +static char scary[][10] = { + { MVD, MVD, CVT, CVT, CVT, CVT, CSE, CSE, CVT, CVT }, + { MVD, MVD, MVZ, MVZ, MVZ, MVZ, MZE, MZE, MZC, MZC }, + { MVD, MVD, MVD, MVD, CVT, CVT, CSE, CSE, CVT, CVT }, + { MVD, MVD, MVD, MVD, MVZ, MVZ, MZE, MZE, MZC, MZC }, + { MVD, MVD, MVD, MVD, MVD, MVD, MLE, MLE, CVT, CVT }, + { MVD, MVD, MVD, MVD, MVD, MVD, MLZ, MLZ, 'I', 'I' }, + { MVD, MVD, MVD, MVD, MVD, MVD, MVD, MVD, 'J', 'K' }, + { MVD, MVD, MVD, MVD, MVD, MVD, MVD, MVD, 'L', 'M' }, + { CVT, CVT, CVT, CVT, CVT, CVT, 'N', 'O', MVD, CVT }, + { CVT, CVT, CVT, CVT, CVT, CVT, 'P', 'Q', CVT, MVD }, +}; + +static void +sconv(NODE *p) +{ + NODE *l = p->n_left; + TWORD ts, td; + int o; + + /* + * Source node may be in register or memory. + * Result is always in register. + */ + ts = l->n_type; + if (ISPTR(ts)) + ts = UNSIGNED; + td = p->n_type; + ts = ts < LONG ? ts-2 : ts-4; + td = td < LONG ? td-2 : td-4; + + o = scary[ts][td]; + switch (o) { + case MLE: + case MLZ: + expand(p, INAREG|INBREG, "\tmovl\tAL,A1\n"); + break; + + case MVD: + if (l->n_op == REG && regno(l) == regno(getlr(p, '1'))) + break; /* unneccessary move */ + expand(p, INAREG|INBREG, "\tmovZR\tAL,A1\n"); + break; + + case CSE: + expand(p, INAREG|INBREG, "\tcvtZLl\tAL,A1\n"); + break; + + case CVT: + expand(p, INAREG|INBREG, "\tcvtZLZR\tAL,A1\n"); + break; + + case MZE: + expand(p, INAREG|INBREG, "\tmovzZLl\tAL,A1\n"); + break; + + case MVZ: + expand(p, INAREG|INBREG, "\tmovzZLZR\tAL,A1\n"); + break; + + case MZC: + expand(p, INAREG|INBREG, "\tmovzZLl\tAL,A1\n"); + expand(p, INAREG|INBREG, "\tcvtlZR\tA1,A1\n"); + break; + + case 'I': /* unsigned to double */ + expand(p, INAREG|INBREG, "\tcvtld\tAL,A1\n"); + printf("\tjgeq\t1f\n"); + expand(p, INAREG|INBREG, "\taddd2\t$0d4.294967296e+9,A1\n"); + printf("1:\n"); + break; + default: + comperr("unsupported conversion %d", o); + } + switch (o) { + case MLE: + case CSE: + expand(p, INBREG, "\tashl\t$-31,A1,U1\n"); + break; + case MLZ: + case MZE: + expand(p, INAREG|INBREG, "\tclrl\tU1\n"); + break; + } +} + +/* + * Assign a constant from p to q. Both are expected to be leaves by now. + * This is for 64-bit integers. + */ +static void +casg64(NODE *p) +{ + NODE *l, *r; + char *str; + int mneg = 1; + + l = p->n_left; + r = p->n_right; + +#ifdef PCC_DEBUG + if (r->n_op != ICON) + comperr("casg"); +#endif + if (r->n_name[0] != '\0') { + /* named constant, nothing to do */ + str = "movq\tAR,AL"; + mneg = 0; + } else if (r->n_lval == 0) { + str = "clrq\tAL"; + mneg = 0; + } else if (r->n_lval < 0) { + if (r->n_lval >= -63) { + r->n_lval = -r->n_lval; + str = "mnegl\tAR,AL"; + } else if (r->n_lval >= -128) { + str = "cvtbl\tAR,AL"; + } else if (r->n_lval >= -32768) { + str = "cvtwl\tAR,AL"; + } else if (r->n_lval >= -4294967296LL) { + str = "movl\tAR,AL"; + } else { + str = "movq\tAR,AL"; + mneg = 0; + } + } else { + mneg = 0; + if (r->n_lval <= 63 || r->n_lval > 4294967295LL) { + str = "movq\tAR,AL"; + } else if (r->n_lval <= 255) { + str = "movzbl\tAR,AL\n\tclrl\tUL"; + } else if (r->n_lval <= 65535) { + str = "movzwl\tAR,AL\n\tclrl\tUL"; + } else /* if (r->n_lval <= 4294967295) */ { + str = "movl\tAR,AL\n\tclrl\tUL"; + } + } + expand(p, FOREFF, str); + if (mneg) + expand(p, FOREFF, "\n\tmnegl $1,UL"); +} + +/* + * Assign a constant from p to q. Both are expected to be leaves by now. + * This is only for 32-bit integer types. + */ +static void +casg(NODE *p) +{ + NODE *l, *r; + char *str; + + l = p->n_left; + r = p->n_right; + +#ifdef PCC_DEBUG + if (r->n_op != ICON) + comperr("casg"); +#endif + if (r->n_name[0] != '\0') { + /* named constant, nothing to do */ + str = "movZL\tAR,AL"; + } else if (r->n_lval == 0) { + str = "clrZL\tAL"; + } else if (r->n_lval < 0) { + if (r->n_lval >= -63) { + r->n_lval = -r->n_lval; + str = "mnegZL\tAR,AL"; + } else if (r->n_lval >= -128) { + if (l->n_type == CHAR) + str = "movb\tAR,AL"; + else + str = "cvtbZL\tAR,AL"; + } else if (r->n_lval >= -32768) { + if (l->n_type == SHORT) + str = "movw\tAR,AL"; + else + str = "cvtwZL\tAR,AL"; + } else + str = "movZL\tAR,AL"; + } else { + if (r->n_lval <= 63 || r->n_lval > 65535) { + str = "movZL\tAR,AL"; + } else if (r->n_lval <= 255) { + str = l->n_type < SHORT ? + "movb\tAR,AL" : "movzbZL\tAR,AL"; + } else /* if (r->n_lval <= 65535) */ { + str = l->n_type < INT ? + "movw\tAR,AL" : "movzwZL\tAR,AL"; + } + } + expand(p, FOREFF, str); +} + +/* + * Emit code to compare two longlong numbers. + */ +static void +twollcomp(NODE *p) +{ + int u; + int s = getlab2(); + int e = p->n_label; + int cb1, cb2; + + u = p->n_op; + switch (p->n_op) { + case NE: + cb1 = 0; + cb2 = NE; + break; + case EQ: + cb1 = NE; + cb2 = 0; + break; + case LE: + case LT: + u += (ULE-LE); + /* FALLTHROUGH */ + case ULE: + case ULT: + cb1 = GT; + cb2 = LT; + break; + case GE: + case GT: + u += (ULE-LE); + /* FALLTHROUGH */ + case UGE: + case UGT: + cb1 = LT; + cb2 = GT; + break; + + default: + cb1 = cb2 = 0; /* XXX gcc */ + } + if (p->n_op >= ULE) + cb1 += 4, cb2 += 4; + expand(p, 0, " cmpl UL,UR\n"); + if (cb1) cbgen(cb1, s); + if (cb2) cbgen(cb2, e); + expand(p, 0, " cmpl AL,AR\n"); + cbgen(u, e); + deflab(s); +} + + +void +zzzcode(NODE *p, int c) +{ + NODE *l, *r; + TWORD t; + int m; + char *ch; + + switch (c) { + case 'N': /* logical ops, turned into 0-1 */ + /* use register given by register 1 */ + cbgen( 0, m=getlab2()); + deflab( p->n_label ); + printf( " clrl %s\n", rnames[getlr( p, '1' )->n_rval] ); + deflab( m ); + return; + + case 'A': /* Assign a constant directly to a memory position */ + printf("\t"); + if (p->n_type < LONG || ISPTR(p->n_type)) + casg(p); + else + casg64(p); + printf("\n"); + break; + + case 'B': /* long long compare */ + twollcomp(p); + break; + + case 'C': /* num words pushed on arg stack */ + printf("$%d", p->n_qual); + break; + + case 'D': /* INCR and DECR */ + zzzcode(p->n_left, 'A'); + printf("\n "); + +#if 0 + case 'E': /* INCR and DECR, FOREFF */ + if (p->n_right->n_lval == 1) + { + printf("%s", (p->n_op == INCR ? "inc" : "dec") ); + prtype(p->n_left); + printf(" "); + adrput(stdout, p->n_left); + return; + } + printf("%s", (p->n_op == INCR ? "add" : "sub") ); + prtype(p->n_left); + printf("2 "); + adrput(stdout, p->n_right); + printf(","); + adrput(p->n_left); + return; +#endif + + case 'F': /* register type of right operand */ + { + register NODE *n; + register int ty; + + n = getlr( p, 'R' ); + ty = n->n_type; + + if (x2debug) printf("->%d<-", ty); + + if ( ty==DOUBLE) printf("d"); + else if ( ty==FLOAT ) printf("f"); + else printf("l"); + return; + } + + case 'G': /* emit conversion instructions */ + sconv(p); + break; + + case 'J': /* jump or ret? */ + { + struct interpass *ip = + DLIST_PREV((struct interpass *)p2env.epp, qelem); + if (ip->type != IP_DEFLAB || + ip->ip_lbl != getlr(p, 'L')->n_lval) + expand(p, FOREFF, "jbr LL"); + else + printf("ret"); + } + break; + + case 'L': /* type of left operand */ + case 'R': /* type of right operand */ + { + register NODE *n; + + n = getlr ( p, c); + if (x2debug) printf("->%d<-", n->n_type); + + prtype(n); + return; + } + + case 'l': /* print out long long constant as hex */ + case 'r': /* works around a bug in gas */ + l = getlr(p, c == 'l' ? 'L' : 'R'); + if (l->n_op == ICON && ISLONGLONG(l->n_type)) { + printf("$0x%llx", l->n_lval); + } else + adrput(stdout, l); + break; + + case 'O': /* print out emulated ops */ + expand(p, FOREFF, "\tmovq AR,-(%sp)\n"); + expand(p, FOREFF, "\tmovq AL,-(%sp)\n"); + if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv"; + else if (p->n_op == DIV) ch = "div"; + else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod"; + else if (p->n_op == MOD) ch = "mod"; + else if (p->n_op == MUL) ch = "mul"; + else ch = 0, comperr("ZO %d", p->n_op); + printf("\tcalls $4,__%sdi3\n", ch); + break; + + + case 'Z': /* complement mask for bit instr */ + printf("$%lld", ~p->n_right->n_lval); + return; + + case 'U': /* 32 - n, for unsigned right shifts */ + t = DEUNSIGN(p->n_left->n_type); + m = t == CHAR ? 8 : t == SHORT ? 16 : 32; + printf("$" CONFMT, m - p->n_right->n_lval); + return; + + case 'T': /* rounded structure length for arguments */ + { + int size; + + size = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + SETOFF( size, 4); + printf("$%d", size); + return; + } + + case 'S': /* structure assignment */ + { + register int size; + + size = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); + SETOFF(size, 4); + l = r = NULL; /* XXX gcc */ + if( p->n_op == STASG ){ + l = p->n_left; + r = p->n_right; + + } + else if( p->n_op == STARG ){ + /* store an arg into a temporary */ + printf("\tsubl2 $%d,%%sp\n", + size < 4 ? 4 : size); + l = mklnode(OREG, 0, SP, INT); + r = p->n_left; + } + else cerror( "STASG bad" ); + + if( r->n_op == ICON ) r->n_op = NAME; + else if( r->n_op == REG ) r->n_op = OREG; + else if( r->n_op != OREG ) cerror( "STASG-r" ); + + if (size != 0) { + if( size <= 0 || size > 65535 ) + cerror("structure size <0=0 or >65535"); + + switch(size) { + case 1: + printf(" movb "); + break; + case 2: + printf(" movw "); + break; + case 4: + printf(" movl "); + break; + case 8: + printf(" movq "); + break; + default: + printf(" movc3 $%d,", size); + break; + } + adrput(stdout, r); + printf(","); + adrput(stdout, l); + printf("\n"); + } + + if( r->n_op == NAME ) r->n_op = ICON; + else if( r->n_op == OREG ) r->n_op = REG; + if (p->n_op == STARG) + tfree(l); + + } + break; + + default: + comperr("illegal zzzcode '%c'", c); + } +} + +void +rmove(int rt, int rs, TWORD t) +{ + char c = (t == FLOAT ? 'f' : t == DOUBLE ? 'd' : + t == LONGLONG || t == ULONGLONG ? 'q' : 'l'); + printf(" mov%c %s,%s\n", c, rnames[rt], rnames[rs]); +} + +int +rewfld(NODE *p) +{ + return(1); +} + +#if 0 +int +callreg(NODE *p) +{ + return( R0 ); +} + +int +base(register NODE *p) +{ + register int o = p->op; + + if( (o==ICON && p->name[0] != '\0')) return( 100 ); /* ie no base reg */ + if( o==REG ) return( p->rval ); + if( (o==PLUS || o==MINUS) && p->left->op == REG && p->right->op==ICON) + return( p->left->rval ); + if( o==OREG && !R2TEST(p->rval) && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) ) + return( p->rval + 0200*1 ); + if( o==INCR && p->left->op==REG ) return( p->left->rval + 0200*2 ); + if( o==ASG MINUS && p->left->op==REG) return( p->left->rval + 0200*4 ); + if( o==UNARY MUL && p->left->op==INCR && p->left->left->op==REG + && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) ) + return( p->left->left->rval + 0200*(1+2) ); + return( -1 ); +} + +int +offset(register NODE *p, int tyl) +{ + + if( tyl==1 && p->op==REG && (p->type==INT || p->type==UNSIGNED) ) return( p->rval ); + if( (p->op==LS && p->left->op==REG && (p->left->type==INT || p->left->type==UNSIGNED) && + (p->right->op==ICON && p->right->name[0]=='\0') + && (1<right->lval)==tyl)) + return( p->left->rval ); + return( -1 ); +} +#endif + +#if 0 +void +makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { + register NODE *t; + NODE *f; + + p->n_op = OREG; + f = p->n_left; /* have to free this subtree later */ + + /* init base */ + switch (q->n_op) { + case ICON: + case REG: + case OREG: + t = q; + break; + + case MINUS: + q->n_right->n_lval = -q->n_right->n_lval; + case PLUS: + t = q->n_right; + break; + + case UMUL: + t = q->n_left->n_left; + break; + + default: + cerror("illegal makeor2"); + t = NULL; /* XXX gcc */ + } + + p->n_lval = t->n_lval; + p->n_name = t->n_name; + + /* init offset */ + p->n_rval = R2PACK( (b & 0177), o, (b>>7) ); + + tfree(f); + return; + } + +int +canaddr( p ) NODE *p; { + register int o = p->n_op; + + if( o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, STARNM|SOREG)) ) return(1); + return(0); + } + +shltype( o, p ) register NODE *p; { + return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UMUL && shumul(p->n_left, STARNM|SOREG)) ); + } +#endif + +int +fldexpand(NODE *p, int cookie, char **cp) +{ + return 0; +} + +int +flshape(register NODE *p) +{ + return( p->n_op == REG || p->n_op == NAME || p->n_op == ICON || + (p->n_op == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)) ); +} + +int +shtemp(register NODE *p) +{ + if( p->n_op == STARG ) p = p->n_left; + return( p->n_op==NAME || p->n_op ==ICON || p->n_op == OREG || (p->n_op==UMUL && shumul(p->n_left, STARNM|SOREG)) ); +} + +/* + * Shape matches for UMUL. Cooperates with offstar(). + */ +int +shumul(NODE *p, int shape) +{ + + if (x2debug) + printf("shumul(%p)\n", p); + + /* Turns currently anything into OREG on vax */ + if (shape & SOREG) + return SROREG; + return SRNOPE; +} + + +#ifdef notdef +int +shumul( p, shape ) register NODE *p; int shape; { + register int o; + + if (x2debug) { + printf("\nshumul:op=%d,lop=%d,rop=%d", p->n_op, p->n_left->n_op, p->n_right->n_op); + printf(" prname=%s,plty=%d, prlval=%lld\n", p->n_right->n_name, p->n_left->n_type, p->n_right->n_lval); + } + + + o = p->n_op; + if( o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON ) + if (shape & STARNM) + return SRDIR; + + if( ( o == INCR || o == ASG MINUS ) && + ( p->n_left->n_op == REG && p->n_right->n_op == ICON ) && + p->n_right->n_name[0] == '\0' ) + { + switch (p->n_left->n_type) + { + case CHAR|PTR: + case UCHAR|PTR: + o = 1; + break; + + case SHORT|PTR: + case USHORT|PTR: + o = 2; + break; + + case INT|PTR: + case UNSIGNED|PTR: + case LONG|PTR: + case ULONG|PTR: + case FLOAT|PTR: + o = 4; + break; + + case DOUBLE|PTR: + o = 8; + break; + + default: + if ( ISPTR(p->n_left->n_type) ) { + o = 4; + break; + } + else return(0); + } + return( p->n_right->n_lval == o ? STARREG : 0); + } + + return( SRNOPE ); + } +#endif + +void +adrcon(CONSZ val) +{ + comperr("adrcon"); + printf( "$" ); + printf( CONFMT, val ); +} + +void +conput(FILE *fp, NODE *p) +{ + switch( p->n_op ){ + + case ICON: + acon( p ); + return; + + case REG: + printf( "%s", rnames[p->n_rval] ); + return; + + default: + cerror( "illegal conput" ); + } + } + +void +insput(register NODE *p) +{ + cerror( "insput" ); +} + +/* + * Write out the upper address, like the upper register of a 2-register + * reference, or the next memory location. + */ +void +upput(NODE *p, int size) +{ + + size /= SZCHAR; + switch (p->n_op) { + case REG: + printf("%s", rnames[regno(p)-16+1]); + break; + + case NAME: + if (kflag) + comperr("upput NAME"); + case OREG: + p->n_lval += size; + adrput(stdout, p); + p->n_lval -= size; + break; + case ICON: + printf("$" CONFMT, (p->n_lval >> 32) & 0xffffffff); + break; + default: + comperr("upput bad op %d size %d", p->n_op, size); + } +} + +void +adrput(FILE *fp, NODE *p) +{ + register int r; + /* output an address, with offsets, from p */ + + if( p->n_op == FLD ){ + p = p->n_left; + } + switch( p->n_op ){ + + case NAME: + acon( p ); + return; + + case ICON: + /* addressable value of the constant */ + if (p->n_name[0] == '\0') /* uses xxxab */ + printf("$"); + if (ISLONGLONG(p->n_type)) + printf("0x%llx", p->n_lval); + else + acon(p); + return; + + case REG: + printf( "%s", rnames[p->n_rval] ); + return; + + case OREG: + r = p->n_rval; + if( R2TEST(r) ){ /* double indexing */ + register int flags; + + flags = R2UPK3(r); + if( flags & 1 ) printf("*"); + if( flags & 4 ) printf("-"); + if( p->n_lval != 0 || p->n_name[0] != '\0' ) acon(p); + if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] ); + if( flags & 2 ) printf("+"); + printf( "[%s]", rnames[R2UPK2(r)] ); + return; + } + if( r == AP ){ /* in the argument region */ + if( p->n_lval <= 0 || p->n_name[0] != '\0' ) + werror( "bad arg temp" ); + printf( CONFMT, p->n_lval ); + printf( "(%%ap)" ); + return; + } + if( p->n_lval != 0 || p->n_name[0] != '\0') acon( p ); + printf( "(%s)", rnames[p->n_rval] ); + return; + + case UMUL: + /* STARNM or STARREG found */ + if( tshape(p, STARNM) ) { + printf( "*" ); + adrput(0, p->n_left); + } + else { /* STARREG - really auto inc or dec */ + register NODE *q; + +/* tbl + p = p->n_left; + p->n_left->n_op = OREG; + if( p->n_op == INCR ) { + adrput( p->n_left ); + printf( "+" ); + } + else { + printf( "-" ); + adrput( p->n_left ); + } + tbl */ +#ifdef notyet + printf("%c(%s)%c", (p->n_left->n_op==INCR ? '\0' : '-'), + rnames[p->n_left->n_left->n_rval], + (p->n_left->n_op==INCR ? '+' : '\0') ); +#else + printf("%c(%s)%c", '-', + rnames[p->n_left->n_left->n_rval], + '\0' ); +#endif + p->n_op = OREG; + p->n_rval = p->n_left->n_left->n_rval; + q = p->n_left; +#ifdef notyet + + p->n_lval = (p->n_left->n_op == INCR ? -p->n_left->n_right->n_lval : 0); +#else + p->n_lval = 0; +#endif + p->n_name[0] = '\0'; + tfree(q); + } + return; + + default: + cerror( "illegal address" ); + return; + } + +} + +/* + * print out a constant + */ +void +acon(NODE *p) +{ + int u = (int)p->n_lval;; + CONSZ v = u; + + if (p->n_name[0] == '\0') { + printf(CONFMT, v); + } else if( p->n_lval == 0 ) { + printf("%s", p->n_name); + } else { + printf("%s+", p->n_name); + printf(CONFMT, v); + } +} + +#if 0 +genscall( p, cookie ) register NODE *p; { + /* structure valued call */ + return( gencall( p, cookie ) ); + } + +/* tbl */ +int gc_numbytes; +/* tbl */ + +gencall( p, cookie ) register NODE *p; { + /* generate the call given by p */ + register NODE *p1, *ptemp; + register temp, temp1; + register m; + + if( p->right ) temp = argsize( p->right ); + else temp = 0; + + if( p->op == STCALL || p->op == UNARY STCALL ){ + /* set aside room for structure return */ + + if( p->stsize > temp ) temp1 = p->stsize; + else temp1 = temp; + } + + if( temp > maxargs ) maxargs = temp; + SETOFF(temp1,4); + + if( p->right ){ /* make temp node, put offset in, and generate args */ + ptemp = talloc(); + ptemp->op = OREG; + ptemp->lval = -1; + ptemp->rval = SP; + ptemp->name[0] = '\0'; + ptemp->rall = NOPREF; + ptemp->su = 0; + genargs( p->right, ptemp ); + nfree(ptemp); + } + + p1 = p->left; + if( p1->op != ICON ){ + if( p1->op != REG ){ + if( p1->op != OREG || R2TEST(p1->rval) ){ + if( p1->op != NAME ){ + order( p1, INAREG ); + } + } + } + } + +/* + if( p1->op == REG && p->rval == R5 ){ + cerror( "call register overwrite" ); + } + */ +/* tbl + setup gc_numbytes so reference to ZC works */ + + gc_numbytes = temp; +/* tbl */ + + p->op = UNARY CALL; + m = match( p, INTAREG|INTBREG ); +/* tbl + switch( temp ) { + case 0: + break; + case 2: + printf( " tst (%sp)+\n" ); + break; + case 4: + printf( " cmp (%sp)+,(%sp)+\n" ); + break; + default: + printf( " add $%d,%sp\n", temp); + } + tbl */ + return(m != MDONE); + } +#endif + +static char * +ccbranches[] = { + "jeql", + "jneq", + "jleq", + "jlss", + "jgeq", + "jgtr", + "jlequ", + "jlssu", + "jgequ", + "jgtru", +}; + +/* + * printf conditional and unconditional branches + */ +void +cbgen(int o, int lab) +{ + + if (o == 0) { + printf(" jbr " LABFMT "\n", lab); + } else { + if (o > UGT) + comperr("bad conditional branch: %s", opst[o]); + printf("\t%s\t" LABFMT "\n", ccbranches[o-EQ], lab); + } +} + +static void +mkcall(NODE *p, char *name) +{ + p->n_op = CALL; + p->n_right = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type); + p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type); + p->n_left->n_name = name; +} + +/* do local tree transformations and optimizations */ +static void +optim2(NODE *p, void *arg) +{ + NODE *r, *s; + TWORD lt; + + switch (p->n_op) { + case DIV: + case MOD: + if (p->n_type == USHORT || p->n_type == UCHAR) { + r = mkunode(SCONV, p->n_left, 0, UNSIGNED); + r = mkunode(FUNARG, r, 0, UNSIGNED); + s = mkunode(SCONV, p->n_right, 0, UNSIGNED); + s = mkunode(FUNARG, s, 0, UNSIGNED); + r = mkbinode(CM, r, s, INT); + s = mklnode(ICON, 0, 0, FTN|UNSIGNED); + s->n_name = p->n_op == MOD ? "__urem" : "__udiv"; + p->n_left = mkbinode(CALL, s, r, UNSIGNED); + p->n_op = SCONV; + } else if (p->n_type == UNSIGNED) { + p->n_left = mkunode(FUNARG, p->n_left, 0, UNSIGNED); + p->n_right = mkunode(FUNARG, p->n_right, 0, UNSIGNED); + p->n_right = mkbinode(CM, p->n_left, p->n_right, INT); + p->n_left = mklnode(ICON, 0, 0, FTN|UNSIGNED); + p->n_left->n_name = p->n_op == MOD ? "__urem" : "__udiv"; + p->n_op = CALL; + } + break; + + case RS: + if (p->n_type == ULONGLONG) { + p->n_right = mkbinode(CM, + mkunode(FUNARG, p->n_left, 0, p->n_left->n_type), + mkunode(FUNARG, p->n_right, 0, p->n_right->n_type), + INT); + p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type); + p->n_left->n_name = "__lshrdi3"; + p->n_op = CALL; + } else if (p->n_type == INT || p->n_type == LONGLONG) { + /* convert >> to << with negative shift count */ + /* RS of char & short must use extv */ + if (p->n_right->n_op == ICON) { + p->n_right->n_lval = -p->n_right->n_lval; + } else if (p->n_right->n_op == UMINUS) { + r = p->n_right->n_left; + nfree(p->n_right); + p->n_right = r; + } else { + p->n_right = mkunode(UMINUS, p->n_right, + 0, p->n_right->n_type); + } + p->n_op = LS; + } + break; + + case AND: + /* commute L and R to eliminate compliments and constants */ + if ((p->n_left->n_op == ICON && p->n_left->n_name[0] == 0) || + p->n_left->n_op==COMPL) { + r = p->n_left; + p->n_left = p->n_right; + p->n_right = r; + } + /* change meaning of AND to ~R&L - bic on pdp11 */ + r = p->n_right; + if (r->n_op == ICON && r->n_name[0] == 0) { + /* compliment constant */ + r->n_lval = ~r->n_lval; + } else if (r->n_op == COMPL) { /* ~~A => A */ + s = r->n_left; + nfree(r); + p->n_right = s; + } else { /* insert complement node */ + p->n_right = mkunode(COMPL, r, 0, r->n_type); + } + break; + case SCONV: + lt = p->n_left->n_type; + switch (p->n_type) { + case LONGLONG: + if (lt == FLOAT) + mkcall(p, "__fixsfdi"); + else if (lt == DOUBLE) + mkcall(p, "__fixdfdi"); + break; + case ULONGLONG: + if (lt == FLOAT) + mkcall(p, "__fixunssfdi"); + else if (lt == DOUBLE) + mkcall(p, "__fixunsdfdi"); + break; + case FLOAT: + if (lt == LONGLONG) + mkcall(p, "__floatdisf"); + else if (lt == ULONGLONG) { + p->n_left = mkunode(SCONV, p->n_left,0, DOUBLE); + p->n_type = FLOAT; + mkcall(p->n_left, "__floatundidf"); + } else if (lt == UNSIGNED) { + /* insert an extra double-to-float sconv */ + p->n_left = mkunode(SCONV, p->n_left,0, DOUBLE); + } + break; + case DOUBLE: + if (lt == LONGLONG) + mkcall(p, "__floatdidf"); + else if (lt == ULONGLONG) + mkcall(p, "__floatundidf"); + break; + + } + break; + } +} + +static void +aofname(NODE *p, void *arg) +{ + int o = optype(p->n_op); + TWORD t; + + if (o == LTYPE || p->n_op == ADDROF) + return; + t = p->n_left->n_type; + if (p->n_left->n_op == NAME && ISLONGLONG(t)) + p->n_left = mkunode(UMUL, + mkunode(ADDROF, p->n_left, 0, INCREF(t)), 0, t); + if (o == BITYPE && p->n_right->n_op == NAME && + ISLONGLONG(p->n_right->n_type)) { + t = p->n_right->n_type; + p->n_right = mkunode(UMUL, + mkunode(ADDROF, p->n_right, 0, INCREF(t)), 0, t); + } +} + +void +myreader(struct interpass *ipole) +{ + struct interpass *ip; + + DLIST_FOREACH(ip, ipole, qelem) { + if (ip->type != IP_NODE) + continue; + if (kflag) + walkf(ip->ip_node, aofname, 0); + walkf(ip->ip_node, optim2, 0); + } +} + +void +mycanon(NODE *p) +{ +} + +void +myoptim(struct interpass *ip) +{ +} + +/* + * Return argument size in regs. + */ +static int +argsiz(NODE *p) +{ + TWORD t = p->n_type; + + if (t == STRTY || t == UNIONTY) + return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+3)/4; + return szty(t); +} + +/* + * Last chance to do something before calling a function. + */ +void +lastcall(NODE *p) +{ + NODE *op = p; + int size = 0; + + /* Calculate argument sizes */ + p->n_qual = 0; + if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) + return; + for (p = p->n_right; p->n_op == CM; p = p->n_left) + size += argsiz(p->n_right); + if (p->n_op != ASSIGN) + size += argsiz(p); + op->n_qual = size; /* XXX */ +} + +/* + * Return a class suitable for a specific type. + */ +int +gclass(TWORD t) +{ + return (szty(t) == 2 ? CLASSB : CLASSA); +} + +/* + * For class c, find worst-case displacement of the number of + * registers in the array r[] indexed by class. + */ +int +COLORMAP(int c, int *r) +{ + int num; + int a,b; + + a = r[CLASSA]; + b = r[CLASSB]; + switch (c) { + case CLASSA: + /* there are 12 classa, so min 6 classb are needed to block */ + num = b * 2; + num += a; + return num < 12; + case CLASSB: + if (b > 3) return 0; + if (b > 2 && a) return 0; + if (b > 1 && a > 2) return 0; + if (b && a > 3) return 0; + if (a > 5) return 0; + return 1; + } + comperr("COLORMAP"); + return 0; /* XXX gcc */ +} + +/* + * Special shapes. + */ +int +special(NODE *p, int shape) +{ + return SRNOPE; +} + +/* + * Target-dependent command-line options. + */ +void +mflags(char *str) +{ +} +/* + * Do something target-dependent for xasm arguments. + * Supposed to find target-specific constraints and rewrite them. + */ +int +myxasm(struct interpass *ip, NODE *p) +{ + char *c; + int i; + + /* Discard o<> constraints since they will not be generated */ + for (c = p->n_name; *c; c++) { + if (*c == 'o' || *c == '<' || *c == '>') { + for (i = 0; c[i]; i++) + c[i] = c[i+1]; + c--; + } + } + return 0; +} + +int +xasmconstregs(char *s) +{ + int i; + + for (i = 0; i < 16; i++) + if (strcmp(&rnames[i][1], s) == 0) + return i; + return -1; +} diff --git a/lang/pcc/pcc/arch/vax/macdefs.h b/lang/pcc/pcc/arch/vax/macdefs.h new file mode 100644 index 000000000..70fe98cb0 --- /dev/null +++ b/lang/pcc/pcc/arch/vax/macdefs.h @@ -0,0 +1,266 @@ +/* $Id: macdefs.h,v 1.23 2016/03/05 15:53:04 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ + +# define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); + +# define ARGINIT 32 +# define AUTOINIT 0 +# define SZCHAR 8 +# define SZBOOL 8 +# define SZINT 32 +# define SZFLOAT 32 +# define SZDOUBLE 64 +# define SZLDOUBLE 64 /* XXX use longer? */ +# define SZLONG 32 +# define SZLONGLONG 64 +# define SZSHORT 16 +# define SZPOINT(t) 32 +# define ALCHAR 8 +# define ALBOOL 8 +# define ALINT 32 +# define ALFLOAT 32 +# define ALDOUBLE 32 +# define ALLDOUBLE 32 +# define ALLONG 32 +# define ALLONGLONG 32 +# define ALSHORT 16 +# define ALPOINT 32 +# define ALSTRUCT 8 +# define ALSTACK 32 +#define MYVAARGSZ SZINT + +/* + * Min/max values. + */ +#define MIN_CHAR -128 +#define MAX_CHAR 127 +#define MAX_UCHAR 255 +#define MIN_SHORT -32768 +#define MAX_SHORT 32767 +#define MAX_USHORT 65535 +#define MIN_INT (-0x7fffffff-1) +#define MAX_INT 0x7fffffff +#define MAX_UNSIGNED 0xffffffff +#define MIN_LONG MIN_INT +#define MAX_LONG MAX_INT +#define MAX_ULONG MAX_UNSIGNED +#define MIN_LONGLONG 0x8000000000000000LL +#define MAX_LONGLONG 0x7fffffffffffffffLL +#define MAX_ULONGLONG 0xffffffffffffffffULL + +/* Default char is signed */ +#undef CHAR_UNSIGNED +#define BOOL_TYPE CHAR /* what used to store _Bool */ +#define HASP2ALIGN +/* size in which constants are converted */ +/* should be long if feasable */ + +typedef long long CONSZ; +typedef unsigned long long U_CONSZ; + +# define CONFMT "%lld" +# define LABFMT ".L%d" +# define STABLBL ".LL%d" + +/* size in which offsets are kept + * should be large enough to cover address space in bits + */ +typedef long long OFFSZ; + +/* register cookie for stack poINTer */ + + +/* show stack grows negatively */ +#define BACKAUTO +#define BACKTEMP + +/* show field hardware support on VAX */ +/* XXX notyet */ +#undef FIELDOPS + +/* bytes are numbered from right to left */ +#define TARGET_ENDIAN TARGET_LE +#define UNALIGNED_ACCESS + +/* we want prtree included */ +# define STDPRTREE + +/* VAX-11/780 Registers */ + + /* scratch registers */ +# define R0 0 +# define R1 1 +# define R2 2 +# define R3 3 +# define R4 4 +# define R5 5 + + /* register variables */ +# define R6 6 +# define R7 7 +# define R8 8 +# define R9 9 +# define R10 10 +# define R11 11 + + /* special purpose */ +# define AP 12 /* argument pointer */ +# define FP 13 /* frame pointer */ +# define SP 14 /* stack pointer */ +# define PC 15 /* program counter */ + + /* floating registers */ + + /* there are no floating point registers on the VAX */ + /* but there are concatenated regs */ + /* we call them XR? */ +#define XR0 16 +#define XR1 17 +#define XR2 18 +#define XR3 19 +#define XR4 20 +#define XR5 21 +#define XR6 22 +#define XR7 23 +#define XR8 24 +#define XR9 25 +#define XR10 26 + + + + +extern int fregs; +extern int maxargs; + +# define BYTEOFF(x) ((x)&03) +# define wdal(k) (BYTEOFF(k)==0) + +# define REGSZ 16 + +# define TMPREG FP + +//# define R2REGS /* permit double indexing */ + +# define STOARG(p) /* just evaluate the arguments, and be done with it... */ +# define STOFARG(p) +# define STOSTARG(p) +# define genfcall(a,b) gencall(a,b) + +# define NESTCALL + +/* + * Register allocator stuff. + * The register allocator sees this as 16 general regs (AREGs) + * and 11 64-bit concatenated regs. (BREGs) + */ +#define MAXREGS 033 /* 27 registers */ + +#define RSTATUS \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ + SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, SAREG|PERMREG, \ + SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ + 0, 0, 0, 0, /* do not care about ap, fp, sp or pc */ \ + SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ + SBREG, SBREG, SBREG, + +#define ROVERLAP \ + { XR0, -1 }, \ + { XR0, XR1, -1 }, \ + { XR1, XR2, -1 }, \ + { XR2, XR3, -1 }, \ + { XR3, XR4, -1 }, \ + { XR4, XR5, -1 }, \ + { XR5, XR6, -1 }, \ + { XR6, XR7, -1 }, \ + { XR7, XR8, -1 }, \ + { XR8, XR9, -1 }, \ + { XR9, XR10, -1 }, \ + { XR10, -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { -1 }, \ + { R0, R1, XR1, -1 }, \ + { R1, R2, XR0, XR2, -1 }, \ + { R2, R3, XR1, XR3, -1 }, \ + { R3, R4, XR2, XR4, -1 }, \ + { R4, R5, XR3, XR5, -1 }, \ + { R5, R6, XR4, XR6, -1 }, \ + { R6, R7, XR5, XR7, -1 }, \ + { R7, R8, XR6, XR8, -1 }, \ + { R8, R9, XR7, XR9, -1 }, \ + { R9, R10, XR8, XR10, -1 }, \ + { R10, R11, XR9, -1 }, + +#define NUMCLASS 2 /* highest number of reg classes used */ + +/* size, in registers, needed to hold thing of type t */ +#define szty(t) (((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) +#define FPREG FP /* frame pointer */ +#define STKREG SP +#define ARGREG AP + +#define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ +#define ENCRD(x) (x) /* Encode dest reg in n_reg */ +#define ENCRA1(x) ((x) << 6) /* A1 */ +#define ENCRA2(x) ((x) << 12) /* A2 */ +#define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ + +#define PCLASS(p) (szty(p->n_type) == 2 ? SBREG : SAREG) +#define RETREG(x) (szty(x) == 2 ? XR0 : R0) +#define GCLASS(x) (x < XR0 ? CLASSA : CLASSB) +int xasmconstregs(char *s); +#define XASMCONSTREGS(x) xasmconstregs(x) +int COLORMAP(int c, int *r); + +#define SNCON (MAXSPECIAL+1) /* named constand */ + +#define TARGET_FLT_EVAL_METHOD 0 /* all as their type */ +/* + * Builtins. + */ +#ifdef LANG_CXX +#define P1ND struct node +#else +#define P1ND struct p1node +#endif +struct p1node; +struct bitable; + +#define TARGET_FFS /* target-specific ffs */ +P1ND *builtin_ffs(const struct bitable *, P1ND *a); +P1ND *builtin_ffsl(const struct bitable *, P1ND *a); +P1ND *builtin_ffsll(const struct bitable *, P1ND *a); +#undef P1ND diff --git a/lang/pcc/pcc/arch/vax/order.c b/lang/pcc/pcc/arch/vax/order.c new file mode 100644 index 000000000..d3f59011c --- /dev/null +++ b/lang/pcc/pcc/arch/vax/order.c @@ -0,0 +1,667 @@ +/* $Id: order.c,v 1.10 2014/10/12 13:16:32 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "pass2.h" + +int canaddr(NODE *); + +int maxargs = { -1 }; + +#if 0 +stoasg( p, o ) register NODE *p; { + /* should the assignment op p be stored, + given that it lies as the right operand of o + (or the left, if o==UNARY MUL) */ +/* + if( p->op == INCR || p->op == DECR ) return; + if( o==UNARY MUL && p->left->op == REG && !isbreg(p->left->rval) ) SETSTO(p,INAREG); + */ + } + +int +deltest( p ) register NODE *p; { + /* should we delay the INCR or DECR operation p */ + p = p->n_left; + return( p->n_op == REG || p->n_op == NAME || p->n_op == OREG ); + } + +autoincr( p ) NODE *p; { + register NODE *q = p->left, *r; + + if( q->op == INCR && (r=q->left)->op == REG && + ISPTR(q->type) && p->type == DECREF(q->type) && + tlen(p) == q->right->lval ) return(1); + + return(0); + } + +mkadrs(p) register NODE *p; { + register o; + + o = p->op; + + if( asgop(o) ){ + if( p->left->su >= p->right->su ){ + if( p->left->op == UNARY MUL ){ + SETSTO( p->left->left, INTEMP ); + } + else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ + SETSTO( p->left->left->left, INTEMP ); + } + else { /* should be only structure assignment */ + SETSTO( p->left, INTEMP ); + } + } + else SETSTO( p->right, INTEMP ); + } + else { + if( p->left->su > p->right->su ){ + SETSTO( p->left, INTEMP ); + } + else { + SETSTO( p->right, INTEMP ); + } + } + } +#endif + +int +notoff(TWORD t, int r, CONSZ off, char *cp) +{ + /* is it legal to make an OREG or NAME entry which has an + * offset of off, (from a register of r), if the + * resulting thing had type t */ + +/* if( r == R0 ) return( 1 ); / * NO */ + return(0); /* YES */ + } + +# define max(x,y) ((x)<(y)?(y):(x)) + +#if 0 +sucomp( p ) register NODE *p; { + + /* set the su field in the node to the sethi-ullman + number, or local equivalent */ + + register o, ty, sul, sur, r; + + o = p->op; + ty = optype( o ); + p->su = szty( p->type ); /* 2 for float or double, else 1 */; + + if( ty == LTYPE ){ + if( o == OREG ){ + r = p->rval; + /* oreg cost is (worst case) 1 + number of temp registers used */ + if( R2TEST(r) ){ + if( R2UPK1(r)!=100 && istreg(R2UPK1(r)) ) ++p->su; + if( istreg(R2UPK2(r)) ) ++p->su; + } + else { + if( istreg( r ) ) ++p->su; + } + } + if( p->su == szty(p->type) && + (p->op!=REG || !istreg(p->rval)) && + (p->type==INT || p->type==UNSIGNED || p->type==DOUBLE) ) + p->su = 0; + return; + } + + else if( ty == UTYPE ){ + switch( o ) { + case UNARY CALL: + case UNARY STCALL: + p->su = fregs; /* all regs needed */ + return; + + default: + p->su = p->left->su + (szty( p->type ) > 1 ? 2 : 0) ; + return; + } + } + + + /* If rhs needs n, lhs needs m, regular su computation */ + + sul = p->left->su; + sur = p->right->su; + + if( o == ASSIGN ){ + /* computed by doing right, then left (if not in mem), then doing it */ + p->su = max(sur,sul+1); + return; + } + + if( o == CALL || o == STCALL ){ + /* in effect, takes all free registers */ + p->su = fregs; + return; + } + + if( o == STASG ){ + /* right, then left */ + p->su = max( max( 1+sul, sur), fregs ); + return; + } + + if( asgop(o) ){ + /* computed by doing right, doing left address, doing left, op, and store */ + p->su = max(sur,sul+2); +/* + if( o==ASG MUL || o==ASG DIV || o==ASG MOD) p->su = max(p->su,fregs); + */ + return; + } + + switch( o ){ + case ANDAND: + case OROR: + case QUEST: + case COLON: + case COMOP: + p->su = max( max(sul,sur), 1); + return; + + case PLUS: + case OR: + case ER: + /* commutative ops; put harder on left */ + if( p->right->su > p->left->su && !istnode(p->left) ){ + register NODE *temp; + temp = p->left; + p->left = p->right; + p->right = temp; + } + break; + } + + /* binary op, computed by left, then right, then do op */ + p->su = max(sul,szty(p->right->type)+sur); +/* + if( o==MUL||o==DIV||o==MOD) p->su = max(p->su,fregs); + */ + + } + +int radebug = 0; + +rallo( p, down ) NODE *p; { + /* do register allocation */ + register o, type, down1, down2, ty; + + if( radebug ) printf( "rallo( %o, %d )\n", p, down ); + + down2 = NOPREF; + p->rall = down; + down1 = ( down &= ~MUSTDO ); + + ty = optype( o = p->op ); + type = p->type; + + + if( type == DOUBLE || type == FLOAT ){ + if( o == FORCE ) down1 = R0|MUSTDO; + } + else switch( o ) { + case ASSIGN: + down1 = NOPREF; + down2 = down; + break; + +/* + case MUL: + case DIV: + case MOD: + down1 = R3|MUSTDO; + down2 = R5|MUSTDO; + break; + + case ASG MUL: + case ASG DIV: + case ASG MOD: + p->left->rall = down1 = R3|MUSTDO; + if( p->left->op == UNARY MUL ){ + rallo( p->left->left, R4|MUSTDO ); + } + else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ + rallo( p->left->left->left, R4|MUSTDO ); + } + else rallo( p->left, R3|MUSTDO ); + rallo( p->right, R5|MUSTDO ); + return; + */ + + case CALL: + case STASG: + case EQ: + case NE: + case GT: + case GE: + case LT: + case LE: + case NOT: + case ANDAND: + case OROR: + down1 = NOPREF; + break; + + case FORCE: + down1 = R0|MUSTDO; + break; + + } + + if( ty != LTYPE ) rallo( p->left, down1 ); + if( ty == BITYPE ) rallo( p->right, down2 ); + + } +#endif + +/* + * Turn a UMUL-referenced node into OREG. + * Be careful about register classes, this is a place where classes change. + */ +void +offstar(NODE *p, int shape) +{ + + if (x2debug) + printf("offstar(%p)\n", p); + + if (isreg(p)) + return; /* Is already OREG */ + +#if 0 /* notyet */ + NODE *r; + r = p->n_right; + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( r->n_op == ICON ){ + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + /* Converted in ormake() */ + return; + } + if (r->n_op == LS && r->n_right->n_op == ICON && + r->n_right->n_lval == 2 && p->n_op == PLUS) { + if (isreg(p->n_left) == 0) + (void)geninsn(p->n_left, INAREG); + if (isreg(r->n_left) == 0) + (void)geninsn(r->n_left, INAREG); + return; + } + } +#endif + (void)geninsn(p, INAREG); +} + + +#if 0 +void +offstar( p, s ) register NODE *p; { + if( p->n_op == PLUS ) { + if( p->n_left->n_su == fregs ) { + order( p->n_left, INAREG ); + return; + } else if( p->n_right->n_su == fregs ) { + order( p->n_right, INAREG ); + return; + } + if( p->n_left->n_op==LS && + (p->n_left->n_left->n_op!=REG || tlen(p->n_left->n_left)!=sizeof(int) ) ) { + order( p->n_left->n_left, INAREG ); + return; + } + if( p->n_right->n_op==LS && + (p->n_right->n_left->n_op!=REG || tlen(p->n_right->n_left)!=sizeof(int) ) ) { + order( p->n_right->n_left, INAREG ); + return; + } + if( p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR) ) { + if( p->n_left->n_op!=REG || tlen(p->n_left)!=sizeof(int) ) { + order( p->n_left, INAREG ); + return; + } + else if( p->n_right->n_op!=REG || tlen(p->n_right)!=sizeof(int) ) { + order(p->n_right, INAREG); + return; + } + } + } + if( p->n_op == PLUS || p->n_op == MINUS ){ + if( p->n_right->n_op == ICON ){ + p = p->n_left; + order( p , INAREG); + return; + } + } + + if( p->n_op == UMUL && !canaddr(p) ) { + offstar( p->n_left, 0 ); + return; + } + + order( p, INAREG ); + } +#endif + +int +setbin( p ) register NODE *p; { + +#if 0 + register int ro, rt; + + rt = p->n_right->n_type; + ro = p->n_right->n_op; + + if( canaddr( p->n_left ) && !canaddr( p->n_right ) ) { /* address rhs */ + if( ro == UMUL ) { + offstar( p->n_right->n_left, 0 ); + return(1); + } else { + order( p->n_right, INAREG|SOREG ); + return(1); + } + } + if( !istnode( p->n_left) ) { /* try putting LHS into a reg */ +/* order( p->n_left, logop(p->n_op)?(INAREG|INBREG|INTAREG|INTBREG|SOREG):(INTAREG|INTBREG|SOREG) );*/ + order( p->n_left, INAREG|INTAREG|INBREG|INTBREG|SOREG ); + return(1); + } + else if( ro == UNARY MUL && rt != CHAR && rt != UCHAR ){ + offstar( p->n_right->n_left ); + return(1); + } + else if( rt == CHAR || rt == UCHAR || rt == SHORT || rt == USHORT || (ro != REG && + ro != NAME && ro != OREG && ro != ICON ) ){ + order( p->n_right, INAREG|INBREG ); + return(1); + } +/* + else if( logop(p->n_op) && rt==USHORT ){ / * must get rhs into register */ +/* + order( p->n_right, INAREG ); + return( 1 ); + } + */ +#endif + return(0); + } + +#if 0 +int +setstr( p ) register NODE *p; { /* structure assignment */ + if( p->right->op != REG ){ + order( p->right, INTAREG ); + return(1); + } + p = p->left; + if( p->op != NAME && p->op != OREG ){ + if( p->op != UNARY MUL ) cerror( "bad setstr" ); + order( p->left, INTAREG ); + return( 1 ); + } + return( 0 ); + } +#endif + +int +setasg( p, s ) register NODE *p; { + +#if 0 + /* setup for assignment operator */ + + if( !canaddr(p->n_right) ) { + if( p->n_right->n_op == UNARY MUL ) + offstar(p->n_right->n_left); + else + order( p->n_right, INAREG|INBREG|SOREG ); + return(1); + } + if( p->n_left->n_op == UMUL ) { + offstar( p->n_left->n_left ); + return(1); + } + if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ + offstar( p->left->left->left ); + return(1); + } +/* FLD patch */ + if( p->left->op == FLD && !(p->right->type==INT || p->right->type==UNSIGNED)) { + order( p->right, INAREG); + return(1); + } +/* end of FLD patch */ +#endif + return(0); + } + +/* setup for unary operator */ +int +setuni(NODE *p, int cookie) +{ + return 0; +} + + +#if 0 +int +setasop( p ) register NODE *p; { + /* setup for =ops */ + register rt, ro; + + rt = p->right->type; + ro = p->right->op; + + if( ro == UNARY MUL && rt != CHAR ){ + offstar( p->right->left ); + return(1); + } + if( ( rt == CHAR || rt == SHORT || rt == UCHAR || rt == USHORT || + ( ro != REG && ro != ICON && ro != NAME && ro != OREG ) ) ){ + order( p->right, INAREG|INBREG ); + return(1); + } +/* + if( (p->op == ASG LS || p->op == ASG RS) && ro != ICON && ro != REG ){ + order( p->right, INAREG ); + return(1); + } + */ + + + p = p->left; + if( p->op == FLD ) p = p->left; + + switch( p->op ){ + + case REG: + case ICON: + case NAME: + case OREG: + return(0); + + case UNARY MUL: + if( p->left->op==OREG ) + return(0); + else + offstar( p->left ); + return(1); + + } + cerror( "illegal setasop" ); + } +#endif + +void +deflab(int l) +{ + printf(LABFMT ":\n", l); +} + +#if 0 +genargs( p, ptemp ) register NODE *p, *ptemp; { + register NODE *pasg; + register align; + register size; + register TWORD type; + + /* generate code for the arguments */ + + /* first, do the arguments on the right */ + while( p->op == CM ){ + genargs( p->right, ptemp ); + p->op = FREE; + p = p->left; + } + + if( p->op == STARG ){ /* structure valued argument */ + + size = p->stsize; + align = p->stalign; + + /* ptemp->lval = (ptemp->lval/align)*align; / * SETOFF for negative numbers */ + ptemp->lval = 0; /* all moves to (sp) */ + + p->op = STASG; + p->right = p->left; + p->left = tcopy( ptemp ); + + /* the following line is done only with the knowledge + that it will be undone by the STASG node, with the + offset (lval) field retained */ + + if( p->right->op == OREG ) p->right->op = REG; /* only for temporaries */ + + order( p, FORARG ); + ptemp->lval += size; + return; + } + + /* ordinary case */ + + order( p, FORARG ); + } + +argsize( p ) register NODE *p; { + register t; + t = 0; + if( p->op == CM ){ + t = argsize( p->left ); + p = p->right; + } + if( p->type == DOUBLE || p->type == FLOAT ){ + SETOFF( t, 4 ); + return( t+8 ); + } + else if( p->op == STARG ){ + SETOFF( t, 4 ); /* alignment */ + return( t + ((p->stsize+3)/4)*4 ); /* size */ + } + else { + SETOFF( t, 4 ); + return( t+4 ); + } + } +#endif + +/* + * Special handling of some instruction register allocation. + */ +struct rspecial * +nspecial(struct optab *q) +{ + switch (q->op) { + case STARG: + case STASG: + { + static struct rspecial s[] = { + { NEVER, R0, }, { NEVER, R1, }, { NEVER, R2, }, + { NEVER, R3, }, { NEVER, R4, }, { NEVER, R5 }, { 0 } }; + return s; + } + case MOD: + case MUL: + case DIV: + { + static struct rspecial s[] = { + { NEVER, R0, }, { NEVER, R1, }, { NEVER, R2, }, + { NEVER, R3, }, { NEVER, R4, }, { NEVER, R5 }, + { NRES, XR0 }, { 0 }, }; + return s; + } + default: + comperr("nspecial"); + return NULL; + } +} + +/* + * Set evaluation order of a binary node if it differs from default. + */ +int +setorder(NODE *p) +{ + return 0; /* nothing differs on vax */ +} + +/* + * Do the actual conversion of offstar-found OREGs into real OREGs. + */ +void +myormake(NODE *q) +{ +} +/* + * Set registers "live" at function calls (like arguments in registers). + * This is for liveness analysis of registers. + */ +int * +livecall(NODE *p) +{ + static int r[1] = { -1 }; /* Terminate with -1 */ + + return &r[0]; +} + +/* + * Signal whether the instruction is acceptable for this target. + */ +int +acceptable(struct optab *op) +{ + return 1; +} diff --git a/lang/pcc/pcc/arch/vax/table.c b/lang/pcc/pcc/arch/vax/table.c new file mode 100644 index 000000000..0c1137cc6 --- /dev/null +++ b/lang/pcc/pcc/arch/vax/table.c @@ -0,0 +1,879 @@ +/* $Id: table.c,v 1.28 2014/10/12 10:05:28 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "pass2.h" + +# define WPTR TPTRTO|TINT|TFLOAT|TDOUBLE|TPOINT|TUNSIGNED +# define SAWM SNAME|SOREG|STARNM|STARREG +# define AWD SAWM|SCON +/* tbl */ +# define TANYSIGNED TINT|TSHORT|TCHAR +# define TANYUSIGNED TPOINT|TUNSIGNED|TUSHORT|TUCHAR +# define TANYFIXED TANYSIGNED|TANYUSIGNED +# define TWORD TINT|TUNSIGNED|TPOINT +/* tbl */ +# define TLL TLONGLONG|TULONGLONG +# define TBREG TLONGLONG|TULONGLONG|TDOUBLE +# define TAREG TANYFIXED|TFLOAT + +struct optab table[] = { +/* First entry must be an empty entry */ +{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, + +/* PCONVs are usually not necessary */ +{ PCONV, INAREG, + SAREG, TWORD, + SAREG, TWORD, + 0, RLEFT, + "", }, + +{ PCONV, INAREG|INAREG, + SAREG|AWD, TCHAR|TSHORT, + SANY, TPOINT, + NAREG|NASL, RESC1, + " cvtZLl AL,A1\n", }, + +{ PCONV, INAREG|INAREG, + SAREG|AWD, TUCHAR|TUSHORT, + SANY, TPOINT, + NAREG|NASL, RESC1, + " movzZLl AL,A1\n", }, + +/* Handle conversions in C code */ +{ SCONV, INAREG, + SAREG|AWD, TAREG, + SANY, TANY, + NAREG|NASL, RESC1|RESCC, + "ZG", }, + +{ SCONV, INAREG, + SBREG|AWD, TBREG, + SANY, TANY, + NAREG|NASL, RESC1|RESCC, + "ZG", }, + +{ SCONV, INBREG, + SBREG|AWD, TBREG, + SANY, TANY, + NBREG|NBSL, RESC1|RESCC, + "ZG", }, + +{ SCONV, INBREG, + SAREG|AWD, TAREG, + SANY, TANY, + NBREG|NBSL, RESC1|RESCC, + "ZG", }, + +{ GOTO, FOREFF, + SCON, TANY, + SANY, TANY, + 0, RNOP, + " ZJ\n", }, + +{ GOTO, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, RNOP, + " jmp (AL)\n", }, + +{ STARG, FOREFF, + SCON|SAREG, TANY, + SANY, TANY, + NSPECIAL, RNOP, + "ZS", }, + +{ ADDROF, INAREG, + SNAME, TANY, + SAREG, TANY, + NAREG, RESC1, + " movab AL,A1\n", }, + +{ STASG, FOREFF, + SNAME|SOREG, TANY, + SCON|SAREG, TANY, + NSPECIAL, RNOP, + "ZS", }, + +{ STASG, INAREG, + SNAME|SOREG, TANY, + SCON, TANY, + NSPECIAL|NAREG, RDEST, + "ZS movl AR,A1\n", }, + +{ STASG, INAREG, + SNAME|SOREG, TANY, + SAREG, TANY, + NSPECIAL, RDEST, + " pushl AR\nZS movl (%sp)+,AR\n", }, + +{ FLD, INAREG|INAREG, + SANY, TANY, + SFLD, TANYSIGNED, + NAREG|NASR, RESC1, + " extv H,S,AR,A1\n", }, + +{ FLD, INAREG|INAREG, + SANY, TANY, + SFLD, TANYUSIGNED, + NAREG|NASR, RESC1, + " extzv H,S,AR,A1\n", }, + +#if 0 +{ FLD, FORARG, + SANY, TANY, + SFLD, ANYSIGNED, + 0, RNULL, + " extv H,S,AR,-(%sp)\n", }, + +{ FLD, FORARG, + SANY, TANY, + SFLD, ANYUSIGNED, + 0, RNULL, + " extzv H,S,AR,-(%sp)\n", }, +#endif + +{ OPLOG, FORCC, + SBREG|AWD, TLONGLONG|TULONGLONG, + SBREG|AWD, TLONGLONG|TULONGLONG, + 0, 0, + "ZB", }, + +{ OPLOG, FORCC, + SAREG|AWD, TWORD, + SAREG|AWD, TWORD, + 0, RESCC, + " cmpl AL,AR\n", }, + +{ OPLOG, FORCC, + SAREG|AWD, TSHORT|TUSHORT, + SAREG|AWD, TSHORT|TUSHORT, + 0, RESCC, + " cmpw AL,AR\n", }, + +{ OPLOG, FORCC, + SAREG|AWD, TCHAR|TUCHAR, + SAREG|AWD, TCHAR|TUCHAR, + 0, RESCC, + " cmpb AL,AR\n", }, + +{ OPLOG, FORCC, + SAREG|AWD, TSHORT|TUSHORT, + SSCON, TANY, + 0, RESCC, + " cmpw AL,AR\n", }, + +{ OPLOG, FORCC, + SAREG|AWD, TCHAR|TUCHAR, + SCCON, TANY, + 0, RESCC, + " cmpb AL,AR\n", }, + +{ OPLOG, FORCC, + SBREG|AWD, TDOUBLE, + SBREG|AWD, TDOUBLE, + 0, RESCC, + " cmpd AL,AR\n", }, + +{ OPLOG, FORCC, + SAREG|AWD, TFLOAT, + SAREG|AWD, TFLOAT, + 0, RESCC, + " cmpf AL,AR\n", }, + +{ CCODES, INAREG|INAREG, + SANY, TANY, + SANY, TANY, + NAREG, RESC1, + " movl $1,A1\nZN", }, + +/* + * Subroutine calls. + */ + +{ CALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " calls ZC,CL\n", }, + +{ UCALL, FOREFF, + SCON, TANY, + SANY, TANY, + 0, 0, + " calls $0,CL\n", }, + +{ CALL, INAREG, + SCON, TANY, + SANY, TAREG, + NAREG|NASL, RESC1, /* should be register 0 */ + " calls ZC,CL # 1\n", }, + +{ UCALL, INAREG, + SCON, TANY, + SANY, TAREG, + NAREG|NASL, RESC1, /* should be register 0 */ + " calls $0,CL\n", }, + +{ CALL, INBREG, + SCON, TANY, + SANY, TBREG, + NBREG|NBSL, RESC1, /* should be register 0 */ + " calls ZC,CL # 2\n", }, + +{ UCALL, INBREG, + SCON, TANY, + SANY, TBREG, + NBREG|NASL, RESC1, /* should be register 0 */ + " calls $0,CL\n", }, + +{ CALL, INBREG, + SAREG, TANY, + SANY, TBREG, + NBREG|NBSL, RESC1, /* should be 0 */ + " calls ZC,(AL)\n", }, + +{ UCALL, INBREG, + SAREG, TANY, + SANY, TBREG, + NBREG|NBSL, RESC1, /* should be 0 */ + " calls ZC,(AL)\n", }, + +{ CALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, /* should be 0 */ + " calls ZC,(AL)\n", }, + +{ CALL, INAREG, + SAREG, TANY, + SANY, TAREG, + NAREG|NASL, RESC1, /* should be 0 */ + " calls ZC,(AL)\n", }, + +{ UCALL, FOREFF, + SAREG, TANY, + SANY, TANY, + 0, 0, /* should be 0 */ + " calls ZC,(AL)\n", }, + +{ UCALL, INAREG, + SAREG, TANY, + SANY, TAREG, + NAREG|NASL, RESC1, /* should be 0 */ + " calls ZC,(AL)\n", }, + +#if 0 +{ UCALL, FOREFF, + SNAME, TANY, + SANY, TANY, + 0, 0, /* really reg 0 */ + " calls ZC,*AL\n", }, + +{ UCALL, INAREG, + SNAME, TANY, + SANY, TAREG, + NAREG|NASL, RESC1, /* really reg 0 */ + " calls ZC,*AL\n", }, + +{ UCALL, FOREFF, + SSOREG, TANY, + SANY, TANY, + 0, 0, /* really reg 0 */ + " calls ZC,*AL\n", }, + +{ UCALL, INAREG, + SSOREG, TANY, + SANY, TAREG, + NAREG|NASL, RESC1, /* really reg 0 */ + " calls ZC,*AL\n", }, +#endif + +{ STCALL, INAREG, + SCON, TANY, + SANY, TAREG, + NAREG|NASL, RESC1, /* should be register 0 */ + " calls ZC,CL\n", }, + +{ STCALL, FOREFF, + SCON, TANY, + SANY, TAREG, + NAREG|NASL, 0, /* should be register 0 */ + " calls ZC,CL\n", }, + +{ STCALL, INAREG, + SAREG, TANY, + SANY, TAREG, + NAREG|NASL, RESC1, /* should be 0 */ + " calls ZC,(AL)\n", }, + +{ STCALL, FOREFF, + SAREG, TANY, + SANY, TAREG, + NAREG|NASL, 0, /* should be 0 */ + " calls ZC,(AL)\n", }, + +/* + * Function arguments + */ +{ FUNARG, FOREFF, + SCON|SAREG|SNAME|SOREG, TANY, + SANY, TWORD|TPOINT|TFLOAT, + 0, RNULL, + " pushl AL\n" }, + +{ FUNARG, FOREFF, + SCON|SBREG|SNAME|SOREG, TLL|TDOUBLE, + SANY, TANY, + 0, RNULL, + " movq Zl,-(%sp)\n" }, + +/* RS for signed <= int converted to negative LS */ +#if 0 +/* RS ulonglong converted to function call */ +/* RS longlong converted to negative LS */ +{ RS, INBREG|FORCC, + SBREG|AWD, TLONGLONG, + SAREG|SBREG|AWD, TANY, + NBREG|NBSL|NBSR, RESC1|RESCC, + " ashq AR,AL,A1\n", }, +#endif + +{ RS, INAREG|FORCC, + SAREG, TUCHAR, + SAREG|SAWM, TANYFIXED, + NAREG, RLEFT|RESCC, + " subl3 AR,$8,A1\n extzv AR,A1,AL,AL\n", }, + +{ RS, INAREG|FORCC, + SAREG, TUSHORT, + SAREG|SAWM, TANYFIXED, + NAREG, RLEFT|RESCC, + " subl3 AR,$16,A1\n extzv AR,A1,AL,AL\n", }, + +{ RS, INAREG|FORCC, + SAREG, TUNSIGNED, + SAREG|SAWM, TANYFIXED, + NAREG, RLEFT|RESCC, + " subl3 AR,$32,A1\n extzv AR,A1,AL,AL\n", }, + +{ RS, INAREG|FORCC, + SAREG, TUNSIGNED|TUSHORT|TUCHAR, + SCON, TANY, + NAREG|NASL, RESC1|RESCC, + " extzv AR,ZU,AL,A1\n", }, + +/* extv only for short and char, rest uses ashl/q */ +{ RS, INAREG|FORCC, + SAREG, TSHORT|TCHAR, + SCON, TANY, + NAREG|NASL, RESC1|RESCC, + " extv AR,ZU,AL,A1\n", }, + +{ LS, INBREG|FORCC, + SBREG|AWD, TLL, + SAREG|SBREG|AWD, TANY, + NBREG|NBSL|NBSR, RESC1|RESCC, + " ashq AR,Zl,A1\n", }, + +{ LS, INAREG|INAREG|FORCC, + SAREG|AWD, TANYFIXED, + SAREG|AWD, TANYFIXED, + NAREG|NASL|NASR, RESC1|RESCC, + " ashl AR,AL,A1\n", }, + +#if 0 +{ INCR, FOREFF, + SAREG|AWD, TANY, + SANY, TANY, + 0, RLEFT, + " ZE\n", }, + +{ DECR, FOREFF, + SAREG|AWD, TANY, + SCON, TANY, + 0, RLEFT, + " ZE\n", }, + +{ INCR, INAREG|INAREG, + SAREG|AWD, TANY, + SCON, TANY, + NAREG, RESC1, + " ZD\n", }, + +{ DECR, INAREG|INAREG, + SAREG|AWD, TANY, + SCON, TANY, + NAREG, RESC1, + " ZD\n", }, +#endif + +/* Assign to 64-bit register, three entries */ +/* Have FOREFF first to catch mem-mem moves */ +{ ASSIGN, FOREFF, + SBREG|AWD, TBREG, + SCON, TBREG, + 0, 0, + "ZA", }, + +{ ASSIGN, FOREFF, + SBREG|AWD, TBREG, + SBREG|AWD, TBREG, + 0, 0, + " movq Zr,AL\n", }, + +{ ASSIGN, INBREG, + SBREG, TBREG, + SBREG|AWD, TBREG, + 0, RDEST, + " movq Zr,AL\n", }, + +{ ASSIGN, INBREG, + SBREG|AWD, TBREG, + SBREG, TBREG, + 0, RDEST, + " movq AR,AL\n", }, + +/* Assign to 32-bit register, three entries */ +{ ASSIGN, FOREFF|FORCC, + SAREG|AWD, TAREG, + SCON, TAREG, + 0, RESCC, + "ZA", }, + +{ ASSIGN, FOREFF|FORCC, + SAREG|AWD, TAREG, + SAREG|AWD, TAREG, + 0, RESCC, + " movZL AR,AL\n", }, + +{ ASSIGN, INAREG|FORCC, + SAREG, TAREG, + SAREG|AWD, TAREG, + 0, RDEST|RESCC, + " movZL AR,AL\n", }, + +{ ASSIGN, INAREG|FORCC, + SAREG|AWD, TAREG, + SAREG, TAREG, + 0, RDEST|RESCC, + " movZL AR,AL\n", }, + +/* Bitfields, not yet */ +{ ASSIGN, INAREG|FOREFF|FORCC, + SFLD, TANY, + SAREG|AWD, TWORD, + 0, RDEST|RESCC, + " insv AR,H,S,AL\n", }, + +{ ASSIGN, INAREG|FOREFF|FORCC, + SAREG|AWD, TWORD, + SFLD, TANYSIGNED, + 0, RDEST|RESCC, + " extv H,S,AR,AL\n", }, + +{ ASSIGN, INAREG|FOREFF|FORCC, + SAREG|AWD, TWORD, + SFLD, TANYUSIGNED, + 0, RDEST|RESCC, + " extzv H,S,AR,AL\n", }, + +/* dummy UNARY MUL entry to get U* to possibly match OPLTYPE */ +{ UMUL, FOREFF, + SCC, TANY, + SCC, TANY, + 0, RNULL, + " HELP HELP HELP\n", }, + +{ UMUL, INBREG, + SANY, TPOINT, + SOREG, TBREG, + NBREG|NBSL, RESC1, + " movq AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TWORD, + SOREG, TPOINT|TWORD, + NAREG|NASL, RESC1, + " movl AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TSHORT|TUSHORT, + SOREG, TPOINT|TSHORT|TUSHORT, + NAREG|NASL, RESC1, + " movw AL,A1\n", }, + +{ UMUL, INAREG, + SANY, TPOINT|TCHAR|TUCHAR, + SOREG, TPOINT|TCHAR|TUCHAR, + NAREG|NASL, RESC1, + " movb AL,A1\n", }, + +#if 0 +{ REG, FORARG, + SANY, TANY, + SAREG, TDOUBLE|TFLOAT, + 0, RNULL, + " movZR AR,-(%sp)\n", }, + +{ REG, INTEMP, + SANY, TANY, + SAREG, TDOUBLE, + 2*NTEMP, RESC1, + " movd AR,A1\n", }, + +{ REG, INTEMP, + SANY, TANY, + SAREG, TANY, + NTEMP, RESC1, + " movZF AR,A1\n", }, +#endif + +{ OPLTYPE, INBREG, + SANY, TANY, + SCON|SOREG|SNAME, TLONGLONG|TULONGLONG, + NBREG, RESC1, + " movq Zl,A1\n", }, + +{ OPLTYPE, INBREG, + SANY, TANY, + SANY, TBREG, + NBREG|NBSR, RESC1, + " movZR AR,A1\n", }, + +{ OPLTYPE, INAREG|INAREG, + SANY, TANY, + SANY, TAREG, + NAREG|NASR, RESC1, + " movZR AR,A1\n", }, + +{ OPLTYPE, FORCC, + SANY, TANY, + SANY, TANY, + 0, RESCC, + " tstZR AR\n", }, + +#if 0 +{ OPLTYPE, FORARG, + SANY, TANY, + SANY, TWORD, + 0, RNULL, + " pushl AR\n", }, + +{ OPLTYPE, FORARG, + SANY, TANY, + SANY, TCHAR|TSHORT, + 0, RNULL, + " cvtZRl AR,-(%sp)\n", }, + +{ OPLTYPE, FORARG, + SANY, TANY, + SANY, TUCHAR|TUSHORT, + 0, RNULL, + " movzZRl AR,-(%sp)\n", }, + +{ OPLTYPE, FORARG, + SANY, TANY, + SANY, TDOUBLE, + 0, RNULL, + " movd AR,-(%sp)\n", }, + +{ OPLTYPE, FORARG, + SANY, TANY, + SANY, TFLOAT, + 0, RNULL, + " cvtfd AR,-(%sp)\n", }, +#endif + +{ UMINUS, INBREG, + SBREG|AWD, TLL, + SANY, TLL, + NBREG|NBSL, RESC1|RESCC, + " mnegl UL,U1\n mnegl AL,A1\n sbwc $0,U1\n", }, + +{ UMINUS, INAREG|FORCC, + SAREG|AWD, TAREG|TDOUBLE, + SANY, TANY, + NAREG|NASL, RESC1|RESCC, + " mnegZL AL,A1\n", }, + +{ UMINUS, INBREG|FORCC, + SBREG|AWD, TDOUBLE, + SANY, TANY, + NBREG|NASL, RESC1|RESCC, + " mnegZL AL,A1\n", }, + +{ COMPL, INBREG, + SBREG|AWD, TLL, + SANY, TLL, + NBREG|NBSL, RESC1|RESCC, + " mcoml AL,A1\n mcoml UL,U1\n", }, + +{ COMPL, INAREG|FORCC, + SAREG|AWD, TINT|TUNSIGNED, + SANY, TANY, + NAREG|NASL, RESC1|RESCC, + " mcomZL AL,A1\n", }, + +{ COMPL, INAREG|FORCC, + SAREG|AWD, TANYSIGNED|TANYUSIGNED, + SANY, TANY, + NAREG|NASL, RESC1|RESCC, + " cvtZLl AL,A1\n mcoml A1,A1\n", }, + +{ AND, FORCC, + SAREG|AWD, TWORD, + SCON, TWORD, + 0, RESCC, + " bitl ZZ,AL\n", }, + +{ AND, FORCC, + SAREG|AWD, TSHORT|TUSHORT, + SSCON, TWORD, + 0, RESCC, + " bitw ZZ,AL\n", }, + +{ AND, FORCC, + SAREG|AWD, TCHAR|TUCHAR, + SCCON, TWORD, + 0, RESCC, + " bitb ZZ,AL\n", }, + +{ MUL, INAREG|FORCC, + SAREG|AWD, TANYFIXED, + SAREG|AWD, TANYFIXED, + NAREG|NASL|NASR, RESC1|RESCC, + " mulZL3 AR,AL,A1\n", }, + +{ OPMUL, INAREG|INAREG|FORCC, + SAREG, TINT|TUNSIGNED|TLONG|TULONG, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + 0, RLEFT|RESCC, + " OL2 AR,AL\n", }, + +{ OPMUL, INAREG|INAREG|FORCC, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, + NAREG|NASL|NASR, RESC1|RESCC, + " OL3 AR,AL,A1\n", }, + +{ MOD, INAREG|INAREG, + SAREG|AWD, TINT, + SAREG|AWD, TINT, + NAREG, RESC1, + " divl3 AR,AL,A1\n mull2 AR,A1\n subl3 A1,AL,A1\n", }, + +{ PLUS, INBREG|FORCC, + SBREG, TLL, + SBREG|AWD, TLL, + 0, RLEFT, + " addl2 AR,AL\n" + " adwc UR,UL\n", }, + +{ PLUS, INAREG|FORCC, + SAREG, TANYFIXED, + SONE, TANY, + 0, RLEFT|RESCC, + " incZL AL\n", }, + +{ MINUS, INAREG|FORCC, + SAREG, TANYFIXED, + SONE, TANY, + 0, RLEFT|RESCC, + " decZL AL\n", }, + +{ MINUS, INBREG|FORCC, + SBREG, TLL, + SBREG|AWD, TLL, + 0, RLEFT, + " subl2 AR,AL\n" + " sbwc UR,UL\n", }, +{ DIV, INBREG, + SBREG|AWD, TLL, + SBREG|AWD, TLL, + NSPECIAL|NBREG|NBSL|NBSR, RESC1, + "ZO", }, + +{ MOD, INBREG, + SBREG|AWD, TLL, + SBREG|AWD, TLL, + NSPECIAL|NBREG|NBSL|NBSR, RESC1, + "ZO", }, + +{ MUL, INBREG, + SBREG|AWD, TLL, + SBREG|AWD, TLL, + NSPECIAL|NBREG|NBSL|NBSR, RESC1, + "ZO", }, + +{ OR, INBREG, + SBREG, TLL, + SBREG|AWD, TLL, + 0, RLEFT, + " bisl2 AR,AL\n bisl2 UR,UL\n", }, + +{ OR, INBREG, + SBREG|AWD, TLL, + SBREG|AWD, TLL, + NBREG, RESC1, + " bisl3 AR,AL,A1\n bisl3 UR,UL,U1\n", }, + +{ ER, INBREG, + SBREG, TLL, + SBREG|AWD, TLL, + 0, RLEFT, + " xorl2 AR,AL\n xorl2 UR,UL\n", }, + +{ ER, INBREG, + SBREG|AWD, TLL, + SBREG|AWD, TLL, + NBREG, RESC1, + " xorl3 AR,AL,A1\n xorl3 UR,UL,U1\n", }, + +{ AND, INBREG, + SBREG, TLL, + SBREG|AWD, TLL, + 0, RLEFT, + " bicl2 AR,AL\n bicl2 UR,UL\n", }, + +{ AND, INBREG, + SBREG|AWD, TLL, + SBREG|AWD, TLL, + NBREG, RESC1, + " bicl3 AR,AL,A1\n bicl3 UR,UL,U1\n", }, + +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG, TWORD, + SAREG|AWD, TWORD, + 0, RLEFT|RESCC, + " OL2 AR,AL\n", }, + +{ OPSIMP, INAREG|FORCC, + SAREG|AWD, TWORD, + SAREG|AWD, TWORD, + NAREG|NASL|NASR, RESC1|RESCC, + " OL3 AR,AL,A1\n", }, + +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG, TSHORT|TUSHORT, + SAREG|AWD, TSHORT|TUSHORT, + 0, RLEFT|RESCC, + " OW2 AR,AL\n", }, + +{ OPSIMP, INAREG|FORCC, + SAREG|AWD, TSHORT|TUSHORT, + SAREG|AWD, TSHORT|TUSHORT, + NAREG|NASL|NASR, RESC1|RESCC, + " OW3 AR,AL,A1\n", }, + +{ OPSIMP, INAREG|FOREFF|FORCC, + SAREG, TCHAR|TUCHAR, + SAREG|AWD, TCHAR|TUCHAR, + 0, RLEFT|RESCC, + " OB2 AR,AL\n", }, + +{ OPSIMP, INAREG|FORCC, + SAREG|AWD, TCHAR|TUCHAR, + SAREG|AWD, TCHAR|TUCHAR, + NAREG|NASL|NASR, RESC1|RESCC, + " OB3 AR,AL,A1\n", }, + +{ OPFLOAT, INAREG|FORCC, + SAREG, TFLOAT, + SAREG|AWD, TFLOAT, + 0, RLEFT|RESCC, + " OF2 AR,AL\n", }, + +{ OPFLOAT, INAREG|FORCC, + SAREG|AWD, TFLOAT, + SAREG|AWD, TFLOAT, + NAREG|NASL|NASR, RESC1|RESCC, + " OF3 AR,AL,A1\n", }, + +{ OPFLOAT, INBREG|FORCC, + SBREG, TDOUBLE, + SBREG|AWD, TDOUBLE, + 0, RLEFT|RESCC, + " OD2 AR,AL\n", }, + +{ OPFLOAT, INBREG|FORCC, + SBREG|AWD, TDOUBLE, + SBREG|AWD, TDOUBLE, + NBREG|NBSL|NBSR, RESC1|RESCC, + " OD3 AR,AL,A1\n", }, + +#if 0 /* XXX probably wrong */ +{ OPFLOAT, INAREG|INAREG|FORCC, + SAREG|AWD, TFLOAT, + SAREG|AWD, TDOUBLE, + NAREG|NASL, RESC1|RESCC, + " cvtfd AL,A1\n OD2 AR,A1\n", }, + +{ OPFLOAT, INAREG|INAREG|FORCC, + SAREG|AWD, TDOUBLE, + SAREG|AWD, TFLOAT, + NAREG|NASR, RESC1|RESCC, + " cvtfd AR,A1\n OD3 A1,AL,A1\n", }, + +{ OPFLOAT, INAREG|INAREG|FORCC, + SAREG|AWD, TFLOAT, + SAREG|AWD, TFLOAT, + NAREG|NASL|NASR, RESC1|RESCC, + " OF3 AR,AL,A1\n cvtfd A1,A1\n", }, +#endif + + /* Default actions for hard trees ... */ + +# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" + +{ UMUL, DF( UMUL ), }, + +{ ASSIGN, DF(ASSIGN), }, + +{ STASG, DF(STASG), }, + +{ OPLEAF, DF(NAME), }, + +{ OPLOG, FORCC, + SANY, TANY, + SANY, TANY, + REWRITE, BITYPE, + "", }, + +{ OPUNARY, DF(UMINUS), }, + +{ OPANY, DF(BITYPE), }, + +{ FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" } +}; diff --git a/lang/pcc/pcc/cc/Makefile.in b/lang/pcc/pcc/cc/Makefile.in new file mode 100644 index 000000000..710139bf2 --- /dev/null +++ b/lang/pcc/pcc/cc/Makefile.in @@ -0,0 +1,28 @@ +# $Id: Makefile.in,v 1.9 2012/01/01 16:27:25 ragge Exp $ +# +# Makefile.in for top-level of pcc. +# + +@SET_MAKE@ + +ALL_SUBDIRS= cc cpp ccom cxxcom +DIST_SUBDIRS= $(ALL_SUBDIRS) driver + +all install clean: + @for subdir in $(ALL_SUBDIRS); do \ + _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ + echo "===> $$_nextdir_"; \ + (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ + exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ + echo "<=== $$_nextdir_"; \ + done + +distclean: + @for subdir in $(DIST_SUBDIRS); do \ + _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ + echo "===> $$_nextdir_"; \ + (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ + exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ + echo "<=== $$_nextdir_"; \ + done + rm -f Makefile diff --git a/lang/pcc/pcc/cc/cc/Makefile.in b/lang/pcc/pcc/cc/cc/Makefile.in new file mode 100644 index 000000000..34266f88c --- /dev/null +++ b/lang/pcc/pcc/cc/cc/Makefile.in @@ -0,0 +1,82 @@ +# $Id: Makefile.in,v 1.37 2016/03/08 18:42:13 ragge Exp $ +# +# Makefile.in for the cc part of pcc. +# +VPATH=@srcdir@ +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +top_builddir=@top_builddir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +includedir = @includedir@ +datarootdir = @datarootdir@ +mandir = @mandir@ +CC = @CC@ +EXEEXT = @EXEEXT@ +BINPREFIX = @BINPREFIX@ +TARGOS = @targos@ +TARGOSVER = @targosver@ +TARGMACH = @targmach@ +TARGET = @target@ +VERSION = @PACKAGE_VERSION@ +PCCLIBDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/lib +PCCINCDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/include +CFLAGS = @CFLAGS@ @ADD_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ -DLIBEXECDIR=\"$(libexecdir)/\" \ + @ADD_CPPFLAGS@ -DINCLUDEDIR=\"$(includedir)/\" \ + -DPCCINCDIR=\"$(PCCINCDIR)/\" -DPCCLIBDIR=\"$(PCCLIBDIR)/\" \ + -Dos_$(TARGOS) -Dmach_$(TARGMACH) -DTARGOSVER=$(TARGOSVER) \ + -DCXXPROGNAME=\"$(BINPREFIX)p++$(EXEEXT)\" \ + -DCPPROGNAME=\"$(BINPREFIX)pcpp$(EXEEXT)\" \ + -I$(top_srcdir)/cc/driver -I$(top_builddir) \ + -I$(top_srcdir)/os/$(TARGOS) -I$(MIPDIR) -I$(MDIR) -I$(COMMONDIR) +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +MIPDIR=$(top_srcdir)/mip +MDIR=$(top_srcdir)/arch/$(TARGMACH) +COMMONDIR=$(top_srcdir)/common + +DEST=cc$(EXEEXT) +DRIVERS=pcc pcpp p++ + +all: $(DEST) + +OBJS= cc.o compat.o strlist.o xalloc.o + +cc.o: $(srcdir)/cc.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cc.c + +compat.o: $(COMMONDIR)/compat.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c + +strlist.o: $(top_srcdir)/cc/driver/strlist.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(top_srcdir)/cc/driver/strlist.c + +xalloc.o: $(top_srcdir)/cc/driver/xalloc.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(top_srcdir)/cc/driver/xalloc.c + +$(DEST): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) + +install: + test -z "$(DESTDIR)$(bindir)" || mkdir -p "$(DESTDIR)$(bindir)" + test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1" + @for driver in $(DRIVERS); do \ + $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(bindir)/$(BINPREFIX)$$driver$(EXEEXT); \ + $(INSTALL_DATA) $(srcdir)/cc.1 $(DESTDIR)$(mandir)/man1/$$driver.1; \ + done + test -z "$(DESTDIR)$(PCCINCDIR)" || mkdir -p "$(DESTDIR)$(PCCINCDIR)" + test -z "$(DESTDIR)$(PCCLIBDIR)" || mkdir -p "$(DESTDIR)$(PCCLIBDIR)" + +clean: + rm -f $(OBJS) $(DEST) + +distclean: clean + rm -f Makefile diff --git a/lang/pcc/pcc/cc/cc/cc.1 b/lang/pcc/pcc/cc/cc/cc.1 new file mode 100644 index 000000000..1dd60b1d2 --- /dev/null +++ b/lang/pcc/pcc/cc/cc/cc.1 @@ -0,0 +1,395 @@ +.\" $Id: cc.1,v 1.43 2014/12/24 09:55:32 plunky Exp $ +.\" +.\" Copyright (c) 2007 Jeremy C. Reed +.\" +.\" Permission to use, copy, modify, and/or distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM +.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND +.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +.\" THIS SOFTWARE. +.\" +.Dd June 20, 2014 +.Dt CC 1 +.Os +.Sh NAME +.Nm cc +.Nd front-end to the C compiler +.Sh SYNOPSIS +.Nm +.Op Fl cEgkMPStvX +.Op Fl B Ns Ar prefix +.Op Fl D Ar macro Ns Oo = Ns Ar value Oc +.Op Fl d Ns Ar flags +.Op Fl f Ns Ar feature +.Op Fl I Ar path +.Op Fl include Ar file +.Op Fl isystem Ar path +.Op Fl L Ns Ar path +.Op Fl m Ns Ar option +.Op Fl nodefaultlibs +.Op Fl nostartfiles +.Op Fl nostdinc +.Op Fl nostdlib +.Op Fl O Ns Oo Ar level Oc +.Op Fl o Ar outfile +.Op Fl pg +.Op Fl pthread +.Op Fl shared +.Op Fl static +.Op Fl U Ar macro +.Op Fl Wa Ns , Ns Ar options +.Op Fl Wc Ns , Ns Ar options +.Op Fl Wl Ns , Ns Ar options +.Op Fl Wp Ns , Ns Ar options +.Op Fl x Ar language +.Op Ar +.Sh DESCRIPTION +The +.Nm +utility provides a front-end to the +.Dq portable C compiler . +Multiple files may be given on the command line. +Unrecognized options are all sent directly to +.Xr ld 1 . +.Pp +.\" Brief description of its syntax: +Filenames that end with +.Sy \&.c +are passed via +.Xr cpp 1 +\(-> +.Xr ccom 1 +\(-> +.Xr as 1 +\(-> +.Xr ld 1 . +.Pp +Filenames that end with +.Sy \&.i +are passed via +.Xr ccom 1 +\(-> +.Xr as 1 +\(-> +.Xr ld 1 . +.Pp +Filenames that end with +.Sy \&.s +are passed via +.Xr as 1 +\(-> +.Xr ld 1 . +.Pp +Filenames that end with +.Sy \&.S +are passed via +.Xr cpp 1 +\(-> +.Xr as 1 +\(-> +.Xr ld 1 . +.Pp +Filenames that end with +.Sy \&.o +are passed directly to +.Xr ld 1 . +.Pp +.\" +The options are as follows: +.Bl -tag -width Ds +.It Fl B Ns Ar prefix +Define alternate prefix path for +.Xr cpp 1 , +.Xr ccom 1 , +.Xr as 1 , +or +.Xr ld 1 +executables. +.\" TODO: provide an example of -B +.It Fl C +Passed to the +.Xr cpp 1 +preprocessor to not discard comments. +.It Fl c +Stop after generating object code with +.Xr as 1 . +Do not link. +The resulting object output is saved +as a filename with a +.Dq \&.o +suffix unless +.Fl o +option is used. +Note: cannot be combined with +.Fl o +if multiple files are given. +.It Fl D Ar macro Ns Oo = Ns Ar value Oc +Passed to the +.Xr cpp 1 +preprocessor to define +.Ar macro +with an optional +.Ar value . +.It Fl d Ns Ar flags +Debug options. +.Ar flags +is a string of characters, which signify the following actions. +.Bl -tag -width ".Sy M" +.It Sy M +Cause the preprocessor to output a list of macro definitions. +.El +.Lp +any unknown flags are ignored. +.It Fl E +Stop after preprocessing with +.Xr cpp 1 . +Do not compile, assemble, or link. +Output is sent to standard output unless the +.Fl o +option is used. +.It Fl ffreestanding +Assume a freestanding environment. +.It Fl fPIC +Generate PIC code. +.\" TODO: document about avoiding machine-specific maximum size? +.It Fl fpic +Tells C compiler to generate PIC code +and tells assembler that PIC code has been generated. +.\" TODO: document difference between PIC and pic +.It Fl funsigned-char +Tell the compiler to treat +.Sq char +types as if they were unsigned unless explicitly defined otherwise. +.Fl fsigned-char +can be used to signify the opposite behaviour. +The default for the +.Sq char +type depends on the compiler target architecture. +.It Fl fstack-protector +Tell the compiler to wrap functions with code which checks at +runtime that a stack overflow has not occurred. +When stack protection is in effect, the +.Dv __SSP__ +macro will be defined. +.\" other -f GCC compatibility flags are ignored for now +.It Fl g +Send +.Fl g +flag to +.Xr ccom 1 +to create debug output. +Debug information output can be disabled with +.Fl g0 . +.It Fl I Ar path +Passed to the +.Xr cpp 1 +preprocessor to add header search directory to override system defaults. +.It Fl include Ar file +Tells the +.Xr cpp 1 +preprocessor to include the +.Ar file +during preprocessing. +.It Fl isystem Ar path +Defines +.Ar path +as a system header directory for the +.Xr cpp 1 +preprocessor. +.It Fl k +Generate PIC code. +See +.Fl fpic +option. +.It Fl L Ns Ar path +Passed to the linker, to add +.Ar path +to the list of directories searched for shared libraries. +.It Fl M +Pass +.Fl M +flag to +.Xr cpp 1 +to generate dependencies for +.Xr make 1 . +.It Fl m Ns Ar option +Target-dependent options. +Multiple +.Fl m +options can be given, the following are supported: +.Bl -tag -width PowerPC +.It ARM +\-mlittle-endian \-mbig-endian \-mfpe=fpa \-mfpe=vpf \-msoft-float \-march=armv1 \-march=armv2 \-march=armv2a \-march=armv3 \-march=armv4 \-march=armv4t \-march=armv4tej \-march=armv5 \-march=armv6 \-march=armv6t2 \-march=armv6kz \-march=armv6k \-march=armv7 +.It HPPA +.It i386 +.It MIPS +\-mlittle-endian \-mbig-endian \-mhard-float \-msoft-float +.It PDP-10 +.It PowerPC +.It Sparc64 +.It VAX +.El +.It Fl nodefaultlibs +Do not link with the system default libraries (libc, etc.) +.It Fl nostartfiles +Do not link with the system startup files (crt0.c, etc.) +.It Fl nostdinc +Do not use the system include paths (/usr/include, etc.) +.It Fl nostdlib +Do not link with the system default libraries or startup files. +.It Fl O Ns Oo Ar level Oc +Enable compiler optimizations. +Currently, for levels higher than zero, +this defines +.Dv __OPTIMIZE__ +in the +.Xr cpp 1 +preprocessor, and passes +.Fl xdce , +.Fl xdeljumps , +.Fl xtemps +and +.Fl xinline +to +.Xr ccom 1 . +If no level is given the optimization level is increased, or +optimizations can be disabled using +.Fl O0 . +.It Fl o Ar outfile +Save result to +.Ar outfile . +.It Fl P +Inhibit generation of line markers in preprocessor output. +This is sometimes useful when running the preprocessor on something other than C code. +.It Fl pg +Enable profiling on the generated executable. +.It Fl pthread +Defines the +.Dv _PTHREADS +preprocessor identifier for +.Xr cpp 1 , and +adds +.Fl lpthread +to the +.Xr ld 1 +linker arguments. +.It Fl S +Stop after compilation by +.Xr ccom 1 . +Do not assemble and do not link. +The resulting assembler-language output is saved +as a filename with a +.Dq \&.s +suffix unless the +.Fl o +option is used. +Note: cannot be combined with +.Fl o +if multiple files are given. +.It Fl shared +Create a shared object of the result. +Tells the linker not to generate an executable. +.It Fl static +Do not use dynamic linkage. +By default, it will link using the dynamic linker options +and/or shared objects for the platform. +.It Fl t +Passed to +.Xr cpp 1 +to suppress some default macro definitions and enable use +of traditional C preprocessor syntax. +.It Fl U Ar macro +Passes to the +.Xr cpp 1 +preprocessor to remove the initial macro definition. +.It Fl v +Outputs the version of +.Nm +and shows commands as they are run with their command line arguments. +.It Fl ### +As per +.Fl v +except that the commands are not run, and the arguments will be quoted +if they contain unusual characters or spaces. +.It Fl Wa Ns , Ns Ar options +Comma separated list of options for the assembler. +.It Fl Wc Ns , Ns Ar options +Comma separated list of options for the compiler. +.It Fl Wl Ns , Ns Ar options +Comma separated list of options for the linker. +.It Fl Wp Ns , Ns Ar options +Comma separated list of options for the preprocessor. +.It Fl X +Don't remove temporary files on exit. +.It Fl x Ar language +GCC compatibility option; specify the language in use rather than +interpreting the filename extension. +Currently known language values are +.Sy none , +.Sy c , +.Sy c++ , +.Sy assembler +and +.Sy assembler-with-cpp . +Any unknown +.Fl x +options are passed to +.Xr ccom 1 . +.El +.Ss Predefined Macros +A few +macros are predefined by +.Nm +when sent to +.Xr cpp 1 . +.Bl -diag +.It __PCC__ +Set to the major version of +.Xr pcc 1 . +These macros can be used to select code based on +.Xr pcc 1 +compatibility. +See the +.Fl v +option. +.It __PCC_MINOR__ +Set to the minor version. +.It __PCC_MINORMINOR__ +Set to the minor-minor version \(em the number after the minor version. +.It _PTHREADS +Defined when +.Fl pthread +switch is used. +.It __ASSEMBLER__ +Defined when input files have a .S suffix, or if the +.Fl x Ns assembler-with-cpp +option is specified. +.El +.Pp +Also system- and/or machine-dependent macros may also be predefined; +for example: +.Dv __NetBSD__ , +.Dv __ELF__ , +and +.Dv __i386__ . +.Sh SEE ALSO +.Xr as 1 , +.Xr ccom 1 , +.Xr cpp 1 , +.Xr ld 1 +.Sh HISTORY +The +.Nm +command comes from the original Portable C Compiler by +.An "S. C. Johnson" , +written in the late 70's. +.Pp +This product includes software developed or owned by Caldera +International, Inc. diff --git a/lang/pcc/pcc/cc/cc/cc.c b/lang/pcc/pcc/cc/cc/cc.c new file mode 100644 index 000000000..da01b68f0 --- /dev/null +++ b/lang/pcc/pcc/cc/cc/cc.c @@ -0,0 +1,2132 @@ +/* $Id: cc.c,v 1.305 2016/02/23 11:14:08 ragge Exp $ */ + +/*- + * Copyright (c) 2011 Joerg Sonnenberger . + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND 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 + * COPYRIGHT HOLDERS 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. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ + +/* + * Front-end to the C compiler. + * + * Brief description of its syntax: + * - Files that end with .c are passed via cpp->ccom->as->ld + * - Files that end with .i are passed via ccom->as->ld + * - Files that end with .S are passed via cpp->as->ld + * - Files that end with .s are passed via as->ld + * - Files that end with .o are passed directly to ld + * - Multiple files may be given on the command line. + * - Unrecognized options are all sent directly to ld. + * -c or -S cannot be combined with -o if multiple files are given. + * + * This file should be rewritten readable. + */ +#include "config.h" + +#include +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#include +#include +#include +#ifdef HAVE_LIBGEN_H +#include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#define F_OK 0x00 +#define R_OK 0x04 +#define W_OK 0x02 +#define X_OK R_OK +#endif + +#include "compat.h" + +#include "macdefs.h" + +#include "xalloc.h" +#include "strlist.h" + +#include "ccconfig.h" +/* C command */ + +#define MKS(x) _MKS(x) +#define _MKS(x) #x + +/* default program names in pcc */ +/* May be overridden if cross-compiler is generated */ +#ifndef CXXPROGNAME /* name as C++ front end */ +#define CXXPROGNAME "c++" +#endif +#ifndef CPPROGNAME +#define CPPROGNAME "cpp" /* name as CPP front end */ +#endif +#ifndef PREPROCESSOR +#define PREPROCESSOR "cpp" /* "real" preprocessor name */ +#endif +#ifndef COMPILER +#define COMPILER "ccom" +#endif +#ifndef CXXCOMPILER +#define CXXCOMPILER "cxxcom" +#endif +#ifndef ASSEMBLER +#define ASSEMBLER "as" +#endif +#ifndef LINKER +#define LINKER "ld" +#endif +char *passp = PREPROCESSOR; +char *pass0 = COMPILER; +char *passxx0 = CXXCOMPILER; +char *as = ASSEMBLER; +char *ld = LINKER; +char *sysroot = "", *isysroot; + + +/* crt files using pcc default names */ +#ifndef CRTBEGIN_S +#define CRTBEGIN_S "crtbeginS.o" +#endif +#ifndef CRTEND_S +#define CRTEND_S "crtendS.o" +#endif +#ifndef CRTBEGIN_T +#define CRTBEGIN_T "crtbeginT.o" +#endif +#ifndef CRTEND_T +#define CRTEND_T "crtendT.o" +#endif +#ifndef CRTBEGIN +#define CRTBEGIN "crtbegin.o" +#endif +#ifndef CRTEND +#define CRTEND "crtend.o" +#endif +#ifndef CRTI +#define CRTI "crti.o" +#endif +#ifndef CRTN +#define CRTN "crtn.o" +#endif +#ifndef CRT0 +#define CRT0 "crt0.o" +#endif +#ifndef GCRT0 +#define GCRT0 "gcrt0.o" +#endif + +/* preprocessor stuff */ +#ifndef STDINC +#define STDINC "/usr/include/" +#endif +#ifdef MULTIARCH_PATH +#define STDINC_MA STDINC MULTIARCH_PATH "/" +#endif + + +char *cppadd[] = CPPADD; +char *cppmdadd[] = CPPMDADD; + +/* Default libraries and search paths */ +#ifndef PCCLIBDIR /* set by autoconf */ +#define PCCLIBDIR NULL +#endif +#ifndef LIBDIR +#define LIBDIR "/usr/lib/" +#endif +#ifndef DEFLIBDIRS /* default library search paths */ +#ifdef MULTIARCH_PATH +#define DEFLIBDIRS { LIBDIR, LIBDIR MULTIARCH_PATH "/", 0 } +#else +#define DEFLIBDIRS { LIBDIR, 0 } +#endif +#endif +#ifndef DEFLIBS /* default libraries included */ +#define DEFLIBS { "-lpcc", "-lc", "-lpcc", 0 } +#endif +#ifndef DEFPROFLIBS /* default profiling libraries */ +#define DEFPROFLIBS { "-lpcc", "-lc_p", "-lpcc", 0 } +#endif +#ifndef DEFCXXLIBS /* default c++ libraries */ +#define DEFCXXLIBS { "-lp++", "-lpcc", "-lc", "-lpcc", 0 } +#endif +#ifndef STARTLABEL +#define STARTLABEL "__start" +#endif +#ifndef DYNLINKARG +#define DYNLINKARG "-dynamic-linker" +#endif +#ifndef DYNLINKLIB +#define DYNLINKLIB NULL +#endif + +char *dynlinkarg = DYNLINKARG; +char *dynlinklib = DYNLINKLIB; +char *pcclibdir = PCCLIBDIR; +char *deflibdirs[] = DEFLIBDIRS; +char *deflibs[] = DEFLIBS; +char *defproflibs[] = DEFPROFLIBS; +char *defcxxlibs[] = DEFCXXLIBS; + +char *outfile, *MFfile, *fname; +static char **lav; +static int lac; +static char *find_file(const char *file, struct strlist *path, int mode); +static int preprocess_input(char *input, char *output, int dodep); +static int compile_input(char *input, char *output); +static int assemble_input(char *input, char *output); +static int run_linker(void); +static int strlist_exec(struct strlist *l); + +char *cat(const char *, const char *); +char *setsuf(char *, char); +int cxxsuf(char *); +int getsuf(char *); +char *getsufp(char *s); +int main(int, char *[]); +void errorx(int, char *, ...); +int cunlink(char *); +void exandrm(char *); +void dexit(int); +void idexit(int); +char *gettmp(void); +void oerror(char *); +char *argnxt(char *, char *); +char *nxtopt(char *o); +void setup_cpp_flags(void); +void setup_ccom_flags(void); +void setup_as_flags(void); +void setup_ld_flags(void); +static void expand_sysroot(void); +#ifdef _WIN32 +char *win32pathsubst(char *); +char *win32commandline(struct strlist *l); +#endif +int sspflag; +int freestanding; +int Sflag; +int cflag; +int gflag; +int rflag; +int vflag; +int noexec; /* -### */ +int tflag; +int Eflag; +int Oflag; +int kflag; /* generate PIC/pic code */ +#define F_PIC 1 +#define F_pic 2 +int Mflag, needM, MDflag, MMDflag; /* dependencies only */ +int pgflag; +int Xflag; +int nostartfiles, Bstatic, shared; +int nostdinc, nostdlib; +int pthreads; +int xgnu89, xgnu99, c89defs, c99defs, c11defs; +int ascpp; +#ifdef CHAR_UNSIGNED +int xuchar = 1; +#else +int xuchar = 0; +#endif +int cxxflag; +int cppflag; +int printprogname, printfilename; +enum { SC11, STRAD, SC89, SGNU89, SC99, SGNU99 } cstd; + +#ifdef SOFTFLOAT +int softfloat = 1; +#else +int softfloat = 0; +#endif + +#ifdef TARGET_BIG_ENDIAN +int bigendian = 1; +#else +int bigendian = 0; +#endif + +#ifdef mach_amd64 +int amd64_i386; +#endif + +#define match(a,b) (strcmp(a,b) == 0) + +/* handle gcc warning emulations */ +struct Wflags { + char *name; + int flags; +#define INWALL 1 +} Wflags[] = { + { "truncate", 0 }, + { "strict-prototypes", 0 }, + { "missing-prototypes", 0 }, + { "implicit-int", INWALL }, + { "implicit-function-declaration", INWALL }, + { "shadow", 0 }, + { "pointer-sign", INWALL }, + { "sign-compare", 0 }, + { "unknown-pragmas", INWALL }, + { "unreachable-code", 0 }, + { "deprecated-declarations", 0 }, + { "attributes", 0 }, + { NULL, 0 }, +}; + +#ifndef USHORT +/* copied from mip/manifest.h */ +#define USHORT 5 +#define INT 6 +#define UNSIGNED 7 +#endif + +/* + * Wide char defines. + */ +#if WCHAR_TYPE == USHORT +#define WCT "short unsigned int" +#define WCM "65535U" +#if WCHAR_SIZE != 2 +#error WCHAR_TYPE vs. WCHAR_SIZE mismatch +#endif +#elif WCHAR_TYPE == INT +#define WCT "int" +#define WCM "2147483647" +#if WCHAR_SIZE != 4 +#error WCHAR_TYPE vs. WCHAR_SIZE mismatch +#endif +#elif WCHAR_TYPE == UNSIGNED +#define WCT "unsigned int" +#define WCM "4294967295U" +#if WCHAR_SIZE != 4 +#error WCHAR_TYPE vs. WCHAR_SIZE mismatch +#endif +#else +#error WCHAR_TYPE not defined or invalid +#endif + +#ifdef GCC_COMPAT +#ifndef REGISTER_PREFIX +#define REGISTER_PREFIX "" +#endif +#ifndef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "" +#endif +#endif + +#ifndef PCC_WINT_TYPE +#define PCC_WINT_TYPE "unsigned int" +#endif + +#ifndef PCC_SIZE_TYPE +#define PCC_SIZE_TYPE "unsigned long" +#endif + +#ifndef PCC_PTRDIFF_TYPE +#define PCC_PTRDIFF_TYPE "long int" +#endif + + +struct strlist preprocessor_flags; +struct strlist depflags; +struct strlist incdirs; +struct strlist user_sysincdirs; +struct strlist includes; +struct strlist sysincdirs; +struct strlist dirafterdirs; +struct strlist crtdirs; +struct strlist libdirs; +struct strlist progdirs; +struct strlist early_linker_flags; +struct strlist middle_linker_flags; +struct strlist late_linker_flags; +struct strlist inputs; +struct strlist assembler_flags; +struct strlist temp_outputs; +struct strlist compiler_flags; + +int +main(int argc, char *argv[]) +{ + struct Wflags *Wf; + struct string *s; + char *t, *u, *argp; + char *msuffix; + int ninput, j; + + lav = argv; + lac = argc; + ninput = 0; + + strlist_init(&crtdirs); + strlist_init(&libdirs); + strlist_init(&progdirs); + strlist_init(&preprocessor_flags); + strlist_init(&incdirs); + strlist_init(&user_sysincdirs); + strlist_init(&includes); + strlist_init(&sysincdirs); + strlist_init(&dirafterdirs); + strlist_init(&depflags); + strlist_init(&early_linker_flags); + strlist_init(&middle_linker_flags); + strlist_init(&late_linker_flags); + strlist_init(&inputs); + strlist_init(&assembler_flags); + strlist_init(&temp_outputs); + strlist_init(&compiler_flags); + + if ((t = strrchr(argv[0], '/'))) + t++; + else + t = argv[0]; + + if (match(t, CXXPROGNAME)) { + cxxflag = 1; + } else if (match(t, CPPROGNAME)) { + Eflag = cppflag = 1; + } + +#ifdef PCC_EARLY_SETUP + PCC_EARLY_SETUP +#endif + +#ifdef _WIN32 + /* have to prefix path early. -B may override */ + incdir = win32pathsubst(incdir); + altincdir = win32pathsubst(altincdir); + libdir = win32pathsubst(libdir); +#ifdef PCCINCDIR + pccincdir = win32pathsubst(pccincdir); + pxxincdir = win32pathsubst(pxxincdir); +#endif +#ifdef PCCLIBDIR + pcclibdir = win32pathsubst(pcclibdir); +#endif + passp = win32pathsubst(passp); + pass0 = win32pathsubst(pass0); +#ifdef STARTFILES + for (i = 0; startfiles[i] != NULL; i++) + startfiles[i] = win32pathsubst(startfiles[i]); + for (i = 0; endfiles[i] != NULL; i++) + endfiles[i] = win32pathsubst(endfiles[i]); +#endif +#ifdef STARTFILES_T + for (i = 0; startfiles_T[i] != NULL; i++) + startfiles_T[i] = win32pathsubst(startfiles_T[i]); + for (i = 0; endfiles_T[i] != NULL; i++) + endfiles_T[i] = win32pathsubst(endfiles_T[i]); +#endif +#ifdef STARTFILES_S + for (i = 0; startfiles_S[i] != NULL; i++) + startfiles_S[i] = win32pathsubst(startfiles_S[i]); + for (i = 0; endfiles_S[i] != NULL; i++) + endfiles_S[i] = win32pathsubst(endfiles_S[i]); +#endif +#endif + + while (--lac) { + ++lav; + argp = *lav; + +#ifdef PCC_EARLY_ARG_CHECK + PCC_EARLY_ARG_CHECK +#endif + + if (*argp != '-' || match(argp, "-")) { + /* Check for duplicate .o files. */ + if (getsuf(argp) == 'o') { + j = 0; + STRLIST_FOREACH(s, &inputs) + if (match(argp, s->value)) + j++; + if (j) + continue; /* skip it */ + } + strlist_append(&inputs, argp); + ninput++; + continue; + } + + switch (argp[1]) { + default: + oerror(argp); + break; + + case '#': + if (match(argp, "-###")) { + printf("%s\n", VERSSTR); + vflag++; + noexec++; + } else + oerror(argp); + break; + + case '-': /* double -'s */ + if (match(argp, "--version")) { + printf("%s\n", VERSSTR); + return 0; + } else if (strncmp(argp, "--sysroot=", 10) == 0) { + sysroot = argp + 10; + } else if (strncmp(argp, "--sysroot", 9) == 0) { + sysroot = nxtopt(argp); + } else if (strcmp(argp, "--param") == 0) { + /* NOTHING YET */; + (void)nxtopt(0); /* ignore arg */ + } else + oerror(argp); + break; + + case 'B': /* other search paths for binaries */ + t = nxtopt("-B"); + strlist_append(&crtdirs, t); + strlist_append(&libdirs, t); + strlist_append(&progdirs, t); + break; + + case 'C': + if (match(argp, "-C") || match(argp, "-CC")) + strlist_append(&preprocessor_flags, argp); + else + oerror(argp); + break; + + case 'c': + cflag++; + break; + + case 'd': /* debug options */ + for (t = &argp[2]; *t; t++) { + if (*t == 'M') + strlist_append(&preprocessor_flags, "-dM"); + + /* ignore others */ + } + break; + + case 'E': + Eflag++; + break; + + case 'f': /* GCC compatibility flags */ + u = &argp[2]; + j = 0; + if (strncmp(u, "no-", 3) == 0) + j = 1, u += 3; + if (match(u, "PIC") || match(u, "pic")) { + kflag = j ? 0 : *u == 'P' ? F_PIC : F_pic; + } else if (match(u, "freestanding")) { + freestanding = j ? 0 : 1; + } else if (match(u, "signed-char")) { + xuchar = j ? 1 : 0; + } else if (match(u, "unsigned-char")) { + xuchar = j ? 0 : 1; + } else if (match(u, "stack-protector") || + match(u, "stack-protector-all")) { + sspflag = j ? 0 : 1; + } + /* silently ignore the rest */ + break; + + case 'g': /* create debug output */ + if (argp[2] == '0') + gflag = 0; + else + gflag++; + break; + + + case 'X': + Xflag++; + break; + + case 'D': + case 'U': + strlist_append(&preprocessor_flags, argp); + if (argp[2] != 0) + break; + strlist_append(&preprocessor_flags, nxtopt(argp)); + break; + + case 'I': /* Add include dirs */ + strlist_append(&incdirs, nxtopt("-I")); + break; + + case 'i': + if (match(argp, "-isystem")) { + strlist_append(&user_sysincdirs, nxtopt(0)); + } else if (match(argp, "-include")) { + strlist_append(&includes, nxtopt(0)); + } else if (match(argp, "-isysroot")) { + isysroot = nxtopt(0); + } else if (strcmp(argp, "-idirafter") == 0) { + strlist_append(&dirafterdirs, nxtopt(0)); + } else + oerror(argp); + break; + + case 'k': /* generate PIC code */ + kflag = argp[2] ? argp[2] - '0' : F_pic; + break; + + case 'l': + case 'L': + if (argp[2] == 0) + argp = cat(argp, nxtopt(0)); + strlist_append(&inputs, argp); + break; + + case 'm': /* target-dependent options */ + if (strncmp(argp, "-march=", 6) == 0) { + strlist_append(&compiler_flags, argp); + break; + } +#ifdef mach_amd64 + /* need to call i386 ccom for this */ + if (strcmp(argp, "-melf_i386") == 0) { + pass0 = LIBEXECDIR "/ccom_i386"; + amd64_i386 = 1; + break; + } +#endif +#if defined(mach_arm) || defined(mach_mips) + if (match(argp, "-mbig-endian")) { + bigendian = 1; + strlist_append(&compiler_flags, argp); + break; + } + if (match(argp, "-mlittle-endian")) { + bigendian = 0; + strlist_append(&compiler_flags, argp); + break; + } + if (match(argp, "-msoft-float")) { + softfloat = 1; + strlist_append(&compiler_flags, argp); + break; + } +#endif +#if defined(mach_mips) + if (match(argp, "-mhard-float")) { + softfloat = 0; + strlist_append(&compiler_flags, argp); + break; + } +#endif + strlist_append(&middle_linker_flags, argp); + if (argp[2] == 0) { + t = nxtopt(0); + strlist_append(&middle_linker_flags, t); + } + break; + + case 'n': /* handle -n flags */ + if (strcmp(argp, "-nostdinc") == 0) + nostdinc++; + else if (strcmp(argp, "-nostdlib") == 0) { + nostdlib++; + nostartfiles++; + } else if (strcmp(argp, "-nostartfiles") == 0) + nostartfiles = 1; + else if (strcmp(argp, "-nodefaultlibs") == 0) + nostdlib++; + else + oerror(argp); + break; + + case 'p': + if (strcmp(argp, "-pg") == 0 || + strcmp(argp, "-p") == 0) + pgflag++; + else if (strcmp(argp, "-pthread") == 0) + pthreads++; + else if (strcmp(argp, "-pipe") == 0) + /* NOTHING YET */; + else if (strcmp(argp, "-pedantic") == 0) + /* NOTHING YET */; + else if ((t = argnxt(argp, "-print-prog-name="))) { + fname = t; + printprogname = 1; + } else if ((t = argnxt(argp, "-print-file-name="))) { + fname = t; + printfilename = 1; + } else if (match(argp, "-print-libgcc-file-name")) { + fname = "libpcc.a"; + printfilename = 1; + } else + oerror(argp); + break; + + case 'R': + if (argp[2] == 0) + argp = cat(argp, nxtopt(0)); + strlist_append(&middle_linker_flags, argp); + break; + + case 'r': + rflag = 1; + break; + + case 'T': + strlist_append(&inputs, argp); + if (argp[2] == 0 || + strcmp(argp, "-Ttext") == 0 || + strcmp(argp, "-Tdata") == 0 || + strcmp(argp, "-Tbss") == 0) + strlist_append(&inputs, nxtopt(0)); + break; + + case 's': + if (match(argp, "-shared")) { + shared = 1; + } else if (match(argp, "-static")) { + Bstatic = 1; + } else if (match(argp, "-symbolic")) { + strlist_append(&middle_linker_flags, + "-Bsymbolic"); + } else if (strncmp(argp, "-std", 4) == 0) { + if (strcmp(&argp[5], "gnu99") == 0 || + strcmp(&argp[5], "gnu9x") == 0) + cstd = SGNU99; + if (strcmp(&argp[5], "c89") == 0) + cstd = SC89; + if (strcmp(&argp[5], "gnu89") == 0) + cstd = SGNU89; + if (strcmp(&argp[5], "c99") == 0) + cstd = SC99; + } else + oerror(argp); + break; + + case 'S': + Sflag++; + cflag++; + break; + + case 't': + tflag++; + cstd = STRAD; + break; + + case 'o': + if (outfile) + errorx(8, "too many -o"); + outfile = nxtopt("-o"); + break; + + case 'O': + if (argp[2] == '\0') + Oflag++; + else if (argp[3] == '\0' && + isdigit((unsigned char)argp[2])) + Oflag = argp[2] - '0'; + else if (argp[3] == '\0' && argp[2] == 's') + Oflag = 1; /* optimize for space only */ + else + oerror(argp); + break; + + case 'P': + strlist_append(&preprocessor_flags, argp); + break; + + case 'M': + needM = 1; + if (match(argp, "-M")) { + Mflag++; + strlist_append(&depflags, argp); + } else if (match(argp, "-MP")) { + strlist_append(&depflags, "-xMP"); + } else if (match(argp, "-MF")) { + MFfile = nxtopt("-MF"); + } else if (match(argp, "-MT") || match(argp, "-MQ")) { + t = cat("-xMT,", nxtopt("-MT")); + t[3] = argp[2]; + strlist_append(&depflags, t); + } else if (match(argp, "-MD")) { + MDflag++; + needM = 0; + strlist_append(&depflags, "-M"); + } else if (match(argp, "-MMD")) { + MMDflag++; + needM = 0; + strlist_append(&depflags, "-M"); + strlist_append(&depflags, "-xMMD"); + } else + oerror(argp); + break; + + case 'v': + printf("%s\n", VERSSTR); + vflag++; + break; + + case 'w': /* no warnings at all emitted */ + strlist_append(&compiler_flags, "-w"); + break; + + case 'W': /* Ignore (most of) W-flags */ + if ((t = argnxt(argp, "-Wl,"))) { + u = strtok(t, ","); + do { + strlist_append(&inputs, u); + } while ((u = strtok(NULL, ",")) != NULL); + } else if ((t = argnxt(argp, "-Wa,"))) { + u = strtok(t, ","); + do { + strlist_append(&assembler_flags, u); + } while ((u = strtok(NULL, ",")) != NULL); + } else if ((t = argnxt(argp, "-Wc,"))) { + u = strtok(t, ","); + do { + strlist_append(&compiler_flags, u); + } while ((u = strtok(NULL, ",")) != NULL); + } else if ((t = argnxt(argp, "-Wp,"))) { + u = strtok(t, ","); + do { + strlist_append(&preprocessor_flags, u); + } while ((u = strtok(NULL, ",")) != NULL); + } else if (strcmp(argp, "-Werror") == 0) { + strlist_append(&compiler_flags, "-Werror"); + strlist_append(&preprocessor_flags, "-E"); + } else if (strcmp(argp, "-Wall") == 0) { + for (Wf = Wflags; Wf->name; Wf++) + if (Wf->flags & INWALL) + strlist_append(&compiler_flags, + cat("-W", Wf->name)); + } else if (strcmp(argp, "-WW") == 0) { + for (Wf = Wflags; Wf->name; Wf++) + strlist_append(&compiler_flags, + cat("-W", Wf->name)); + } else { + /* pass through, if supported */ + t = &argp[2]; + if (strncmp(t, "no-", 3) == 0) + t += 3; + if (strncmp(t, "error=", 6) == 0) + t += 6; + for (Wf = Wflags; Wf->name; Wf++) { + if (strcmp(t, Wf->name) == 0) + strlist_append(&compiler_flags, + argp); + } + } + break; + + case 'x': + t = nxtopt("-x"); + if (match(t, "none")) + strlist_append(&inputs, ")"); + else if (match(t, "c")) + strlist_append(&inputs, ")c"); + else if (match(t, "assembler")) + strlist_append(&inputs, ")s"); + else if (match(t, "assembler-with-cpp")) + strlist_append(&inputs, ")S"); + else if (match(t, "c++")) + strlist_append(&inputs, ")c++"); + else { + strlist_append(&compiler_flags, "-x"); + strlist_append(&compiler_flags, t); + } + break; + + } + continue; + + } + + /* Sanity checking */ + if (cppflag) { + if (ninput == 0) { + strlist_append(&inputs, "-"); + ninput++; + } else if (ninput > 2 || (ninput == 2 && outfile)) { + errorx(8, "too many files"); + } else if (ninput == 2) { + outfile = STRLIST_NEXT(STRLIST_FIRST(&inputs))->value; + STRLIST_FIRST(&inputs)->next = NULL; + ninput--; + } + } + if (tflag && Eflag == 0) + errorx(8,"-t only allowed fi -E given"); + + /* Correct C standard */ + switch (cstd) { + case STRAD: break; + case SC89: c89defs = 1; break; + case SGNU89: xgnu89 = c89defs = 1; break; + case SC99: c89defs = c99defs = 1; break; + case SGNU99: c89defs = c99defs = xgnu99 = 1; break; + case SC11: c89defs = c11defs = 1; break; + } + + if (ninput == 0 && !(printprogname || printfilename)) + errorx(8, "no input files"); + if (outfile && (cflag || Sflag || Eflag) && ninput > 1) + errorx(8, "-o given with -c || -E || -S and more than one file"); +#if 0 + if (outfile && clist[0] && strcmp(outfile, clist[0]) == 0) + errorx(8, "output file will be clobbered"); +#endif + + if (needM && !Mflag && !MDflag && !MMDflag) + errorx(8, "to make dependencies needs -M"); + + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) /* interrupt */ + signal(SIGINT, idexit); + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) /* terminate */ + signal(SIGTERM, idexit); + + /* after arg parsing */ + strlist_append(&progdirs, LIBEXECDIR); + if (pcclibdir) + strlist_append(&crtdirs, pcclibdir); + for (j = 0; deflibdirs[j]; j++) { + if (sysroot) + deflibdirs[j] = cat(sysroot, deflibdirs[j]); + strlist_append(&crtdirs, deflibdirs[j]); + } + + setup_cpp_flags(); + setup_ccom_flags(); + setup_as_flags(); + + if (isysroot == NULL) + isysroot = sysroot; + expand_sysroot(); + + if (printprogname) { + printf("%s\n", find_file(fname, &progdirs, X_OK)); + return 0; + } else if (printfilename) { + printf("%s\n", find_file(fname, &crtdirs, R_OK)); + return 0; + } + + msuffix = NULL; + STRLIST_FOREACH(s, &inputs) { + char *suffix; + char *ifile, *ofile = NULL; + + ifile = s->value; + if (ifile[0] == ')') { /* -x source type given */ + msuffix = ifile[1] ? &ifile[1] : NULL; + continue; + } + if (ifile[0] == '-' && ifile[1] == 0) + suffix = msuffix ? msuffix : "c"; + else if (ifile[0] == '-') + suffix = "o"; /* source files cannot begin with - */ + else if (msuffix) + suffix = msuffix; + else + suffix = getsufp(ifile); + /* + * C preprocessor + */ + ascpp = match(suffix, "S"); + if (ascpp || cppflag || match(suffix, "c") || cxxsuf(suffix)) { + /* find out next output file */ + if (Mflag || MDflag || MMDflag) { + char *Mofile = NULL; + + if (MFfile) + Mofile = MFfile; + else if (outfile) + Mofile = setsuf(outfile, 'd'); + else if (MDflag || MMDflag) + Mofile = setsuf(ifile, 'd'); + if (preprocess_input(ifile, Mofile, 1)) + exandrm(Mofile); + } + if (Mflag) + continue; + if (Eflag) { + /* last pass */ + ofile = outfile; + } else { + /* to temp file */ + strlist_append(&temp_outputs, ofile = gettmp()); + } + if (preprocess_input(ifile, ofile, 0)) + exandrm(ofile); + if (Eflag) + continue; + ifile = ofile; + suffix = match(suffix, "S") ? "s" : "i"; + } + + /* + * C compiler + */ + if (match(suffix, "i")) { + /* find out next output file */ + if (Sflag) { + ofile = outfile; + if (outfile == NULL) + ofile = setsuf(s->value, 's'); + } else + strlist_append(&temp_outputs, ofile = gettmp()); + if (compile_input(ifile, ofile)) + exandrm(ofile); + if (Sflag) + continue; + ifile = ofile; + suffix = "s"; + } + + /* + * Assembler + */ + if (match(suffix, "s")) { + if (cflag) { + ofile = outfile; + if (ofile == NULL) + ofile = setsuf(s->value, 'o'); + } else { + strlist_append(&temp_outputs, ofile = gettmp()); + /* strlist_append linker */ + } + if (assemble_input(ifile, ofile)) + exandrm(ofile); + ifile = ofile; + } + + strlist_append(&middle_linker_flags, ifile); + } + + if (cflag || Eflag || Mflag) + dexit(0); + + /* + * Linker + */ + setup_ld_flags(); + if (run_linker()) + exandrm(0); + +#ifdef notdef + strlist_free(&crtdirs); + strlist_free(&libdirs); + strlist_free(&progdirs); + strlist_free(&incdirs); + strlist_free(&preprocessor_flags); + strlist_free(&user_sysincdirs); + strlist_free(&includes); + strlist_free(&sysincdirs); + strlist_free(&dirafterdirs); + strlist_free(&depflags); + strlist_free(&early_linker_flags); + strlist_free(&middle_linker_flags); + strlist_free(&late_linker_flags); + strlist_free(&inputs); + strlist_free(&assembler_flags); + strlist_free(&temp_outputs); + strlist_free(&compiler_flags); +#endif + dexit(0); + return 0; +} + +/* + * exit and cleanup after interrupt. + */ +void +idexit(int arg) +{ + dexit(100); +} + +/* + * exit and cleanup. + */ +void +dexit(int eval) +{ + struct string *s; + + if (!Xflag) { + STRLIST_FOREACH(s, &temp_outputs) + cunlink(s->value); + } + exit(eval); +} + +/* + * Called when something failed. + */ +void +exandrm(char *s) +{ + if (s && *s) + strlist_append(&temp_outputs, s); + dexit(1); +} + +/* + * complain and exit. + */ +void +errorx(int eval, char *s, ...) +{ + va_list ap; + + va_start(ap, s); + fputs("error: ", stderr); + vfprintf(stderr, s, ap); + putc('\n', stderr); + va_end(ap); + dexit(eval); +} + +static char * +find_file(const char *file, struct strlist *path, int mode) +{ + struct string *s; + char *f; + size_t lf, lp; + int need_sep; + + lf = strlen(file); + STRLIST_FOREACH(s, path) { + lp = strlen(s->value); + need_sep = (lp && s->value[lp - 1] != '/') ? 1 : 0; + f = xmalloc(lp + lf + need_sep + 1); + memcpy(f, s->value, lp); + if (need_sep) + f[lp] = '/'; + memcpy(f + lp + need_sep, file, lf + 1); + if (access(f, mode) == 0) + return f; + free(f); + } + return xstrdup(file); +} + +#ifdef TWOPASS +static int +compile_input(char *input, char *output) +{ + struct strlist args; + char *tfile; + int retval; + + strlist_append(&temp_outputs, tfile = gettmp()); + + strlist_init(&args); + strlist_append_list(&args, &compiler_flags); + strlist_append(&args, input); + strlist_append(&args, tfile); + strlist_prepend(&args, + find_file(cxxflag ? "cxx0" : "cc0", &progdirs, X_OK)); + retval = strlist_exec(&args); + strlist_free(&args); + if (retval) + return retval; + + strlist_init(&args); + strlist_append_list(&args, &compiler_flags); + strlist_append(&args, tfile); + strlist_append(&args, output); + strlist_prepend(&args, + find_file(cxxflag ? "cxx1" : "cc1", &progdirs, X_OK)); + retval = strlist_exec(&args); + strlist_free(&args); + return retval; +} +#else +static int +compile_input(char *input, char *output) +{ + struct strlist args; + int retval; + + strlist_init(&args); + strlist_append_list(&args, &compiler_flags); + strlist_append(&args, input); + strlist_append(&args, output); + strlist_prepend(&args, + find_file(cxxflag ? passxx0 : pass0, &progdirs, X_OK)); + retval = strlist_exec(&args); + strlist_free(&args); + return retval; +} +#endif + +static int +assemble_input(char *input, char *output) +{ + struct strlist args; + int retval; + + strlist_init(&args); +#ifdef PCC_EARLY_AS_ARGS + PCC_EARLY_AS_ARGS +#endif + strlist_append_list(&args, &assembler_flags); + strlist_append(&args, input); + strlist_append(&args, "-o"); + strlist_append(&args, output); + strlist_prepend(&args, + find_file(as, &progdirs, X_OK)); +#ifdef PCC_LATE_AS_ARGS + PCC_LATE_AS_ARGS +#endif + retval = strlist_exec(&args); + strlist_free(&args); + return retval; +} + +static int +preprocess_input(char *input, char *output, int dodep) +{ + struct strlist args; + struct string *s; + int retval; + + strlist_init(&args); + strlist_append_list(&args, &preprocessor_flags); + if (ascpp) { + strlist_append(&args, "-A"); + strlist_append(&args, "-D__ASSEMBLER__"); + } + STRLIST_FOREACH(s, &includes) { + strlist_append(&args, "-i"); + strlist_append(&args, s->value); + } + STRLIST_FOREACH(s, &incdirs) { + strlist_append(&args, "-I"); + strlist_append(&args, s->value); + } + STRLIST_FOREACH(s, &user_sysincdirs) { + strlist_append(&args, "-S"); + strlist_append(&args, s->value); + } + if (!nostdinc) { + STRLIST_FOREACH(s, &sysincdirs) { + strlist_append(&args, "-S"); + strlist_append(&args, s->value); + } + } + STRLIST_FOREACH(s, &dirafterdirs) { + strlist_append(&args, "-S"); + strlist_append(&args, s->value); + } + if (dodep) + strlist_append_list(&args, &depflags); + strlist_append(&args, input); + if (output) + strlist_append(&args, output); + + strlist_prepend(&args, find_file(passp, &progdirs, X_OK)); + retval = strlist_exec(&args); + strlist_free(&args); + return retval; +} + +static int +run_linker(void) +{ + struct strlist linker_flags; + int retval; + + if (outfile) { + strlist_prepend(&early_linker_flags, outfile); + strlist_prepend(&early_linker_flags, "-o"); + } + strlist_init(&linker_flags); + strlist_append_list(&linker_flags, &early_linker_flags); + strlist_append_list(&linker_flags, &middle_linker_flags); + strlist_append_list(&linker_flags, &late_linker_flags); + strlist_prepend(&linker_flags, find_file(ld, &progdirs, X_OK)); + + retval = strlist_exec(&linker_flags); + + strlist_free(&linker_flags); + return retval; +} + +static char *cxxt[] = { "cc", "cp", "cxx", "cpp", "CPP", "c++", "C" }; +int +cxxsuf(char *s) +{ + unsigned i; + for (i = 0; i < sizeof(cxxt)/sizeof(cxxt[0]); i++) + if (strcmp(s, cxxt[i]) == 0) + return 1; + return 0; +} + +char * +getsufp(char *s) +{ + register char *p; + + if ((p = strrchr(s, '.')) && p[1] != '\0') + return &p[1]; + return ""; +} + +int +getsuf(char *s) +{ + register char *p; + + if ((p = strrchr(s, '.')) && p[1] != '\0' && p[2] == '\0') + return p[1]; + return(0); +} + +/* + * Get basename of string s, copy it and change its suffix to ch. + */ +char * +setsuf(char *s, char ch) +{ + char *e, *p, *rp; + + e = NULL; + for (p = s; *p; p++) { + if (*p == '/') + s = p + 1; + if (*p == '.') + e = p; + } + if (s > e) + e = p; + + rp = p = xmalloc(e - s + 3); + while (s < e) + *p++ = *s++; + + *p++ = '.'; + *p++ = ch; + *p = '\0'; + return rp; +} + +#ifdef _WIN32 + +static int +strlist_exec(struct strlist *l) +{ + char *cmd; + STARTUPINFO si; + PROCESS_INFORMATION pi; + DWORD exitCode; + BOOL ok; + + cmd = win32commandline(l); + if (vflag) + printf("%s\n", cmd); + if (noexec) + return 0; + + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + + ok = CreateProcess(NULL, // the executable program + cmd, // the command line arguments + NULL, // ignored + NULL, // ignored + TRUE, // inherit handles + HIGH_PRIORITY_CLASS, + NULL, // ignored + NULL, // ignored + &si, + &pi); + + if (!ok) + errorx(100, "Can't find %s\n", STRLIST_FIRST(l)->value); + + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &exitCode); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + return (exitCode != 0); +} + +#else + +static int +strlist_exec(struct strlist *l) +{ + sig_atomic_t exit_now = 0; + sig_atomic_t child; + char **argv; + size_t argc; + int result; + + strlist_make_array(l, &argv, &argc); + if (vflag) { + printf("Calling "); + strlist_print(l, stdout, noexec); + printf("\n"); + } + if (noexec) + return 0; + + switch ((child = fork())) { + case 0: + execvp(argv[0], argv); + result = write(STDERR_FILENO, "Exec of ", 8); + result = write(STDERR_FILENO, argv[0], strlen(argv[0])); + result = write(STDERR_FILENO, " failed\n", 8); + (void)result; + _exit(127); + case -1: + errorx(1, "fork failed"); + default: + while (waitpid(child, &result, 0) == -1 && errno == EINTR) + /* nothing */(void)0; + result = WEXITSTATUS(result); + if (result) + errorx(1, "%s terminated with status %d", argv[0], result); + while (argc-- > 0) + free(argv[argc]); + free(argv); + break; + } + return exit_now; +} + +#endif + +/* + * Catenate two (optional) strings together + */ +char * +cat(const char *a, const char *b) +{ + size_t len; + char *rv; + + len = (a ? strlen(a) : 0) + (b ? strlen(b) : 0) + 1; + rv = xmalloc(len); + snprintf(rv, len, "%s%s", (a ? a : ""), (b ? b : "")); + return rv; +} + +int +cunlink(char *f) +{ + if (f==0 || Xflag) + return(0); + return (unlink(f)); +} + +#ifdef _WIN32 +char * +gettmp(void) +{ + DWORD pathSize; + char pathBuffer[MAX_PATH + 1]; + char tempFilename[MAX_PATH]; + UINT uniqueNum; + + pathSize = GetTempPath(sizeof(pathBuffer), pathBuffer); + if (pathSize == 0 || pathSize > sizeof(pathBuffer)) + pathBuffer[0] = '\0'; + uniqueNum = GetTempFileName(pathBuffer, "ctm", 0, tempFilename); + if (uniqueNum == 0) + errorx(8, "GetTempFileName failed: path \"%s\"", pathBuffer); + + return xstrdup(tempFilename); +} + +#else + +char * +gettmp(void) +{ + char *sfn = xstrdup("/tmp/ctm.XXXXXX"); + int fd = -1; + + if ((fd = mkstemp(sfn)) == -1) + errorx(8, "%s: %s\n", sfn, strerror(errno)); + close(fd); + return sfn; +} +#endif + +static void +expand_sysroot(void) +{ + struct string *s; + struct strlist *lists[] = { &crtdirs, &sysincdirs, &incdirs, + &user_sysincdirs, &libdirs, &progdirs, &dirafterdirs, NULL }; + const char *sysroots[] = { sysroot, isysroot, isysroot, isysroot, + sysroot, sysroot, isysroot, NULL }; + size_t i, sysroot_len, value_len; + char *path; + + assert(sizeof(lists) / sizeof(lists[0]) == + sizeof(sysroots) / sizeof(sysroots[0])); + + for (i = 0; lists[i] != NULL; ++i) { + STRLIST_FOREACH(s, lists[i]) { + if (s->value[0] != '=') + continue; + sysroot_len = strlen(sysroots[i]); + /* Skipped '=' compensates additional space for '\0' */ + value_len = strlen(s->value); + path = xmalloc(sysroot_len + value_len); + memcpy(path, sysroots[i], sysroot_len); + memcpy(path + sysroot_len, s->value + 1, value_len); + free(s->value); + s->value = path; + } + } +} + +void +oerror(char *s) +{ + errorx(8, "unknown option '%s'", s); +} + +/* + * See if m matches the beginning of string str, if it does return the + * remaining of str, otherwise NULL. + */ +char * +argnxt(char *str, char *m) +{ + if (strncmp(str, m, strlen(m))) + return NULL; /* No match */ + return str + strlen(m); +} + +/* + * Return next argument to option, or complain. + */ +char * +nxtopt(char *o) +{ + int l; + + if (o != NULL) { + l = strlen(o); + if (lav[0][l] != 0) + return &lav[0][l]; + } + if (lac == 1) + errorx(8, "missing argument to '%s'", o); + lav++; + lac--; + return lav[0]; +} + +struct flgcheck { + int *flag; + int set; + char *def; +} cppflgcheck[] = { + { &vflag, 1, "-v" }, + { &c99defs, 1, "-D__STDC_VERSION__=199901L" }, + { &c11defs, 1, "-D__STDC_VERSION__=201112L" }, + { &c89defs, 1, "-D__STDC__=1" }, + { &freestanding, 1, "-D__STDC_HOSTED__=0" }, + { &freestanding, 0, "-D__STDC_HOSTED__=1" }, + { &cxxflag, 1, "-D__cplusplus" }, + { &xuchar, 1, "-D__CHAR_UNSIGNED__" }, + { &sspflag, 1, "-D__SSP__" }, + { &pthreads, 1, "-D_PTHREADS" }, + { &Oflag, 1, "-D__OPTIMIZE__" }, + { &tflag, 1, "-t" }, + { &kflag, 1, "-D__PIC__" }, + { 0 }, +}; + +static void +cksetflags(struct flgcheck *fs, struct strlist *sl, int which) +{ + void (*fn)(struct strlist *, const char *); + + fn = which == 'p' ? strlist_prepend : strlist_append; + for (; fs->flag; fs++) { + if (fs->set && *fs->flag) + fn(sl, fs->def); + if (!fs->set && !*fs->flag) + fn(sl, fs->def); + } +} + +#ifndef TARGET_LE +#define TARGET_LE 1 +#define TARGET_BE 2 +#define TARGET_PDP 3 +#define TARGET_ANY 4 +#endif + +static char *defflags[] = { + "-D__PCC__=" MKS(PCC_MAJOR), + "-D__PCC_MINOR__=" MKS(PCC_MINOR), + "-D__PCC_MINORMINOR__=" MKS(PCC_MINORMINOR), + "-D__VERSION__=" MKS(VERSSTR), + "-D__SCHAR_MAX__=" MKS(MAX_CHAR), + "-D__SHRT_MAX__=" MKS(MAX_SHORT), + "-D__INT_MAX__=" MKS(MAX_INT), + "-D__LONG_MAX__=" MKS(MAX_LONG), + "-D__LONG_LONG_MAX__=" MKS(MAX_LONGLONG), + + "-D__STDC_ISO_10646__=200009L", + "-D__WCHAR_TYPE__=" WCT, + "-D__SIZEOF_WCHAR_T__=" MKS(WCHAR_SIZE), + "-D__WCHAR_MAX__=" WCM, + "-D__WINT_TYPE__=" PCC_WINT_TYPE, + "-D__SIZE_TYPE__=" PCC_SIZE_TYPE, + "-D__PTRDIFF_TYPE__=" PCC_PTRDIFF_TYPE, + "-D__SIZEOF_WINT_T__=4", + "-D__ORDER_LITTLE_ENDIAN__=1234", + "-D__ORDER_BIG_ENDIAN__=4321", + "-D__ORDER_PDP_ENDIAN__=3412", +#ifndef NO_C11 + "-D__STDC_UTF_16__=1", + "-D__STDC_UTF_32__=1", + "-D__STDC_NO_ATOMICS__=1", + "-D__STDC_NO_THREADS__=1", +#endif + +/* + * These should probably be changeable during runtime... + */ +#if TARGET_ENDIAN == TARGET_BE + "-D__FLOAT_WORD_ORDER__=__ORDER_BIG_ENDIAN__", + "-D__BYTE_ORDER__=__ORDER_BIG_ENDIAN__", +#elif TARGET_ENDIAN == TARGET_PDP + "-D__FLOAT_WORD_ORDER__=__ORDER_PDP_ENDIAN__", + "-D__BYTE_ORDER__=__ORDER_PDP_ENDIAN__", +#elif TARGET_ENDIAN == TARGET_LE + "-D__FLOAT_WORD_ORDER__=__ORDER_LITTLE_ENDIAN__", + "-D__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__", +#else +#error Unknown endian... +#endif +}; + +static char *gcppflags[] = { +#ifndef os_win32 +#ifdef GCC_COMPAT + "-D__GNUC__=4", + "-D__GNUC_MINOR__=3", + "-D__GNUC_PATCHLEVEL__=1", + "-D__REGISTER_PREFIX__=" REGISTER_PREFIX, + "-D__USER_LABEL_PREFIX__=" USER_LABEL_PREFIX, +#if SZLONG == 64 + "-D__SIZEOF_LONG__=8", +#elif SZLONG == 32 + "-D__SIZEOF_LONG__=4", +#endif +#if SZPOINT(CHAR) == 64 + "-D__SIZEOF_POINTER__=8", +#elif SZPOINT(CHAR) == 32 + "-D__SIZEOF_POINTER__=4", +#endif +#endif +#endif + NULL +}; + +/* These should _not_ be defined here */ +static char *fpflags[] = { +#ifdef TARGET_FLT_EVAL_METHOD + "-D__FLT_EVAL_METHOD__=" MKS(TARGET_FLT_EVAL_METHOD), +#endif +#if defined(os_darwin) || defined(os_netbsd) || defined(os_minix) + "-D__FLT_RADIX__=2", +#if defined(mach_vax) + "-D__FLT_DIG__=6", + "-D__FLT_EPSILON__=1.19209290e-07F", + "-D__FLT_MANT_DIG__=24", + "-D__FLT_MAX_10_EXP__=38", + "-D__FLT_MAX_EXP__=127", + "-D__FLT_MAX__=1.70141173e+38F", + "-D__FLT_MIN_10_EXP__=(-38)", + "-D__FLT_MIN_EXP__=(-127)", + "-D__FLT_MIN__=2.93873588e-39F", + "-D__DBL_DIG__=16", + "-D__DBL_EPSILON__=2.77555756156289135e-17", + "-D__DBL_MANT_DIG__=56", + "-D__DBL_MAX_10_EXP__=38", + "-D__DBL_MAX_EXP__=127", + "-D__DBL_MAX__=1.701411834604692294e+38", + "-D__DBL_MIN_10_EXP__=(-38)", + "-D__DBL_MIN_EXP__=(-127)", + "-D__DBL_MIN__=2.938735877055718770e-39", +#else + "-D__FLT_DIG__=6", + "-D__FLT_EPSILON__=1.19209290e-07F", + "-D__FLT_MANT_DIG__=24", + "-D__FLT_MAX_10_EXP__=38", + "-D__FLT_MAX_EXP__=128", + "-D__FLT_MAX__=3.40282347e+38F", + "-D__FLT_MIN_10_EXP__=(-37)", + "-D__FLT_MIN_EXP__=(-125)", + "-D__FLT_MIN__=1.17549435e-38F", + "-D__DBL_DIG__=15", + "-D__DBL_EPSILON__=2.2204460492503131e-16", + "-D__DBL_MANT_DIG__=53", + "-D__DBL_MAX_10_EXP__=308", + "-D__DBL_MAX_EXP__=1024", + "-D__DBL_MAX__=1.7976931348623157e+308", + "-D__DBL_MIN_10_EXP__=(-307)", + "-D__DBL_MIN_EXP__=(-1021)", + "-D__DBL_MIN__=2.2250738585072014e-308", +#endif +#if defined(mach_i386) || defined(mach_amd64) + "-D__LDBL_DIG__=18", + "-D__LDBL_EPSILON__=1.08420217248550443401e-19L", + "-D__LDBL_MANT_DIG__=64", + "-D__LDBL_MAX_10_EXP__=4932", + "-D__LDBL_MAX_EXP__=16384", + "-D__LDBL_MAX__=1.18973149535723176502e+4932L", + "-D__LDBL_MIN_10_EXP__=(-4931)", + "-D__LDBL_MIN_EXP__=(-16381)", + "-D__LDBL_MIN__=3.36210314311209350626e-4932L", +#elif defined(mach_vax) + "-D__LDBL_DIG__=16", + "-D__LDBL_EPSILON__=2.77555756156289135e-17", + "-D__LDBL_MANT_DIG__=56", + "-D__LDBL_MAX_10_EXP__=38", + "-D__LDBL_MAX_EXP__=127", + "-D__LDBL_MAX__=1.701411834604692294e+38", + "-D__LDBL_MIN_10_EXP__=(-38)", + "-D__LDBL_MIN_EXP__=(-127)", + "-D__LDBL_MIN__=2.938735877055718770e-39", +#else + "-D__LDBL_DIG__=15", + "-D__LDBL_EPSILON__=2.2204460492503131e-16", + "-D__LDBL_MANT_DIG__=53", + "-D__LDBL_MAX_10_EXP__=308", + "-D__LDBL_MAX_EXP__=1024", + "-D__LDBL_MAX__=1.7976931348623157e+308", + "-D__LDBL_MIN_10_EXP__=(-307)", + "-D__LDBL_MIN_EXP__=(-1021)", + "-D__LDBL_MIN__=2.2250738585072014e-308", +#endif +#endif + NULL +}; + +/* + * Configure the standard cpp flags. + */ +void +setup_cpp_flags(void) +{ + int i; + + /* a bunch of misc defines */ + for (i = 0; i < (int)sizeof(defflags)/(int)sizeof(char *); i++) + strlist_prepend(&preprocessor_flags, defflags[i]); + + for (i = 0; gcppflags[i]; i++) + strlist_prepend(&preprocessor_flags, gcppflags[i]); + strlist_prepend(&preprocessor_flags, xgnu89 ? + "-D__GNUC_GNU_INLINE__" : "-D__GNUC_STDC_INLINE__"); + + cksetflags(cppflgcheck, &preprocessor_flags, 'p'); + + /* Create time and date defines */ + if (tflag == 0) { + char buf[100]; /* larger than needed */ + time_t t = time(NULL); + char *n = ctime(&t); + + n[19] = 0; + snprintf(buf, sizeof buf, "-D__TIME__=\"%s\"", n+11); + strlist_prepend(&preprocessor_flags, xstrdup(buf)); + + n[24] = n[11] = 0; + snprintf(buf, sizeof buf, "-D__DATE__=\"%s%s\"", n+4, n+20); + strlist_prepend(&preprocessor_flags, xstrdup(buf)); + } + + for (i = 0; fpflags[i]; i++) + strlist_prepend(&preprocessor_flags, fpflags[i]); + + for (i = 0; cppadd[i]; i++) + strlist_prepend(&preprocessor_flags, cppadd[i]); + for (i = 0; cppmdadd[i]; i++) + strlist_prepend(&preprocessor_flags, cppmdadd[i]); + + /* Include dirs */ + strlist_append(&sysincdirs, "=" INCLUDEDIR "pcc/"); +#ifdef STDINC_MA + strlist_append(&sysincdirs, "=" STDINC_MA); +#endif + strlist_append(&sysincdirs, "=" STDINC); +#ifdef PCCINCDIR + if (cxxflag) + strlist_append(&sysincdirs, "=" PCCINCDIR "/c++"); + strlist_append(&sysincdirs, "=" PCCINCDIR); +#endif +} + +struct flgcheck ccomflgcheck[] = { + { &Oflag, 1, "-xtemps" }, + { &Oflag, 1, "-xdeljumps" }, + { &Oflag, 1, "-xinline" }, + { &Oflag, 1, "-xdce" }, +#ifdef notyet + { &Oflag, 1, "-xssa" }, +#endif + { &freestanding, 1, "-ffreestanding" }, + { &pgflag, 1, "-p" }, + { &gflag, 1, "-g" }, + { &xgnu89, 1, "-xgnu89" }, + { &xgnu99, 1, "-xgnu99" }, + { &xuchar, 1, "-xuchar" }, +#if !defined(os_sunos) && !defined(mach_i386) + { &vflag, 1, "-v" }, +#endif +#ifdef os_darwin + { &Bstatic, 0, "-k" }, +#elif defined(os_sunos) && defined(mach_i386) + { &kflag, 1, "-K" }, + { &kflag, 1, "pic" }, +#else + { &kflag, 1, "-k" }, +#endif + { &sspflag, 1, "-fstack-protector" }, + { 0 } +}; + +void +setup_ccom_flags(void) +{ + + cksetflags(ccomflgcheck, &compiler_flags, 'a'); +} + +static int one = 1; + +struct flgcheck asflgcheck[] = { +#if defined(USE_YASM) + { &one, 1, "-p" }, + { &one, 1, "gnu" }, + { &one, 1, "-f" }, +#if defined(os_win32) + { &one, 1, "win32" }, +#elif defined(os_darwin) + { &one, 1, "macho" }, +#else + { &one, 1, "elf" }, +#endif +#endif +#if defined(os_sunos) && defined(mach_sparc64) + { &one, 1, "-m64" }, +#endif +#if defined(os_darwin) + { &Bstatic, 1, "-static" }, +#endif +#if !defined(USE_YASM) + { &vflag, 1, "-v" }, +#endif + { &kflag, 1, "-k" }, +#ifdef os_darwin + { &one, 1, "-arch" }, +#if mach_amd64 + { &amd64_i386, 1, "i386" }, + { &amd64_i386, 0, "x86_64" }, +#else + { &one, 1, "i386" }, +#endif +#else +#ifdef mach_amd64 + { &amd64_i386, 1, "--32" }, +#endif +#endif + { 0 } +}; +void +setup_as_flags(void) +{ + one = one; +#ifdef PCC_SETUP_AS_ARGS + PCC_SETUP_AS_ARGS +#endif + cksetflags(asflgcheck, &assembler_flags, 'a'); +} + +struct flgcheck ldflgcheck[] = { +#ifndef MSLINKER + { &vflag, 1, "-v" }, +#endif +#ifdef os_darwin + { &shared, 1, "-dylib" }, +#elif defined(os_win32) + { &shared, 1, "-Bdynamic" }, +#else + { &shared, 1, "-shared" }, +#endif +#if !defined(os_sunos) && !defined(os_win32) +#ifndef os_darwin + { &shared, 0, "-d" }, +#endif +#endif +#ifdef os_darwin + { &Bstatic, 1, "-static" }, +#else + { &Bstatic, 1, "-Bstatic" }, +#endif +#if !defined(os_darwin) && !defined(os_sunos) + { &gflag, 1, "-g" }, +#endif + { &pthreads, 1, "-lpthread" }, + { 0 }, +}; + +static void +strap(struct strlist *sh, struct strlist *cd, char *n, int where) +{ + void (*fn)(struct strlist *, const char *); + char *fil; + + if (n == 0) + return; /* no crtfile */ + + fn = where == 'p' ? strlist_prepend : strlist_append; + fil = find_file(n, cd, R_OK); + (*fn)(sh, fil); +} + +void +setup_ld_flags(void) +{ + char *b, *e; + int i; + +#ifdef PCC_SETUP_LD_ARGS + PCC_SETUP_LD_ARGS +#endif + + cksetflags(ldflgcheck, &early_linker_flags, 'a'); + if (Bstatic == 0 && shared == 0 && rflag == 0) { + if (dynlinklib) { + strlist_append(&early_linker_flags, dynlinkarg); + strlist_append(&early_linker_flags, dynlinklib); + } + strlist_append(&early_linker_flags, "-e"); + strlist_append(&early_linker_flags, STARTLABEL); + } + if (shared == 0 && rflag) + strlist_append(&early_linker_flags, "-r"); +#ifdef STARTLABEL_S + if (shared == 1) { + strlist_append(&early_linker_flags, "-e"); + strlist_append(&early_linker_flags, STARTLABEL_S); + } +#endif + if (sysroot && *sysroot) + strlist_append(&early_linker_flags, cat("--sysroot=", sysroot)); + if (!nostdlib) { + /* library search paths */ + if (pcclibdir) + strlist_append(&late_linker_flags, + cat("-L", pcclibdir)); + for (i = 0; deflibdirs[i]; i++) + strlist_append(&late_linker_flags, + cat("-L", deflibdirs[i])); + /* standard libraries */ + if (pgflag) { + for (i = 0; defproflibs[i]; i++) + strlist_append(&late_linker_flags, + defproflibs[i]); + } else if (cxxflag) { + for (i = 0; defcxxlibs[i]; i++) + strlist_append(&late_linker_flags, + defcxxlibs[i]); + } else { + for (i = 0; deflibs[i]; i++) + strlist_append(&late_linker_flags, deflibs[i]); + } + } + if (!nostartfiles) { + if (Bstatic) { + b = CRTBEGIN_T; + e = CRTEND_T; + } else if (shared /* || pieflag */) { + b = CRTBEGIN_S; + e = CRTEND_S; + } else { + b = CRTBEGIN; + e = CRTEND; + } + strap(&middle_linker_flags, &crtdirs, b, 'p'); + strap(&late_linker_flags, &crtdirs, e, 'a'); + strap(&middle_linker_flags, &crtdirs, CRTI, 'p'); + strap(&late_linker_flags, &crtdirs, CRTN, 'a'); +#ifdef os_win32 + /* + * On Win32 Cygwin/MinGW runtimes, the profiling code gcrtN.o + * comes in addition to crtN.o or dllcrtN.o + */ + if (pgflag) + strap(&middle_linker_flags, &crtdirs, GCRT0, 'p'); + if (shared == 0) + b = CRT0; + else + b = CRT0_S; /* dllcrtN.o */ + strap(&middle_linker_flags, &crtdirs, b, 'p'); +#else + if (shared == 0) { + if (pgflag) + b = GCRT0; +#ifdef notyet + else if (pieflag) + b = SCRT0; +#endif + else + b = CRT0; + strap(&middle_linker_flags, &crtdirs, b, 'p'); + } +#endif + } +} + +#ifdef _WIN32 +char * +win32pathsubst(char *s) +{ + char env[1024]; + DWORD len; + + len = ExpandEnvironmentStrings(s, env, sizeof(env)); + if (len == 0 || len > sizeof(env)) + errorx(8, "ExpandEnvironmentStrings failed, len %lu", len); + + len--; /* skip nil */ + while (len-- > 0 && (env[len] == '/' || env[len] == '\\')) + env[len] = '\0'; + + return xstrdup(env); +} + +char * +win32commandline(struct strlist *l) +{ + const struct string *s; + char *cmd; + char *p; + int len; + int j, k; + + len = 0; + STRLIST_FOREACH(s, l) { + len++; + for (j = 0; s->value[j] != '\0'; j++) { + if (s->value[j] == '\"') { + for (k = j-1; k >= 0 && s->value[k] == '\\'; k--) + len++; + len++; + } + len++; + } + for (k = j-1; k >= 0 && s->value[k] == '\\'; k--) + len++; + len++; + len++; + } + + p = cmd = xmalloc(len); + + STRLIST_FOREACH(s, l) { + *p++ = '\"'; + for (j = 0; s->value[j] != '\0'; j++) { + if (s->value[j] == '\"') { + for (k = j-1; k >= 0 && s->value[k] == '\\'; k--) + *p++ = '\\'; + *p++ = '\\'; + } + *p++ = s->value[j]; + } + for (k = j-1; k >= 0 && s->value[k] == '\\'; k--) + *p++ = '\\'; + *p++ = '\"'; + *p++ = ' '; + } + p[-1] = '\0'; + + return cmd; +} +#endif diff --git a/lang/pcc/pcc/cc/ccom/Makefile.in b/lang/pcc/pcc/cc/ccom/Makefile.in new file mode 100644 index 000000000..eb1214a86 --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/Makefile.in @@ -0,0 +1,219 @@ +# $Id: Makefile.in,v 1.49 2016/03/08 18:42:13 ragge Exp $ +# +# Makefile.in for ccom +# +VPATH=@srcdir@ +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +builddir=@builddir@ +top_builddir=@top_builddir@ +CC = @CC@ +EXEEXT = @EXEEXT@ +BINPREFIX = @BINPREFIX@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ @ADD_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -D_ISOC99_SOURCE \ + -Dos_$(TARGOS) -Dmach_$(TARGMACH) \ + -I$(srcdir) -I$(builddir) -I$(top_builddir) -I$(MIPDIR) -I$(MDIR) \ + -I$(top_srcdir)/os/$(TARGOS) -I$(COMMONDIR) +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LFLAGS = +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +TARGOS = @targos@ +TARGOSVER = @targosver@ +TARGMACH = @targmach@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +mandir = @mandir@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +CCOM=$(BINPREFIX)ccom$(EXEEXT) +CC0=$(BINPREFIX)cc0$(EXEEXT) +CC1=$(BINPREFIX)cc1$(EXEEXT) +CF0=@CF0@ +CF1=@CF1@ + +MDIR=$(top_srcdir)/arch/$(TARGMACH) +MIPDIR=$(top_srcdir)/mip +COMMONDIR=$(top_srcdir)/common + +DEST=@CCNAMES@ +MANPAGE=$(BINPREFIX)ccom +MKEXT=mkext$(EXEEXT) + +all: $(DEST) + +OBJS= builtins.o cgram.o code.o common.o compat.o dwarf.o external.o \ + gcc_compat.o init.o inline.o local.o local2.o main.o \ + match.o optim.o optim2.o order.o pftn.o reader.o \ + regs.o scan.o stabs.o symtabs.o table.o trees.o unicode.o + +OBJS0= builtins.o cgram.o code.o common.o compat.o dwarf.o external.o \ + gcc_compat.o init.o inline.o local.o main.o \ + optim.o pftn.o \ + scan.o stabs.o symtabs.o trees.o unicode.o + +OBJS1= common2.o compat.o external.o \ + local2.o main2.o \ + match.o optim2.o order.o reader.o \ + regs.o table.o + + +LOBJS= mkext.lo common.lo table.lo + +HDRS= $(srcdir)/pass1.h $(MIPDIR)/pass2.h $(MIPDIR)/manifest.h \ + $(MDIR)/macdefs.h $(MIPDIR)/node.h $(COMMONDIR)/compat.h \ + $(COMMONDIR)/unicode.h + +# +# round 1: generate external.[ch], cgram.[ch] & scan.c +# + +$(LOBJS): $(HDRS) + +mkext.lo: $(MIPDIR)/mkext.c + $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/mkext.c + +common.lo: $(MIPDIR)/common.c + $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/common.c + +table.lo: $(MDIR)/table.c + $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MDIR)/table.c + +$(MKEXT): $(LOBJS) + $(CC_FOR_BUILD) $(LDFLAGS) $(LOBJS) -o $@ $(LIBS) + +external.c: $(MKEXT) + $(builddir)/$(MKEXT) + +cgram.c: $(srcdir)/cgram.y + $(YACC) $(YFLAGS) -d $(srcdir)/cgram.y + mv -f y.tab.c cgram.c + mv -f y.tab.h cgram.h + +scan.c: $(srcdir)/scan.l + $(LEX) $(LFLAGS) $(srcdir)/scan.l + mv -f $(LEX_OUTPUT_ROOT).c scan.c + +# +# round 2: compile $(OBJS) +# + +$(OBJS): $(HDRS) external.c cgram.c + +builtins.o: $(srcdir)/builtins.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/builtins.c + +cgram.o: cgram.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ cgram.c + +code.o: $(MDIR)/code.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/code.c + +common.o: $(MIPDIR)/common.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c + +common2.o: $(MIPDIR)/common.c + $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c + +compat.o: $(COMMONDIR)/compat.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c + +dwarf.o: $(srcdir)/dwarf.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/dwarf.c + +external.o: external.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ external.c + +gcc_compat.o: $(srcdir)/gcc_compat.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/gcc_compat.c + +init.o: $(srcdir)/init.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/init.c + +inline.o: $(srcdir)/inline.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/inline.c + +local.o: $(MDIR)/local.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local.c + +local2.o: $(MDIR)/local2.c + $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local2.c + +main.o: $(srcdir)/main.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c + +main2.o: $(srcdir)/main.c + $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c + +match.o: $(MIPDIR)/match.c + $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/match.c + +optim.o: $(srcdir)/optim.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/optim.c + +optim2.o: $(MIPDIR)/optim2.c + $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/optim2.c + +order.o: $(MDIR)/order.c + $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/order.c + +pftn.o: $(srcdir)/pftn.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/pftn.c + +reader.o: $(MIPDIR)/reader.c + $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/reader.c + +regs.o: $(MIPDIR)/regs.c + $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/regs.c + +scan.o: scan.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ scan.c + +stabs.o: $(srcdir)/stabs.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/stabs.c + +symtabs.o: $(srcdir)/symtabs.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/symtabs.c + +table.o: $(MDIR)/table.c + $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/table.c + +trees.o: $(srcdir)/trees.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/trees.c + +unicode.o: $(COMMONDIR)/unicode.c + $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/unicode.c + +# +# round 3: build $(DEST) +# + +$(CCOM): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) + +$(CC0): $(OBJS0) + $(CC) $(LDFLAGS) $(OBJS0) -o $@ $(LIBS) + +$(CC1): $(OBJS1) + $(CC) $(LDFLAGS) $(OBJS1) -o $@ $(LIBS) + +install: $(DEST) + test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)" + $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir) + test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1" + $(INSTALL_DATA) $(srcdir)/ccom.1 $(DESTDIR)$(mandir)/man1/$(MANPAGE).1 + +clean: + rm -f $(DEST) $(OBJS0) $(OBJS1) $(MKEXT) $(LOBJS) \ + $(LEX_OUTPUT_ROOT).c scan.c y.tab.[ch] cgram.[ch] external.[ch] + +distclean: clean + rm -f Makefile diff --git a/lang/pcc/pcc/cc/ccom/builtins.c b/lang/pcc/pcc/cc/ccom/builtins.c new file mode 100644 index 000000000..e5b393e72 --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/builtins.c @@ -0,0 +1,1057 @@ +/* $Id: builtins.c,v 1.67 2016/03/05 15:31:24 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#define ccopy p1tcopy + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +#ifndef NO_C_BUILTINS + +extern int dimfuncnt; +/* + * replace an alloca function with direct allocation on stack. + * return a destination temp node. + */ +static P1ND * +builtin_alloca(const struct bitable *bt, P1ND *a) +{ + P1ND *t, *u; + +#ifdef notyet + if (xnobuiltins) + return NULL; +#endif + + t = tempnode(0, VOID|PTR, 0, 0); + u = tempnode(regno(t), VOID|PTR, 0, 0); + spalloc(t, a, SZCHAR); + return u; +} + +/* + * Determine if a value is known to be constant at compile-time and + * hence that PCC can perform constant-folding on expressions involving + * that value. + */ +static P1ND * +builtin_constant_p(const struct bitable *bt, P1ND *a) +{ + P1ND *f; + int isconst; + + p1walkf(a, putjops, 0); + for (f = a; f->n_op == COMOP; f = f->n_right) + ; + isconst = nncon(f); + p1tfree(a); + return bcon(isconst); +} + +/* + * Hint to the compiler whether this expression will evaluate true or false. + * Just ignored for now. + */ +static P1ND * +builtin_expect(const struct bitable *bt, P1ND *a) +{ + P1ND *f; + + if (a && a->n_op == CM) { + p1tfree(a->n_right); + f = a->n_left; + p1nfree(a); + a = f; + } + + return a; +} + +/* + * Take integer absolute value. + * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1))) + */ +static P1ND * +builtin_abs(const struct bitable *bt, P1ND *a) +{ + P1ND *p, *q, *r, *t, *t2, *t3; + int tmp1, tmp2, shift; + + if (a->n_type != INT) + a = cast(a, INT, 0); + + if (a->n_op == ICON) { + if (glval(a) < 0) + slval(a, -glval(a)); + p = a; + } else { + t = tempnode(0, a->n_type, a->n_df, a->n_ap); + tmp1 = regno(t); + p = buildtree(ASSIGN, t, a); + + t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); + shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1; + q = buildtree(RS, t, bcon(shift)); + + t2 = tempnode(0, a->n_type, a->n_df, a->n_ap); + tmp2 = regno(t2); + q = buildtree(ASSIGN, t2, q); + + t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); + t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); + t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); + r = buildtree(MINUS, buildtree(ER, t, t2), t3); + + p = buildtree(COMOP, p, buildtree(COMOP, q, r)); + } + + return p; +} + +#define cmop(x,y) buildtree(COMOP, x, y) +#define lblnod(l) nlabel(l) + +#ifndef TARGET_BSWAP +static P1ND * +builtin_bswap16(const struct bitable *bt, P1ND *a) +{ + P1ND *f, *t1, *t2; + + t1 = buildtree(LS, buildtree(AND, ccopy(a), bcon(255)), bcon(8)); + t2 = buildtree(AND, buildtree(RS, a, bcon(8)), bcon(255)); + f = buildtree(OR, t1, t2); + return f; +} + +static P1ND * +builtin_bswap32(const struct bitable *bt, P1ND *a) +{ + P1ND *f, *t1, *t2, *t3, *t4; + + t1 = buildtree(LS, buildtree(AND, ccopy(a), bcon(255)), bcon(24)); + t2 = buildtree(LS, buildtree(AND, ccopy(a), bcon(255 << 8)), bcon(8)); + t3 = buildtree(AND, buildtree(RS, ccopy(a), bcon(8)), bcon(255 << 8)); + t4 = buildtree(AND, buildtree(RS, a, bcon(24)), bcon(255)); + f = buildtree(OR, buildtree(OR, t1, t2), buildtree(OR, t3, t4)); + return f; +} + +static P1ND * +builtin_bswap64(const struct bitable *bt, P1ND *a) +{ + P1ND *f, *t1, *t2, *t3, *t4, *t5, *t6, *t7, *t8; + +#define X(x) xbcon(x, NULL, ctype(ULONGLONG)) + t1 = buildtree(LS, buildtree(AND, ccopy(a), X(255)), bcon(56)); + t2 = buildtree(LS, buildtree(AND, ccopy(a), X(255 << 8)), bcon(40)); + t3 = buildtree(LS, buildtree(AND, ccopy(a), X(255 << 16)), bcon(24)); + t4 = buildtree(LS, buildtree(AND, ccopy(a), X(255 << 24)), bcon(8)); + t5 = buildtree(AND, buildtree(RS, ccopy(a), bcon(8)), X(255 << 24)); + t6 = buildtree(AND, buildtree(RS, ccopy(a), bcon(24)), X(255 << 16)); + t7 = buildtree(AND, buildtree(RS, ccopy(a), bcon(40)), X(255 << 8)); + t8 = buildtree(AND, buildtree(RS, a, bcon(56)), X(255)); + f = buildtree(OR, + buildtree(OR, buildtree(OR, t1, t2), buildtree(OR, t3, t4)), + buildtree(OR, buildtree(OR, t5, t6), buildtree(OR, t7, t8))); + return f; +#undef X +} + +#endif + +#ifndef TARGET_CXZ +/* + * Find number of beginning 0's in a word of type t. + * t should be deunsigned. + */ +static P1ND * +builtin_cxz(P1ND *a, TWORD t, int isclz) +{ + P1ND *t101, *t102; + P1ND *rn, *p; + int l15, l16, l17; + int sz; + + t = ctype(t); + sz = (int)tsize(t, 0, 0); + + t101 = tempnode(0, INT, 0, 0); + t102 = tempnode(0, t, 0, 0); + l15 = getlab(); + l16 = getlab(); + l17 = getlab(); + rn = buildtree(ASSIGN, ccopy(t102), a); + rn = cmop(rn, buildtree(ASSIGN, ccopy(t101), bcon(0))); + rn = cmop(rn, lblnod(l16)); + + p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15)); + rn = cmop(rn, p); + if (isclz) { + p = buildtree(CBRANCH, + buildtree(GE, ccopy(t102), bcon(0)), bcon(l17)); + } else { + p = buildtree(CBRANCH, + buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), + bcon(0)), bcon(l17)); + } + rn = cmop(rn, p); + + rn = cmop(rn, block(GOTO, bcon(l15), NULL, INT, 0, 0)); + + rn = cmop(rn, lblnod(l17)); + rn = cmop(rn, buildtree(isclz ? LSEQ : RSEQ , t102, bcon(1))); + + rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); + + rn = cmop(rn, block(GOTO, bcon(l16), NULL, INT, 0, 0)); + rn = cmop(rn, lblnod(l15)); + return cmop(rn, t101); +} + +static P1ND * +builtin_clz(const struct bitable *bt, P1ND *a) +{ + return builtin_cxz(a, INT, 1); +} + +static P1ND * +builtin_clzl(const struct bitable *bt, P1ND *a) +{ + return builtin_cxz(a, LONG, 1); +} + +static P1ND * +builtin_clzll(const struct bitable *bt, P1ND *a) +{ + return builtin_cxz(a, LONGLONG, 1); +} + +static P1ND * +builtin_ctz(const struct bitable *bt, P1ND *a) +{ + return builtin_cxz(a, INT, 0); +} + +static P1ND * +builtin_ctzl(const struct bitable *bt, P1ND *a) +{ + return builtin_cxz(a, LONG, 0); +} + +static P1ND * +builtin_ctzll(const struct bitable *bt, P1ND *a) +{ + return builtin_cxz(a, LONGLONG, 0); +} +#endif + +#ifndef TARGET_ERA +static P1ND * +builtin_era(const struct bitable *bt, P1ND *a) +{ + return a; /* Just pass through */ +} +#endif + +#ifndef TARGET_FFS +/* + * Find number of beginning 0's in a word of type t. + * t should be deunsigned. + */ +static P1ND * +builtin_ff(P1ND *a, TWORD t) +{ + P1ND *t101, *t102; + P1ND *rn, *p; + int l15, l16, l17; + int sz; + + t = ctype(t); + sz = (int)tsize(t, 0, 0)+1; + + t101 = tempnode(0, INT, 0, 0); + t102 = tempnode(0, t, 0, 0); + l15 = getlab(); + l16 = getlab(); + l17 = getlab(); + rn = buildtree(ASSIGN, ccopy(t101), bcon(0)); + rn = cmop(rn, buildtree(ASSIGN, ccopy(t102), a)); + + p = buildtree(CBRANCH, buildtree(EQ, ccopy(t102), bcon(0)), bcon(l15)); + rn = cmop(rn, p); + + rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); + + rn = cmop(rn, lblnod(l16)); + + p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15)); + rn = cmop(rn, p); + + p = buildtree(CBRANCH, + buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), + bcon(0)), bcon(l17)); + rn = cmop(rn, p); + + rn = cmop(rn, block(GOTO, bcon(l15), NULL, INT, 0, 0)); + + rn = cmop(rn, lblnod(l17)); + rn = cmop(rn, buildtree(RSEQ, t102, bcon(1))); + + rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); + + rn = cmop(rn, block(GOTO, bcon(l16), NULL, INT, 0, 0)); + rn = cmop(rn, lblnod(l15)); + return cmop(rn, t101); +} + +static P1ND * +builtin_ffs(const struct bitable *bt, P1ND *a) +{ + return builtin_ff(a, INT); +} + +static P1ND * +builtin_ffsl(const struct bitable *bt, P1ND *a) +{ + return builtin_ff(a, LONG); +} + +static P1ND * +builtin_ffsll(const struct bitable *bt, P1ND *a) +{ + return builtin_ff(a, LONGLONG); +} +#endif + +/* + * Get size of object, if possible. + * 0 = whole object, 1 == closest object. Return -1 if not available. + * 2 == max of rem object, 3 == min of rem obj. Return 0 if not available. + */ +static P1ND * +builtin_object_size(const struct bitable *bt, P1ND *a) +{ + CONSZ v = icons(a->n_right); + int r; + + if (v < 0 || v > 3) + uerror("arg2 must be between 0 and 3"); + r = v < 2 ? -1 : 0; + + a = p1nfree(a); +#ifdef notyet + if (ISPTR(a->n_type)) { + a = buildtree(UMUL, a, 0); + a = optloop(a); + a = doszof(a); + } +#else + p1walkf(a, putjops, 0); /* if ?: exists */ + p1tfree(a); +#endif + return xbcon(r, NULL, bt->rt); +} + +#ifndef TARGET_STDARGS +static P1ND * +builtin_stdarg_start(const struct bitable *bt, P1ND *a) +{ + P1ND *p, *q; + int sz; + + /* must first deal with argument size; use int size */ + p = a->n_right; + if (p->n_type < INT) { + sz = (int)(SZINT/tsize(p->n_type, p->n_df, p->n_ap)); + } else + sz = 1; + + /* do the real job */ + p = buildtree(ADDROF, p, NULL); /* address of last arg */ +#ifdef BACKAUTO + p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */ +#else + p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */ +#endif + q = block(NAME, NULL, NULL, PTR+VOID, 0, 0); /* create cast node */ + q = buildtree(CAST, q, p); /* cast to void * (for assignment) */ + p = q->n_right; + p1nfree(q->n_left); + p1nfree(q); + p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */ + p1nfree(a); + return p; +} + +static P1ND * +builtin_va_arg(const struct bitable *bt, P1ND *a) +{ + P1ND *p, *q, *r, *rv; + int sz, nodnum; + + /* create a copy to a temp node of current ap */ + p = ccopy(a->n_left); + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + nodnum = regno(q); + rv = buildtree(ASSIGN, q, p); + + r = a->n_right; + sz = (int)tsize(r->n_type, r->n_df, r->n_ap); +#ifdef MYVAARGSZ + SETOFF(sz, MYVAARGSZ); +#endif + sz /= SZCHAR; + /* add one to ap */ +#ifdef BACKAUTO + rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz))); +#else +#error fix wrong eval order in builtin_va_arg + ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz))); +#endif + + p1nfree(a->n_right); + p1nfree(a); + r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_ap); + return buildtree(COMOP, rv, buildtree(UMUL, r, NULL)); + +} + +static P1ND * +builtin_va_end(const struct bitable *bt, P1ND *a) +{ + return a; /* may have side effects */ +} + +static P1ND * +builtin_va_copy(const struct bitable *bt, P1ND *a) +{ + P1ND *f; + + f = buildtree(ASSIGN, a->n_left, a->n_right); + p1nfree(a); + return f; +} +#endif /* TARGET_STDARGS */ + +/* + * For unimplemented "builtin" functions, try to invoke the + * non-builtin name + */ +static P1ND * +binhelp(P1ND *a, TWORD rt, char *n) +{ + P1ND *f = block(NAME, NULL, NULL, INT, 0, 0); + int oblvl = blevel; + + blevel = 0; + f->n_sp = lookup(addname(n), SNORMAL); + blevel = oblvl; + if (f->n_sp->sclass == SNULL) { + f->n_sp->sclass = EXTERN; + f->n_sp->stype = INCREF(rt)+(FTN-PTR); + f->n_sp->sdf = permalloc(sizeof(union dimfun)); + dimfuncnt++; + f->n_sp->sdf->dfun = NULL; + } + f->n_type = f->n_sp->stype; + f = clocal(f); + return buildtree(CALL, f, a); +} + +static P1ND * +builtin_unimp(const struct bitable *bt, P1ND *a) +{ + return binhelp(a, bt->rt, &bt->name[10]); +} + +#if 0 +static P1ND * +builtin_unimp_f(P1ND *f, P1ND *a, TWORD rt) +{ + return binhelp(f, a, rt, f->n_sp->sname); +} +#endif + +#ifndef TARGET_PREFETCH +static P1ND * +builtin_prefetch(const struct bitable *bt, P1ND *a) +{ + p1tfree(a); + return bcon(0); +} +#endif + +/* + * check if compatible types. + * XXX - all enum are considered equal types + */ +static P1ND * +builtin_tc(const struct bitable *bt, P1ND *a) +{ + P1ND *p; + + if (a == NULL || a->n_op != CM || + a->n_left->n_op != TYPE || a->n_right->n_op != TYPE) + uerror("bad %s arg", bt->name); + + p = bcon(a->n_left->n_type == a->n_right->n_type); + p1nfree(a->n_left); + p1nfree(a->n_right); + p1nfree(a); + return p; +} + +static void +putinlbl(P1ND *p, void *arg) +{ + if (p->n_op == COMOP && p->n_left->n_op == GOTO) { + int v = (int)glval(p->n_left->n_left); + send_passt(IP_DEFLAB, v+1); + } +} + +/* + * Similar to ?: + */ +static P1ND * +builtin_ce(const struct bitable *bt, P1ND *a) +{ + P1ND *p; + + if (a == NULL || a->n_op != CM || + a->n_left->n_op != CM || a->n_left->n_left->n_op == CM) + uerror("bad %s arg", bt->name); + if (nncon(a->n_left->n_left) == 0) + uerror("arg not constant"); + if (glval(a)) { + p = a->n_left->n_right; + a->n_left->n_op = UMUL; /* for p1tfree() */ + p1walkf(a->n_right, putinlbl, 0); + } else { + p = a->n_right; + a->n_op = UMUL; /* for p1tfree() */ + p1walkf(a->n_left->n_right, putinlbl, 0); + } + p1tfree(a); + return p; + +} + +static P1ND * +builtin_classify_type(const struct bitable *bt, P1ND *a) +{ + TWORD t = a->n_type; + int rv; + + if (t == BOOL) + rv = 4; + else if (t == CHAR || t == UCHAR) + rv = 2; + else if (t <= ULONGLONG) + rv = 1; + else if (t == STRTY) + rv = 12; + else if (t == UNIONTY) + rv = 13; + else if (ISPTR(t)) + rv = 5; + else if (ISFTY(t)) + rv = 8; + else if (ISFTN(t)) + rv = 10; + else if (ISCTY(t)) + rv = 9; + else + rv = -1; + + p1tfree(a); + return bcon(rv); +} + + +#ifndef TARGET_ISMATH +/* + * Handle the builtin macros for the math functions is* + * To get something that is be somewhat generic assume that + * isnan() is a real function and that cast of a NaN type + * to double will still be a NaN. + */ +static P1ND * +mtisnan(P1ND *p) +{ + + return binhelp(cast(ccopy(p), DOUBLE, 0), INT, "isnan"); +} + +static TWORD +mtcheck(P1ND *p) +{ + TWORD t1 = p->n_left->n_type, t2 = p->n_right->n_type; + + if ((t1 >= FLOAT && t1 <= LDOUBLE) || + (t2 >= FLOAT && t2 <= LDOUBLE)) + return MAX(t1, t2); + return 0; +} + +static P1ND * +builtin_isunordered(const struct bitable *bt, P1ND *a) +{ + P1ND *p; + + if (mtcheck(a) == 0) + return bcon(0); + + p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); + p1tfree(a); + return p; +} +static P1ND * +builtin_isany(P1ND *a, TWORD rt, int cmpt) +{ + P1ND *p, *q; + TWORD t; + + if ((t = mtcheck(a)) == 0) + return bcon(0); + p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); + p = buildtree(NOT, p, NULL); + q = buildtree(cmpt, cast(ccopy(a->n_left), t, 0), + cast(ccopy(a->n_right), t, 0)); + p = buildtree(ANDAND, p, q); + p1tfree(a); + return p; +} +static P1ND * +builtin_isgreater(const struct bitable *bt, P1ND *a) +{ + return builtin_isany(a, bt->rt, GT); +} +static P1ND * +builtin_isgreaterequal(const struct bitable *bt, P1ND *a) +{ + return builtin_isany(a, bt->rt, GE); +} +static P1ND * +builtin_isless(const struct bitable *bt, P1ND *a) +{ + return builtin_isany(a, bt->rt, LT); +} +static P1ND * +builtin_islessequal(const struct bitable *bt, P1ND *a) +{ + return builtin_isany(a, bt->rt, LE); +} +static P1ND * +builtin_islessgreater(const struct bitable *bt, P1ND *a) +{ + P1ND *p, *q, *r; + TWORD t; + + if ((t = mtcheck(a)) == 0) + return bcon(0); + p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); + p = buildtree(NOT, p, NULL); + q = buildtree(GT, cast(ccopy(a->n_left), t, 0), + cast(ccopy(a->n_right), t, 0)); + r = buildtree(LT, cast(ccopy(a->n_left), t, 0), + cast(ccopy(a->n_right), t, 0)); + q = buildtree(OROR, q, r); + p = buildtree(ANDAND, p, q); + p1tfree(a); + return p; +} +#endif + +/* + * Math-specific builtins that expands to constants. + * Versions here are for IEEE FP, vax needs its own versions. + */ +#if TARGET_ENDIAN == TARGET_LE +static const unsigned char vFLOAT[] = { 0, 0, 0x80, 0x7f }; +static const unsigned char vDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }; +#ifdef LDBL_128 +static const unsigned char vLDOUBLE[] = { 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f }; +#else /* LDBL_80 */ +static const unsigned char vLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f,0,0,0,0,0,0 }; +#endif +static const unsigned char nFLOAT[] = { 0, 0, 0xc0, 0x7f }; +static const unsigned char nDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f }; +#ifdef LDBL_128 +static const unsigned char nLDOUBLE[] = { 0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f }; +#else /* LDBL_80 */ +static const unsigned char nLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f,0,0,0,0,0,0 }; +#endif +#else +static const unsigned char vFLOAT[] = { 0x7f, 0x80, 0, 0 }; +static const unsigned char vDOUBLE[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }; +#ifdef LDBL_128 +static const unsigned char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 }; +#else /* LDBL_80 */ +static const unsigned char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 }; +#endif +static const unsigned char nFLOAT[] = { 0x7f, 0xc0, 0, 0 }; +static const unsigned char nDOUBLE[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 }; +#ifdef LDBL_128 +static const unsigned char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 }; +#else /* LDBL_80 */ +static const unsigned char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 }; +#endif +#endif + +#define VALX(typ,TYP) { \ + typ d; \ + int x; \ + P1ND *f; \ + x = MIN(sizeof(n ## TYP), sizeof(d)); \ + memcpy(&d, v ## TYP, x); \ + f = block(FCON, NULL, NULL, TYP, NULL, 0); \ + f->n_dcon = stmtalloc(sizeof(FLT)); \ + f->n_dcon->fp = d; \ + return f; \ +} + +static P1ND * +builtin_huge_valf(const struct bitable *bt, P1ND *a) VALX(float,FLOAT) +static P1ND * +builtin_huge_val(const struct bitable *bt, P1ND *a) VALX(double,DOUBLE) +static P1ND * +builtin_huge_vall(const struct bitable *bt, P1ND *a) VALX(long double,LDOUBLE) + +#define builtin_inff builtin_huge_valf +#define builtin_inf builtin_huge_val +#define builtin_infl builtin_huge_vall + +/* + * Return NANs, if reasonable. + */ +static P1ND * +builtin_nanx(const struct bitable *bt, P1ND *a) +{ + + if (a == NULL || a->n_op == CM) { + uerror("%s bad argument", bt->name); + a = bcon(0); + } else if (a->n_op == STRING && *a->n_name == '\0') { + a->n_op = FCON; + a->n_type = bt->rt; + if (sizeof(nLDOUBLE) < sizeof(long double)) + cerror("nLDOUBLE too small"); + a->n_dcon = stmtalloc(sizeof(FLT)); + memcpy(&a->n_dcon->fp, nLDOUBLE, sizeof(long double)); + } else + a = binhelp(eve(a), bt->rt, &bt->name[10]); + return a; +} + +#ifndef NO_COMPLEX +static P1ND * +builtin_cir(const struct bitable *bt, P1ND *a) +{ + char *n; + + if (a == NULL || a->n_op == CM) { + uerror("wrong argument count to %s", bt->name); + return bcon(0); + } + + n = addname(bt->name[1] == 'r' ? "__real" : "__imag"); + return cast(structref(a, DOT, n), bt->rt, 0); +} + +#endif + +/* + * Target defines, to implement target versions of the generic builtins + */ +#ifndef TARGET_MEMCMP +#define builtin_memcmp builtin_unimp +#endif +#ifndef TARGET_MEMCPY +#define builtin_memcpy builtin_unimp +#endif +#ifndef TARGET_MEMPCPY +#define builtin_mempcpy builtin_unimp +#endif +#ifndef TARGET_MEMSET +#define builtin_memset builtin_unimp +#endif + +/* Reasonable type of size_t */ +#ifndef SIZET +#if SZINT == SZSHORT +#define SIZET UNSIGNED +#elif SZLONG > SZINT +#define SIZET ULONG +#else +#define SIZET UNSIGNED +#endif +#endif + +static TWORD memcpyt[] = { VOID|PTR, VOID|PTR, SIZET, INT }; +static TWORD memsett[] = { VOID|PTR, INT, SIZET, INT }; +static TWORD allocat[] = { SIZET }; +static TWORD expectt[] = { LONG, LONG }; +static TWORD strcmpt[] = { CHAR|PTR, CHAR|PTR }; +static TWORD strcpyt[] = { CHAR|PTR, CHAR|PTR, INT }; +static TWORD strncpyt[] = { CHAR|PTR, CHAR|PTR, SIZET, INT }; +static TWORD strchrt[] = { CHAR|PTR, INT }; +static TWORD strcspnt[] = { CHAR|PTR, CHAR|PTR }; +static TWORD strspnt[] = { CHAR|PTR, CHAR|PTR }; +static TWORD strpbrkt[] = { CHAR|PTR, CHAR|PTR }; +static TWORD nant[] = { CHAR|PTR }; +static TWORD bitt[] = { UNSIGNED }; +static TWORD bsw16t[] = { USHORT }; +static TWORD bitlt[] = { ULONG }; +static TWORD bitllt[] = { ULONGLONG }; +static TWORD abst[] = { INT }; +static TWORD fmaxft[] = { FLOAT, FLOAT }; +static TWORD fmaxt[] = { DOUBLE, DOUBLE }; +static TWORD fmaxlt[] = { LDOUBLE, LDOUBLE }; +static TWORD scalbnft[] = { FLOAT, INT }; +static TWORD scalbnt[] = { DOUBLE, INT }; +static TWORD scalbnlt[] = { LDOUBLE, INT }; + +static const struct bitable bitable[] = { + /* gnu universe only */ + { "alloca", builtin_alloca, BTGNUONLY, 1, allocat, VOID|PTR }, + +#ifndef NO_COMPLEX + /* builtins for complex operations */ + { "crealf", builtin_cir, BTNOPROTO, 1, 0, FLOAT }, + { "creal", builtin_cir, BTNOPROTO, 1, 0, DOUBLE }, + { "creall", builtin_cir, BTNOPROTO, 1, 0, LDOUBLE }, + { "cimagf", builtin_cir, BTNOPROTO, 1, 0, FLOAT }, + { "cimag", builtin_cir, BTNOPROTO, 1, 0, DOUBLE }, + { "cimagl", builtin_cir, BTNOPROTO, 1, 0, LDOUBLE }, +#endif + /* always existing builtins */ + { "__builtin___memcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, + { "__builtin___mempcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, + { "__builtin___memmove_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, + { "__builtin___memset_chk", builtin_unimp, 0, 4, memsett, VOID|PTR }, + + { "__builtin___strcat_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR }, + { "__builtin___strcpy_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR }, + { "__builtin___stpcpy_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR }, + { "__builtin___strncat_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR }, + { "__builtin___strncpy_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR }, + { "__builtin___stpncpy_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR }, + + { "__builtin___printf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___fprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___sprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___snprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___vprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___vfprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___vsprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___vsnprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + + { "__builtin_alloca", builtin_alloca, 0, 1, allocat, VOID|PTR }, + { "__builtin_abs", builtin_abs, 0, 1, abst, INT }, + { "__builtin_bswap16", builtin_bswap16, 0, 1, bsw16t, USHORT }, + { "__builtin_bswap32", builtin_bswap32, 0, 1, bitt, UNSIGNED }, + { "__builtin_bswap64", builtin_bswap64, 0, 1, bitllt, ULONGLONG }, + { "__builtin_choose_expr", builtin_ce, BTNOPROTO|BTNORVAL, 0, 0, 0 }, + { "__builtin_clz", builtin_clz, 0, 1, bitt, INT }, + { "__builtin_clzl", builtin_clzl, 0, 1, bitlt, INT }, + { "__builtin_clzll", builtin_clzll, 0, 1, bitllt, INT }, + { "__builtin_ctz", builtin_ctz, 0, 1, bitt, INT }, + { "__builtin_ctzl", builtin_ctzl, 0, 1, bitlt, INT }, + { "__builtin_ctzll", builtin_ctzll, 0, 1, bitllt, INT }, + { "__builtin_extract_return_addr", builtin_era, 0, 1, memcpyt, VOID|PTR }, + { "__builtin_ffs", builtin_ffs, 0, 1, bitt, INT }, + { "__builtin_ffsl", builtin_ffsl, 0, 1, bitlt, INT }, + { "__builtin_ffsll", builtin_ffsll, 0, 1, bitllt, INT }, + { "__builtin_popcount", builtin_unimp, 0, 1, bitt, UNSIGNED }, + { "__builtin_popcountl", builtin_unimp, 0, 1, bitlt, ULONG }, + { "__builtin_popcountll", builtin_unimp, 0, 1, bitllt, ULONGLONG }, + + { "__builtin_classify_type", builtin_classify_type, 0, 1, 0, INT }, + { "__builtin_constant_p", builtin_constant_p, 0, 1, 0, INT }, + { "__builtin_copysignf", builtin_unimp, 0, 2, fmaxft, FLOAT }, + { "__builtin_copysign", builtin_unimp, 0, 2, fmaxt, DOUBLE }, + { "__builtin_copysignl", builtin_unimp, 0, 2, fmaxlt, LDOUBLE }, + { "__builtin_expect", builtin_expect, 0, 2, expectt, LONG }, + { "__builtin_memcmp", builtin_memcmp, 0, 3, memcpyt, INT }, + { "__builtin_memcpy", builtin_memcpy, 0, 3, memcpyt, VOID|PTR }, + { "__builtin_mempcpy", builtin_mempcpy, 0, 3, memcpyt, VOID|PTR }, + { "__builtin_memset", builtin_memset, 0, 3, memsett, VOID|PTR }, + { "__builtin_fabsf", builtin_unimp, 0, 1, fmaxft, FLOAT }, + { "__builtin_fabs", builtin_unimp, 0, 1, fmaxt, DOUBLE }, + { "__builtin_fabsl", builtin_unimp, 0, 1, fmaxlt, LDOUBLE }, + { "__builtin_fmaxf", builtin_unimp, 0, 2, fmaxft, FLOAT }, + { "__builtin_fmax", builtin_unimp, 0, 2, fmaxt, DOUBLE }, + { "__builtin_fmaxl", builtin_unimp, 0, 2, fmaxlt, LDOUBLE }, + { "__builtin_huge_valf", builtin_huge_valf, 0, 0, 0, FLOAT }, + { "__builtin_huge_val", builtin_huge_val, 0, 0, 0, DOUBLE }, + { "__builtin_huge_vall", builtin_huge_vall, 0, 0, 0, LDOUBLE }, + { "__builtin_inff", builtin_inff, 0, 0, 0, FLOAT }, + { "__builtin_inf", builtin_inf, 0, 0, 0, DOUBLE }, + { "__builtin_infl", builtin_infl, 0, 0, 0, LDOUBLE }, + { "__builtin_isgreater", builtin_isgreater, 0, 2, NULL, INT }, + { "__builtin_isgreaterequal", builtin_isgreaterequal, 0, 2, NULL, INT }, + { "__builtin_isinff", builtin_unimp, 0, 1, fmaxft, INT }, + { "__builtin_isinf", builtin_unimp, 0, 1, fmaxt, INT }, + { "__builtin_isinfl", builtin_unimp, 0, 1, fmaxlt, INT }, + { "__builtin_isless", builtin_isless, 0, 2, NULL, INT }, + { "__builtin_islessequal", builtin_islessequal, 0, 2, NULL, INT }, + { "__builtin_islessgreater", builtin_islessgreater, 0, 2, NULL, INT }, + { "__builtin_isnanf", builtin_unimp, 0, 1, fmaxft, INT }, + { "__builtin_isnan", builtin_unimp, 0, 1, fmaxt, INT }, + { "__builtin_isnanl", builtin_unimp, 0, 1, fmaxlt, INT }, + { "__builtin_isunordered", builtin_isunordered, 0, 2, NULL, INT }, + { "__builtin_logbf", builtin_unimp, 0, 1, fmaxft, FLOAT }, + { "__builtin_logb", builtin_unimp, 0, 1, fmaxt, DOUBLE }, + { "__builtin_logbl", builtin_unimp, 0, 1, fmaxlt, LDOUBLE }, + { "__builtin_nanf", builtin_nanx, BTNOEVE, 1, nant, FLOAT }, + { "__builtin_nan", builtin_nanx, BTNOEVE, 1, nant, DOUBLE }, + { "__builtin_nanl", builtin_nanx, BTNOEVE, 1, nant, LDOUBLE }, + { "__builtin_object_size", builtin_object_size, BTNOPROTO, 2, memsett, SIZET }, + { "__builtin_prefetch", builtin_prefetch, 0, 1, memsett, VOID }, + { "__builtin_scalbnf", builtin_unimp, 0, 2, scalbnft, FLOAT }, + { "__builtin_scalbn", builtin_unimp, 0, 2, scalbnt, DOUBLE }, + { "__builtin_scalbnl", builtin_unimp, 0, 2, scalbnlt, LDOUBLE }, + { "__builtin_strcmp", builtin_unimp, 0, 2, strcmpt, INT }, + { "__builtin_strcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR }, + { "__builtin_stpcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR }, + { "__builtin_strchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR }, + { "__builtin_strlen", builtin_unimp, 0, 1, strcmpt, SIZET }, + { "__builtin_strrchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR }, + { "__builtin_strncpy", builtin_unimp, 0, 3, strncpyt, CHAR|PTR }, + { "__builtin_strncat", builtin_unimp, 0, 3, strncpyt, CHAR|PTR }, + { "__builtin_strcspn", builtin_unimp, 0, 2, strcspnt, SIZET }, + { "__builtin_strspn", builtin_unimp, 0, 2, strspnt, SIZET }, + { "__builtin_strstr", builtin_unimp, 0, 2, strcmpt, CHAR|PTR }, + { "__builtin_strpbrk", builtin_unimp, 0, 2, strpbrkt, CHAR|PTR }, + { "__builtin_types_compatible_p", builtin_tc, BTNOPROTO, 2, 0, INT }, +#ifndef TARGET_STDARGS + { "__builtin_stdarg_start", builtin_stdarg_start, 0, 2, 0, VOID }, + { "__builtin_va_start", builtin_stdarg_start, 0, 2, 0, VOID }, + { "__builtin_va_arg", builtin_va_arg, BTNORVAL|BTNOPROTO, 2, 0, 0 }, + { "__builtin_va_end", builtin_va_end, 0, 1, 0, VOID }, + { "__builtin_va_copy", builtin_va_copy, 0, 2, 0, VOID }, +#endif + { "__builtin_dwarf_cfa", builtin_cfa, 0, 0, 0, VOID|PTR }, + { "__builtin_frame_address", + builtin_frame_address, 0, 1, bitt, VOID|PTR }, + { "__builtin_return_address", + builtin_return_address, 0, 1, bitt, VOID|PTR }, +#ifdef TARGET_BUILTINS + TARGET_BUILTINS +#endif +}; + +/* + * Check and cast arguments for builtins. + */ +static int +acnt(P1ND *a, int narg, TWORD *tp) +{ + P1ND *q; + TWORD t; + + if (a == NULL) + return narg; + for (; a->n_op == CM; a = a->n_left, narg--) { + if (tp == NULL) + continue; + q = a->n_right; + t = ctype(tp[narg-1]); + if (q->n_type == t) + continue; + a->n_right = ccast(q, t, 0, NULL, 0); + } + + /* Last arg is ugly to deal with */ + if (narg == 1 && tp != NULL && a->n_type != tp[0]) { + q = p1alloc(); + *q = *a; + q = ccast(q, ctype(tp[0]), 0, NULL, 0); + *a = *q; + p1nfree(q); + } + return narg != 1; +} + +P1ND * +builtin_check(struct symtab *sp, P1ND *a) +{ + const struct bitable *bt; + + if (sp->soffset < 0 || + sp->soffset >= (int)(sizeof(bitable)/sizeof(bitable[0]))) + cerror("builtin_check"); + + bt = &bitable[sp->soffset]; + if ((bt->flags & BTNOEVE) == 0 && a != NULL) + a = eve(a); + if (((bt->flags & BTNOPROTO) == 0) && acnt(a, bt->narg, bt->tp)) { + uerror("wrong argument count to %s", bt->name); + return bcon(0); + } + return (*bt->fun)(bt, a); +} + +/* + * Put all builtin functions into the global symbol table. + */ +void +builtin_init() +{ + const struct bitable *bt; + P1ND *p = block(TYPE, 0, 0, 0, 0, 0); + struct symtab *sp; + int i, d_debug; + + d_debug = ddebug; + ddebug = 0; + for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) { + bt = &bitable[i]; + if ((bt->flags & BTGNUONLY) && xgnu99 == 0 && xgnu89 == 0) + continue; /* not in c99 universe, at least for now */ + sp = lookup(addname(bt->name), 0); + if (bt->rt == 0 && (bt->flags & BTNORVAL) == 0) + cerror("function '%s' has no return type", bt->name); + p->n_type = INCREF(bt->rt) + (FTN-PTR); + p->n_df = memset(permalloc(sizeof(union dimfun)), 0, + sizeof(union dimfun)); + dimfuncnt++; + p->n_sp = sp; + defid(p, EXTERN); + sp->soffset = i; + sp->sflags |= SBUILTIN; + } + p1nfree(p); + ddebug = d_debug; +} +#endif diff --git a/lang/pcc/pcc/cc/ccom/ccom.1 b/lang/pcc/pcc/cc/ccom/ccom.1 new file mode 100644 index 000000000..1aafa9699 --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/ccom.1 @@ -0,0 +1,465 @@ +.\" $Id: ccom.1,v 1.31 2014/06/06 14:59:46 plunky Exp $ +.\" +.\" Copyright (c) 2007 Jeremy C. Reed +.\" +.\" Permission to use, copy, modify, and/or distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM +.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND +.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +.\" THIS SOFTWARE. +.\" +.Dd March 22, 2012 +.Dt CCOM 1 +.Os +.Sh NAME +.Nm ccom +.Nd C compiler +.Sh SYNOPSIS +.Nm +.Op Fl gkpsv +.Op Fl f Ar features +.Op Fl m Ar options +.Op Fl W Ar warnings +.Op Fl X Ar flags +.Op Fl x Ar settings +.Op Fl Z Ar flags +.Op infile +.Op outfile +.Sh DESCRIPTION +The +.Nm +utility provides a C compiler. +The frontend is usually +.Xr pcc 1 . +It is +.Em not +intended to be run directly. +.Nm +reads the C source from +.Ar infile +or standard input and writes the assembler source +to +.Ar outfile +or to standard output. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl f Ar feature +Enable language features. +Multiple +.Fl f +options can be given, the following features are supported: +.Bl -tag -width Ds +.It Sy stack-protector +Enable stack smashing protection. +Currently the same as +.Sy stack-protector-all . +.It Sy stack-protector-all +Enable stack smashing protection for all functions. +.It Sy pack-struct Ns Oo = Ns Ar n Oc +Specify maximum alignment for structure members, similar to a #pragma pack +statement at the start of the file. +If no value is given, the default is 1. +.It Sy freestanding +Emit code for a freestanding environment. +Currently not implemented. +.El +.It Fl g +Include debugging information in the output code for use by +symbolic and source-level debuggers. +Currently this uses the +.Sy stabs +format, encoding information in +.Em s Ns ymbol Em tab Ns le entrie Ns Em s. +.It Fl k +Generate PIC code. +.It Fl m Ar option +Target-specific options, used in machine-dependent code. +Multiple +.Fl m +options can be given, the following options are supported: +.Bl -tag -width PowerPC +.It AMD64 +.It ARM +.Sy little-endian , +.Sy big-endian , +.Sy fpe=fpa , +.Sy fpe=vpf , +.Sy soft-float , +.Sy arch=armv1 , +.Sy arch=armv2 , +.Sy arch=armv2a , +.Sy arch=armv3 , +.Sy arch=armv4 , +.Sy arch=armv4t , +.Sy arch=armv4tej , +.Sy arch=armv5 , +.Sy arch=armv5te , +.Sy arch=armv5tej , +.Sy arch=armv6 , +.Sy arch=armv6t2 , +.Sy arch=armv6kz , +.Sy arch=armv6k No \*(Am +.Sy arch=armv7 . +.It HPPA +.It i386 +.It M16C +.It MIPS +.Sy little-endian No \*(Am +.Sy big-endian . +.It NOVA +.It PDP-10 +.It PDP-11 +.It PowerPC +.Sy little-endian , +.Sy big-endian , +.Sy soft-float No \*(Am +.Sy hard-float . +.It Sparc64 +.It VAX +.El +.It Fl p +Generate profiling code. +.It Fl s +Print statistics to standard error when complete. +This includes: +name table entries, name string size, permanent allocated memory, +temporary allocated memory, lost memory, argument list unions, +dimension/function unions, struct/union/enum blocks, inline node count, +inline control blocks, and permanent symtab entries. +.\" TODO: explain units for above? +.It Fl v +Display version. +.It Fl W Ar warning +Do some basic checks and emit warnings about possible coding problems. +Multiple +.Fl W +options can be given, the following warnings are supported: +.Bl -tag -width Ds +.It Sy error Ns Oo = Ns Ar warning Oc +Enable +.Ar warning , +and treat it as an error condition. +If a specific warning is not given, producing any warning will cause an error. +.It Sy deprecated-declarations +Report whenever a symbol marked with the +.Sq deprecated +attribute is used. +This warning is enabled by default. +.It Sy implicit-function-declaration +(TODO) Require explicit prototypes for all called functions. +.It Sy implicit-int +(TODO) Warn when a function declaration lacks a type. +.It Sy missing-prototypes +Require explicit prototypes for all global function definitions. +.It Sy pointer-sign +Warn when pointer operations are done with mismatched signed and unsigned values. +.It Sy sign-compare +(TODO) Warn about comparisons between signed and unsigned values. +.It Sy strict-prototypes +(TODO) Require that function prototypes are strictly C99. +.It Sy shadow +Report when a local variable shadows something from a higher scope. +.It Sy truncate +Report when integer values may be implicitly truncated to fit a smaller type. +.It Sy unknown-pragmas +Report unhandled pragma statements. +.It Sy unreachable-code +Report statements that cannot be executed. +.El +.Pp +Any of the above may be prefixed with +.Dq no- +in order to disable the effect. +.\" +.It Fl X Ar flags +C specific debugging where +.Ar flags +is one or more of the following: +.Pp +.Bl -tag -compact -width Ds +.It Sy b +Building of parse trees +.It Sy d +Declarations (using multiple +.Sy d +flags gives more output) +.It Sy e +Pass1 trees at exit +.It Sy i +Initializations +.It Sy n +Memory allocations +.It Sy o +Turn off optimisations +.It Sy p +Prototypes +.It Sy s +Inlining +.It Sy t +Type conversions +.It Sy x +Target-specific flag, used in machine-dependent code +.El +.\" +.It Fl x Ar setting +Enable +.Ar setting +in the compiler. +Multiple +.Fl x +options can be given, the following settings are supported: +.Bl -tag -width Ds +.It Sy ccp +Apply sparse conditional constant propagation techniques for optimization. +Currently not implemented. +.It Sy dce +Do dead code elimination. +.It Sy deljumps +Delete redundant jumps and dead code. +.It Sy gnu89 +.It Sy gnu99 +Use GNU C semantics rather than C99 for some things. +Currently only inline. +.It Sy inline +Replace calls to functions marked with an inline specifier with a copy +of the actual function. +.It Sy ssa +Convert statements into static single assignment form for optimization. +Not yet finished. +.It Sy tailcall +Enable optimization of tail-recursion functions. +Currently not implemented. +.It Sy temps +Locate automatic variables into registers where possible, for further +optimization by the register allocator. +.It Sy uchar +Treat character constants as unsigned values. +.El +.\" +.It Fl Z Ar flags +Code generator (pass2) specific debugging where +.Ar flags +is one or more of the following: +.Pp +.Bl -tag -compact -width Ds +.It Sy b +Basic block and SSA building +.It Sy c +Code printout +.It Sy e +Trees when entering pass2 +.It Sy f +Instruction matcher, may provide much output +.It Sy g +Print flow graphs +.It Sy n +Memory allocation +.It Sy o +Instruction generator +.It Sy r +Register allocator +.It Sy s +Shape matching in instruction generator +.It Sy t +Type matching in instruction generator +.It Sy u +Sethi-Ullman computations +.It Sy x +Target-specific flag, used in machine-dependent code +.El +.El +.Sh PRAGMAS +Input lines starting with a +.Dq #pragma +directive can be used to modify behaviour of +.Nm +during compilation. +All tokens up to the first unescaped newline are considered part +of the pragma command, with the following operations being recognized: +.Bl -tag -width Ds +.It Sy STDC +Standard C99 operator follows. +Currently no C99 operations are implemented, and any directives starting +with this token will be silently ignored. +.It Sy GCC diagnostic Ar effect Qq Ar option +GNU C compatibility. +Alter the effects of compiler diagnostics. +The required +.Ar effect +should be stated as +.Sy warning , +.Sy error +or +.Sy ignored , +followed by the compiler diagnostic +.Ar option +in double quotes. +For example, to force unknown pragmas to always generate an error, +a standard header might include +.Bd -literal -offset 2n +#pragma GCC diagnostic error "-Wunknown-pragmas" +.Ed +.It Sy GCC poison Ar identifier ... +GNU C compatibility. +Cause an error if any of the following +.Ar identifier Ns s +subsequently appear in the code +.Pq but not in any macro expansions . +Currently not implemented. +.It Sy GCC system_header +GNU C compatibility. +Currently not implemented. +.It Sy GCC visibility +GNU C compatibility. +Currently not implemented. +.It Sy pack Ns Pq Op Ar n +Set the default maximum alignment for structures and unions, such that +members will have their natural alignment requirements clamped at this +value and may be stored misaligned. +If +.Ar n +is not given, the alignment is reset to the target default. +.It Sy pack Ns Pq Sy push Ns Op , Ar n +Push the current pack setting onto an internal stack then, if +.Ar n +is given, change the default alignment for structures and unions. +Currently not implemented. +.It Sy pack Ns Pq Sy pop +Change the pack setting to the most recently pushed value, and remove +that setting from the stack. +Currently not implemented. +.It Sy packed Op Ar n +Set the maximum alignment for the structure or union defined +in the current statement. +If +.Ar n +is not given, the default value of 1 is used. +.Pq Currently this works except Ar n is not used +.It Sy aligned Op Ar n +Set the minimum alignment for the structure or union defined +in the current statement. +.It Sy rename Ar name +Provide an alternative +.Ar name +which will be used to reference the object declared in the current statement. +.It Sy weak Ar name Ns Op = Ns Ar alias +Mark +.Ar name +as a weak rather than a global symbol, to allow its definition to be +overridden at link time. +If an +.Ar alias +is given, this will be used as the default value of +.Ar name . +.It Sy ident +Currently not implemented. +.El +.Lp +and the following target-specific operations are handled by +machine-dependent code: +.Bl -tag -width Ds +.It Sy tls +For AMD64 and i386 targets, the variable declared in the current statement +will be referenced via the +.Dq thread-local storage +mechanism. +.It Sy init +For AMD64, ARM, HPPA, i386, MIPS and PowerPC targets, when the current statement is a +function declaration, generate a reference in the +.Sy .ctors +section, enabling library code to call the function prior to entering +.Fn main . +.It Sy fini +For AMD64, ARM, HPPA, i386, MIPS and PowerPC targets, when the current statement is a +function declaration, generate a reference in the +.Sy .dtors +section, enabling library code to call the function when +.Fn main +returns or the +.Fn exit +function is called. +.It Sy section Ar name +For AMD64, ARM, HPPA and i386 targets, place the subsequent code in the named +section. +.Pq This is currently broken . +.It Sy alias Ar name +For AMD64, HPPA and i386 targets, emit assembler instructions providing an +alias for the symbol defined by the current statement. +.It Sy stdcall +For i386 targets, enable +.Dq stdcall +semantics during code generation, where function arguments are passed on +the stack in right-to-left order, and the callee is responsible for adjusting +the stack pointer before returning. +Any function result is passed in the EAX register. +On win32, the function name is postfixed with an +.Dq @ +and the size of the stack adjustment. +.It Sy cdecl +For i386 targets, enable +.Dq cdecl +semantics during code generation, where function arguments are passed on +the stack in right-to-left order, and the caller is responsible for cleaning +up the stack after the function returns. +Any function result is passed in the EAX register. +This is the default. +.It Sy fastcall +For i386-win32 targets, enable +.Dq fastcall +semantics during code generation. +.Po +Currently this is equivalent to +.Sy stdcall , +which is likely wrong +.Pc . +.It Sy dllimport +For i386-win32 targets, references to the external symbol defined by +the current statement will be made via indirect access through a +location identified by the symbol name prefixed with +.Dq __imp_ . +.It Sy dllexport +For i386-win32 targets, the external symbol declared by the current +statement will be exported as an indirect reference to be +accessed with +.Sy dllimport . +The global locator will be the symbol name prefixed with +.Dq __imp_ . +Currently this is not completely implemented. +.El +.Pp +Any unknown +.Dq #pragma +directives will be ignored unless the +.Fl Wunknown-pragmas +diagnostic is in effect. +.Sh SEE ALSO +.Xr as 1 , +.Xr cpp 1 , +.Xr pcc 1 +.Sh HISTORY +The +.Nm +compiler is based on the original Portable C Compiler by +.An "S. C. Johnson" , +written in the late 70's. +Even though much of the compiler has been rewritten +.Pq about 50% of the frontend code and 80% of the backend , +some of the basics still remain. +Most is written by +.An "Anders Magnusson" , +with the exception of the data-flow analysis part and +the SSA conversion code which is written by +.An "Peter A Jonsson" , +and the Mips port that were written as part of a project +by undergraduate students at Lulea University of Technology. +.Pp +This product includes software developed or owned by Caldera +International, Inc. diff --git a/lang/pcc/pcc/cc/ccom/cgram.y b/lang/pcc/pcc/cc/ccom/cgram.y new file mode 100644 index 000000000..86ae5b6af --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/cgram.y @@ -0,0 +1,2629 @@ +/* $Id: cgram.y,v 1.414 2016/03/05 15:31:24 ragge Exp $ */ + +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 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. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ + +/* + * Comments for this grammar file. Ragge 021123 + * + * ANSI support required rewrite of the function header and declaration + * rules almost totally. + * + * The lex/yacc shared keywords are now split from the keywords used + * in the rest of the compiler, to simplify use of other frontends. + */ + +/* + * At last count, there were 5 shift/reduce and no reduce/reduce conflicts + * All are accounted for; + * One is "dangling else" + * Two is in attribute parsing + * Two is in ({ }) parsing + */ + +/* + * Token used in C lex/yacc communications. + */ +%token C_STRING /* a string constant */ +%token C_ICON /* an integer constant */ +%token C_FCON /* a floating point constant */ +%token C_NAME /* an identifier */ +%token C_TYPENAME /* a typedef'd name */ +%token C_ANDAND /* && */ +%token C_OROR /* || */ +%token C_GOTO /* unconditional goto */ +%token C_RETURN /* return from function */ +%token C_TYPE /* a type */ +%token C_CLASS /* a storage class */ +%token C_ASOP /* assignment ops */ +%token C_RELOP /* <=, <, >=, > */ +%token C_EQUOP /* ==, != */ +%token C_DIVOP /* /, % */ +%token C_SHIFTOP /* <<, >> */ +%token C_INCOP /* ++, -- */ +%token C_UNOP /* !, ~ */ +%token C_STROP /* ., -> */ +%token C_STRUCT +%token C_IF +%token C_ELSE +%token C_SWITCH +%token C_BREAK +%token C_CONTINUE +%token C_WHILE +%token C_DO +%token C_FOR +%token C_DEFAULT +%token C_CASE +%token C_SIZEOF +%token C_ENUM +%token C_ELLIPSIS +%token C_QUALIFIER +%token C_FUNSPEC +%token C_ASM +%token NOMATCH +%token C_TYPEOF /* COMPAT_GCC */ +%token C_ATTRIBUTE /* COMPAT_GCC */ +%token PCC_OFFSETOF +%token GCC_DESIG + +/* C11 keywords */ +%token C_STATICASSERT +%token C_ALIGNAS +%token C_ALIGNOF +%token C_GENERIC +%token C_ATOMIC + +/* + * Precedence + */ +%left ',' +%right '=' C_ASOP +%right '?' ':' +%left C_OROR +%left C_ANDAND +%left '|' +%left '^' +%left '&' +%left C_EQUOP +%left C_RELOP +%left C_SHIFTOP +%left '+' '-' +%left '*' C_DIVOP +%right C_UNOP +%right C_INCOP C_SIZEOF +%left '[' '(' C_STROP +%{ +# include "pass1.h" +# include +# include +# include + +int fun_inline; /* Reading an inline function */ +int oldstyle; /* Current function being defined */ +static struct symtab *xnf; +extern int enummer, tvaloff, inattr; +extern struct rstack *rpole; +static int alwinl; +P1ND *cftnod; +static int attrwarn = 1; + +#define NORETYP SNOCREAT /* no return type, save in unused field in symtab */ + +struct genlist { + struct genlist *next; + P1ND *p; + TWORD t; +}; + + P1ND *bdty(int op, ...); +static void fend(void); +static void fundef(P1ND *tp, P1ND *p); +static void olddecl(P1ND *p, P1ND *a); +static struct symtab *init_declarator(P1ND *tn, P1ND *p, int assign, P1ND *a, + char *as); +static void resetbc(int mask); +static void swend(void); +static void addcase(P1ND *p); +#ifdef GCC_COMPAT +static void gcccase(P1ND *p, P1ND *); +#endif +static struct attr *gcc_attr_wrapper(P1ND *p); +static void adddef(void); +static void savebc(void); +static void swstart(int, TWORD); +static void genswitch(int, TWORD, struct swents **, int); +static char *mkpstr(char *str); +static struct symtab *clbrace(P1ND *); +static P1ND *cmop(P1ND *l, P1ND *r); +static P1ND *xcmop(P1ND *out, P1ND *in, P1ND *str); +static void mkxasm(char *str, P1ND *p); +static P1ND *xasmop(char *str, P1ND *p); +static P1ND *biop(int op, P1ND *l, P1ND *r); +static void flend(void); +static P1ND *gccexpr(int bn, P1ND *q); +static char * simname(char *s); +static P1ND *tyof(P1ND *); /* COMPAT_GCC */ +static P1ND *voidcon(void); +static P1ND *funargs(P1ND *p); +static void oldargs(P1ND *p); +static void uawarn(P1ND *p, char *s); +static int con_e(P1ND *p); +static void dainit(P1ND *d, P1ND *a); +static P1ND *tymfix(P1ND *p); +static P1ND *namekill(P1ND *p, int clr); +static P1ND *aryfix(P1ND *p); +static P1ND *dogen(struct genlist *g, P1ND *e); +static struct genlist *newgen(P1ND *p, P1ND *q); +static struct genlist *addgen(struct genlist *g, struct genlist *h); + +static void savlab(int); +static void xcbranch(P1ND *, int); +extern int *mkclabs(void); + +#define TYMFIX(inp) { \ + P1ND *pp = inp; \ + inp = tymerge(pp->n_left, pp->n_right); \ + p1nfree(pp->n_left); p1nfree(pp); } + +struct xalloc; +extern struct xalloc *bkpole, *sapole; +extern int cbkp, cstp; +extern int usdnodes; +struct bks { + struct xalloc *ptr; + int off; +}; + +/* + * State for saving current switch state (when nested switches). + */ +struct savbc { + struct savbc *next; + int brklab; + int contlab; + int flostat; + int swx; + struct xalloc *bkptr; + int bkoff; + struct xalloc *stptr; + int stoff; + int numnode; +} *savbc, *savctx; + +%} + +%union { + TWORD type; + int intval; + P1ND *nodep; + struct symtab *symp; + struct rstack *rp; + char *strp; + struct bks *bkp; + FLT *flt; + struct genlist *g; +} + + /* define types */ +%start ext_def_list + +%type ifelprefix ifprefix whprefix forprefix doprefix switchpart + xbegin +%type e .e term enum_dcl struct_dcl cast_type declarator + elist type_sq cf_spec merge_attribs e2 ecq + parameter_declaration abstract_declarator initializer + parameter_type_list parameter_list + declaration_specifiers designation + specifier_qualifier_list merge_specifiers + identifier_list arg_param_list type_qualifier_list + designator_list designator xasm oplist oper cnstr funtype + typeof attribute attribute_specifier /* COMPAT_GCC */ + attribute_list attr_spec_list attr_var /* COMPAT_GCC */ + +%type gen_ass_list gen_assoc +%type string C_STRING GCC_DESIG svstr +%type str_head +%type xnfdeclarator clbrace enum_head + +%type C_STRUCT C_RELOP C_DIVOP C_SHIFTOP + C_ANDAND C_OROR C_STROP C_INCOP C_UNOP C_ASOP C_EQUOP + +%type C_TYPE C_QUALIFIER C_CLASS C_FUNSPEC + +%type C_ICON + +%type C_FCON + +%type C_NAME C_TYPENAME +%% + +ext_def_list: ext_def_list external_def + | { ftnend(); } + ; + +external_def: funtype kr_args compoundstmt { fend(); } + | declaration { blevel = 0; symclear(0); } + | asmstatement ';' + | ';' + | error { blevel = 0; } + ; + +funtype: /* no type given */ declarator { + fundef(mkty(INT, 0, 0), $1); + cftnsp->sflags |= NORETYP; + } + | declaration_specifiers declarator { fundef($1,$2); } + ; + +kr_args: /* empty */ + | arg_dcl_list + ; + +/* + * Returns a node pointer or NULL, if no types at all given. + * Type trees are checked for correctness and merged into one + * type node in typenode(). + */ +declaration_specifiers: + merge_attribs { $$ = typenode($1); } + ; + +merge_attribs: type_sq { $$ = $1; } + | type_sq merge_attribs { $$ = cmop($2, $1); } + | cf_spec { $$ = $1; } + | cf_spec merge_attribs { $$ = cmop($2, $1); } + ; + +type_sq: C_TYPE { $$ = mkty($1, 0, 0); } + | C_TYPENAME { + struct symtab *sp = lookup($1, 0); + if (sp->stype == ENUMTY) { + sp->stype = strmemb(sp->sap)->stype; + } + $$ = mkty(sp->stype, sp->sdf, sp->sap); + $$->n_sp = sp; + } + | struct_dcl { $$ = $1; } + | enum_dcl { $$ = $1; } + | C_QUALIFIER { $$ = block(QUALIFIER, NULL, NULL, 0, 0, 0); $$->n_qual = $1; } + | attribute_specifier { $$ = biop(ATTRIB, $1, 0); } + | C_ALIGNAS '(' e ')' { + $$ = biop(ALIGN, NULL, NULL); + slval($$, con_e($3)); + } + | C_ALIGNAS '(' cast_type ')' { + TYMFIX($3); + $$ = biop(ALIGN, NULL, NULL); + slval($$, talign($3->n_type, $3->n_ap)/SZCHAR); + p1tfree($3); + } + | C_ATOMIC { uerror("_Atomic not supported"); $$ = bcon(0); } + | C_ATOMIC '(' cast_type ')' { + uerror("_Atomic not supported"); $$ = $3; + } + | typeof { $$ = $1; } + ; + +cf_spec: C_CLASS { $$ = block(CLASS, NULL, NULL, $1, 0, 0); } + | C_FUNSPEC { $$ = block(FUNSPEC, NULL, NULL, $1, 0, 0); } + ; + +typeof: C_TYPEOF '(' e ')' { $$ = tyof(eve($3)); } + | C_TYPEOF '(' cast_type ')' { TYMFIX($3); $$ = tyof($3); } + ; + +attribute_specifier : + C_ATTRIBUTE '(' '(' attribute_list ')' ')' { $$ = $4; } + /*COMPAT_GCC*/ ; + +attribute_list: attribute + | attribute ',' attribute_list { $$ = cmop($3, $1); } + ; + +attribute: { +#ifdef GCC_COMPAT + $$ = voidcon(); +#endif + } + | C_NAME { $$ = bdty(NAME, $1); } + | C_NAME '(' elist ')' { + $$ = bdty($3 == NULL ? UCALL : CALL, bdty(NAME, $1), $3); + } + ; + +/* + * Adds a pointer list to front of the declarators. + */ +declarator: '*' declarator { $$ = bdty(UMUL, $2); } + | '*' type_qualifier_list declarator { + $$ = $2; + $$->n_left = $3; + } + | C_NAME { $$ = bdty(NAME, $1); } + | '(' attr_spec_list declarator ')' { + $$ = $3; + $$->n_ap = attr_add($$->n_ap, gcc_attr_wrapper($2)); + } + | '(' declarator ')' { $$ = $2; } + | declarator '[' ecq ']' { $$ = biop(LB, $1, $3); } + | declarator '(' parameter_type_list ')' { + $$ = bdty(CALL, $1, $3); + } + | declarator '(' identifier_list ')' { + $$ = bdty(CALL, $1, $3); + oldstyle = 1; + } + | declarator '(' ')' { $$ = bdty(UCALL, $1); } + ; + +ecq: maybe_r { $$ = bcon(NOOFFSET); } + | e { $$ = $1; } + | r e { $$ = $2; } + | c maybe_r e { $$ = $3; } + | r c e { $$ = $3; } + | '*' { $$ = bcon(NOOFFSET); } + | r '*' { $$ = bcon(NOOFFSET); } + ; + +r: C_QUALIFIER { + if ($1 != 0) + uerror("bad qualifier"); + } + ; + +c: C_CLASS { + if ($1 != STATIC) + uerror("bad class keyword"); + } + ; + +type_qualifier_list: + C_QUALIFIER { $$ = biop(UMUL, 0, 0); $$->n_qual = $1; } + | type_qualifier_list C_QUALIFIER { + $$ = $1; + $$->n_qual |= $2; + } + | attribute_specifier { + $$ = block(UMUL, NULL, NULL, 0, 0, gcc_attr_wrapper($1)); + } + | type_qualifier_list attribute_specifier { + $1->n_ap = attr_add($1->n_ap, gcc_attr_wrapper($2)); + } + ; + +identifier_list: C_NAME { $$ = bdty(NAME, $1); oldargs($$); } + | identifier_list ',' C_NAME { + $$ = cmop($1, bdty(NAME, $3)); + oldargs($$->n_right); + } + ; + +/* + * Returns as parameter_list, but can add an additional ELLIPSIS node. + */ +parameter_type_list: + parameter_list { $$ = $1; } + | parameter_list ',' C_ELLIPSIS { + $$ = cmop($1, biop(ELLIPSIS, NULL, NULL)); + } + ; + +/* + * Returns a linked lists of nodes of op CM with parameters on + * its right and additional CM nodes of its left pointer. + * No CM nodes if only one parameter. + */ +parameter_list: parameter_declaration { $$ = $1; } + | parameter_list ',' parameter_declaration { + $$ = cmop($1, $3); + } + ; + +/* + * Returns a node pointer to the declaration. + */ +parameter_declaration: + declaration_specifiers declarator attr_var { + if (glval($1) != SNULL && glval($1) != REGISTER) + uerror("illegal parameter class"); + $$ = block(TYMERGE, $1, $2, INT, 0, + gcc_attr_wrapper($3)); + } + | declaration_specifiers abstract_declarator { + $1->n_ap = attr_add($1->n_ap, $2->n_ap); + $$ = block(TYMERGE, $1, $2, INT, 0, 0); + } + | declaration_specifiers { + $$ = block(TYMERGE, $1, bdty(NAME, NULL), INT, 0, 0); + } + ; + +abstract_declarator: + '*' { $$ = bdty(UMUL, bdty(NAME, NULL)); } + | '*' type_qualifier_list { + $$ = $2; + $$->n_left = bdty(NAME, NULL); + } + | '*' abstract_declarator { $$ = bdty(UMUL, $2); } + | '*' type_qualifier_list abstract_declarator { + $$ = $2; + $$->n_left = $3; + } + | '(' abstract_declarator ')' { $$ = $2; } + | '[' maybe_r ']' attr_var { + $$ = block(LB, bdty(NAME, NULL), bcon(NOOFFSET), + INT, 0, gcc_attr_wrapper($4)); + } + | '[' e ']' attr_var { + $$ = block(LB, bdty(NAME, NULL), $2, + INT, 0, gcc_attr_wrapper($4)); + } + | abstract_declarator '[' maybe_r ']' attr_var { + $$ = block(LB, $1, bcon(NOOFFSET), + INT, 0, gcc_attr_wrapper($5)); + } + | abstract_declarator '[' e ']' attr_var { + $$ = block(LB, $1, $3, INT, 0, gcc_attr_wrapper($5)); + } + | '(' ')' attr_var { + $$ = bdty(UCALL, bdty(NAME, NULL)); + $$->n_ap = gcc_attr_wrapper($3); + } + | '(' ib2 parameter_type_list ')' attr_var { + $$ = block(CALL, bdty(NAME, NULL), $3, INT, 0, + gcc_attr_wrapper($5)); + } + | abstract_declarator '(' ')' attr_var { + $$ = block(UCALL, $1, NULL, INT, 0, gcc_attr_wrapper($4)); + } + | abstract_declarator '(' ib2 parameter_type_list ')' attr_var { + $$ = block(CALL, $1, $4, INT, 0, gcc_attr_wrapper($6)); + } + ; + +ib2: { } + ; + +maybe_r: { } + | C_QUALIFIER { } + ; + +/* + * K&R arg declaration, between ) and { + */ +arg_dcl_list: arg_declaration + | arg_dcl_list arg_declaration + ; + + +arg_declaration: declaration_specifiers arg_param_list ';' { + p1nfree($1); + } + ; + +arg_param_list: declarator attr_var { + olddecl(block(TYMERGE, p1tcopy($0), $1, + INT, 0, 0), $2); + } + | arg_param_list ',' declarator attr_var { + olddecl(block(TYMERGE, p1tcopy($0), $3, + INT, 0, 0), $4); + } + ; + +/* + * Declarations in beginning of blocks. + */ +block_item_list: block_item + | block_item_list block_item + ; + +block_item: declaration + | statement { stmtfree(); } + ; + +/* + * Here starts the old YACC code. + */ + +/* + * Variables are declared in init_declarator. + */ +declaration: declaration_specifiers ';' { p1tfree($1); fun_inline = 0; } + | declaration_specifiers init_declarator_list ';' { + p1tfree($1); + fun_inline = 0; + } + | C_STATICASSERT '(' e ',' string ')' ';' { + int r = con_e($3); + if (r == 0) /* false */ + uerror($5); + } + ; + +/* + * Normal declaration of variables. curtype contains the current type node. + * Returns nothing, variables are declared in init_declarator. + */ +init_declarator_list: + init_declarator { symclear(blevel); } + | init_declarator_list ',' attr_var { $$ = $0; } init_declarator { + uawarn($3, "init_declarator"); + symclear(blevel); + } + ; + +enum_dcl: enum_head '{' moe_list optcomma '}' { $$ = enumdcl($1); } + | C_ENUM C_NAME { $$ = enumref($2); } + ; + +enum_head: C_ENUM { $$ = enumhd(NULL); } + | C_ENUM C_NAME { $$ = enumhd($2); } + ; + +moe_list: moe + | moe_list ',' moe + ; + +moe: C_NAME { moedef($1); } + | C_TYPENAME { moedef($1); } + | C_NAME '=' e { enummer = con_e($3); moedef($1); } + | C_TYPENAME '=' e { enummer = con_e($3); moedef($1); } + ; + +struct_dcl: str_head '{' struct_dcl_list '}' { + P1ND *p; + + $$ = dclstruct($1); + if (pragma_allpacked) { + p = bdty(CALL, bdty(NAME, "packed"), + bcon(pragma_allpacked)); + $$->n_ap = attr_add($$->n_ap,gcc_attr_wrapper(p)); } + } + | C_STRUCT attr_var C_NAME { + $$ = rstruct($3,$1); + uawarn($2, "struct_dcl"); + } + /*COMPAT_GCC*/ | str_head '{' '}' { $$ = dclstruct($1); } + ; + +attr_var: { + P1ND *q, *p; + + p = pragma_aligned ? bdty(CALL, bdty(NAME, "aligned"), + bcon(pragma_aligned)) : NULL; + if (pragma_packed) { + q = bdty(NAME, "packed"); + p = (p == NULL ? q : cmop(p, q)); + } + pragma_aligned = pragma_packed = 0; + $$ = p; + } + /*COMPAT_GCC*/ | attr_spec_list + ; + +attr_spec_list: attribute_specifier + | attr_spec_list attribute_specifier { $$ = cmop($1, $2); } + ; + +str_head: C_STRUCT attr_var { $$ = bstruct(NULL, $1, $2); } + | C_STRUCT attr_var C_NAME { $$ = bstruct($3, $1, $2); } + ; + +struct_dcl_list: struct_declaration + | struct_dcl_list struct_declaration + ; + +struct_declaration: + specifier_qualifier_list struct_declarator_list optsemi { + p1tfree($1); + } + ; + +optsemi: ';' { } + | optsemi ';' { werror("extra ; in struct"); } + ; + +specifier_qualifier_list: + merge_specifiers { $$ = typenode($1); } + ; + +merge_specifiers: type_sq merge_specifiers { $$ = cmop($2, $1); } + | type_sq { $$ = $1; } + ; + +struct_declarator_list: + struct_declarator { symclear(blevel); } + | struct_declarator_list ',' { $$=$0; } + struct_declarator { symclear(blevel); } + ; + +struct_declarator: declarator attr_var { + P1ND *p; + + $1 = aryfix($1); + p = tymerge($0, tymfix($1)); + if ($2) + p->n_ap = attr_add(p->n_ap, gcc_attr_wrapper($2)); + soumemb(p, (char *)$1->n_sp, 0); + p1tfree(p); + } + | ':' e { + int ie = con_e($2); + if (fldchk(ie)) + ie = 1; + falloc(NULL, ie, $0); + } + | declarator ':' e { + int ie = con_e($3); + if (fldchk(ie)) + ie = 1; + if ($1->n_op == NAME) { + /* XXX - tymfix() may alter $1 */ + tymerge($0, tymfix($1)); + soumemb($1, (char *)$1->n_sp, FIELD | ie); + p1nfree($1); + } else + uerror("illegal declarator"); + } + | declarator ':' e attr_spec_list { + int ie = con_e($3); + if (fldchk(ie)) + ie = 1; + if ($1->n_op == NAME) { + /* XXX - tymfix() may alter $1 */ + tymerge($0, tymfix($1)); + if ($4) + $1->n_ap = attr_add($1->n_ap, + gcc_attr_wrapper($4)); + soumemb($1, (char *)$1->n_sp, FIELD | ie); + p1nfree($1); + } else + uerror("illegal declarator"); + } + | /* unnamed member */ { + P1ND *p = $0; + char *c = permalloc(10); + + if (p->n_type != STRTY && p->n_type != UNIONTY) + uerror("bad unnamed member type"); + snprintf(c, 10, "*%dFAKE", getlab()); + soumemb(p, c, 0); + } + ; + + /* always preceeded by attributes */ +xnfdeclarator: declarator attr_var { + $$ = xnf = init_declarator($0, $1, 1, $2, 0); + } + | declarator C_ASM '(' svstr ')' { + $$ = xnf = init_declarator($0, $1, 1, NULL, $4); + } + ; + +/* + * Handles declarations and assignments. + * Returns nothing. + */ +init_declarator: declarator attr_var { + init_declarator($0, $1, 0, $2, 0); + } + | declarator C_ASM '(' svstr ')' attr_var { + init_declarator($0, $1, 0, $6, $4); + } + | xnfdeclarator '=' e { + if ($1->sclass == STATIC || $1->sclass == EXTDEF) + statinit++; + simpleinit($1, eve($3)); + if ($1->sclass == STATIC || $1->sclass == EXTDEF) + statinit--; + xnf = NULL; + } + | xnfdeclarator '=' begbr init_list optcomma '}' { + endinit(0); + xnf = NULL; + } + /*COMPAT_GCC*/ | xnfdeclarator '=' begbr '}' { endinit(0); xnf = NULL; } + ; + +begbr: '{' { beginit($-1); } + ; + +initializer: e %prec ',' { $$ = eve($1); } + | ibrace init_list optcomma '}' { $$ = NULL; } + | ibrace '}' { asginit(bcon(0)); $$ = NULL; } + ; + +init_list: designation initializer { dainit($1, $2); } + | init_list ',' designation initializer { dainit($3, $4); } + ; + +designation: designator_list '=' { desinit($1); $$ = NULL; } + | GCC_DESIG { desinit(bdty(NAME, $1)); $$ = NULL; } + | '[' e C_ELLIPSIS e ']' '=' { $$ = biop(CM, $2, $4); } + | { $$ = NULL; } + ; + +designator_list: designator { $$ = $1; } + | designator_list designator { $$ = $2; $$->n_left = $1; } + ; + +designator: '[' e ']' { + int ie = con_e($2); + if (ie < 0) { + uerror("designator must be non-negative"); + ie = 0; + } + $$ = biop(LB, NULL, bcon(ie)); + } + | C_STROP C_TYPENAME { + if ($1 != DOT) + uerror("invalid designator"); + $$ = bdty(NAME, $2); + } + | C_STROP C_NAME { + if ($1 != DOT) + uerror("invalid designator"); + $$ = bdty(NAME, $2); + } + ; + +optcomma : /* VOID */ + | ',' + ; + +ibrace: '{' { ilbrace(); } + ; + +/* STATEMENTS */ + +compoundstmt: begin block_item_list '}' { flend(); } + | begin '}' { flend(); } + ; + +begin: '{' { + struct savbc *bc = malloc(sizeof(struct savbc)); + if (blevel == 1) { +#ifdef STABS + if (gflag) + stabs_line(lineno); +#endif + dclargs(); + } +#ifdef STABS + if (gflag && blevel > 1) + stabs_lbrac(blevel+1); +#endif + ++blevel; + oldstyle = 0; + bc->contlab = autooff; + bc->next = savctx; + bc->bkptr = bkpole; + bc->bkoff = cbkp; + bc->stptr = sapole; + bc->stoff = cstp; + bc->numnode = usdnodes; + usdnodes = 0; + bkpole = sapole = NULL; + cbkp = cstp = 0; + savctx = bc; + if (!isinlining && sspflag && blevel == 2) + sspstart(); + } + ; + +statement: e ';' { ecomp(eve($1)); symclear(blevel); } + | compoundstmt + | ifprefix statement { plabel($1); reached = 1; } + | ifelprefix statement { + if ($1 != NOLAB) { + plabel( $1); + reached = 1; + } + } + | whprefix statement { + branch(contlab); + plabel( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP)) + reached = 1; + else + reached = 0; + resetbc(0); + } + | doprefix statement C_WHILE '(' e ')' ';' { + plabel(contlab); + if (flostat & FCONT) + reached = 1; + if (reached) + cbranch(buildtree(NE, eve($5), bcon(0)), + bcon($1)); + else + p1tfree(eve($5)); + plabel( brklab); + reached = 1; + resetbc(0); + } + | forprefix .e ')' statement + { plabel( contlab ); + if( flostat&FCONT ) reached = 1; + if( $2 ) ecomp( $2 ); + branch($1); + plabel( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1; + else reached = 0; + resetbc(0); + blevel--; + symclear(blevel); + } + | switchpart statement + { if( reached ) branch( brklab ); + plabel( $1 ); + swend(); + plabel( brklab); + if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1; + resetbc(FCONT); + } + | C_BREAK ';' { + if (brklab == NOLAB) + uerror("illegal break"); + else if (reached) + branch(brklab); + flostat |= FBRK; + reached = 0; + } + | C_CONTINUE ';' { + if (contlab == NOLAB) + uerror("illegal continue"); + else + branch(contlab); + flostat |= FCONT; + goto rch; + } + | C_RETURN ';' { + branch(retlab); + if (cftnsp->stype != VOID && + (cftnsp->sflags & NORETYP) == 0 && + cftnsp->stype != VOID+FTN) + uerror("return value required"); + rch: + if (!reached) + warner(Wunreachable_code); + reached = 0; + } + | C_RETURN e ';' { + P1ND *p, *q; + + p = nametree(cftnsp); + p->n_type = DECREF(p->n_type); + q = eve($2); +#ifdef TARGET_TIMODE + P1ND *r; + if ((r = gcc_eval_ticast(RETURN, p, q)) != NULL) + q = r; +#endif +#ifndef NO_COMPLEX + if (ANYCX(q) || ANYCX(p)) + q = cxret(q, p); + else if (ISITY(p->n_type) || ISITY(q->n_type)) { + q = imret(q, p); + if (ISITY(p->n_type)) + p->n_type -= (FIMAG-FLOAT); + if (ISITY(q->n_type)) + q->n_type -= (FIMAG-FLOAT); + } +#endif + p = buildtree(RETURN, p, q); + if (p->n_type == VOID) { + ecomp(p->n_right); + } else { + if (cftnod == NULL) { + P1ND *r = tempnode(0, p->n_type, + p->n_df, p->n_ap); + cftnod = tmpalloc(sizeof(P1ND)); + *cftnod = *r; + p1tfree(r); + } + ecomp(buildtree(ASSIGN, + p1tcopy(cftnod), p->n_right)); + } + p1tfree(p->n_left); + p1nfree(p); + branch(retlab); + reached = 0; + } + | C_GOTO C_NAME ';' { gotolabel($2); goto rch; } + | C_GOTO '*' e ';' { ecomp(biop(GOTO, eve($3), NULL)); } + | asmstatement ';' + | ';' + | error ';' + | error '}' + | label statement + ; + +asmstatement: C_ASM mvol '(' svstr ')' { send_passt(IP_ASM, mkpstr($4)); } + | C_ASM mvol '(' svstr xasm ')' { mkxasm($4, $5); } + ; + +svstr: string { $$ = addstring($1); } + ; + +mvol: /* empty */ + | C_QUALIFIER { } + ; + +xasm: ':' oplist { $$ = xcmop($2, NULL, NULL); } + | ':' oplist ':' oplist { $$ = xcmop($2, $4, NULL); } + | ':' oplist ':' oplist ':' cnstr { $$ = xcmop($2, $4, $6); } + ; + +oplist: /* nothing */ { $$ = NULL; } + | oper { $$ = $1; } + ; + +oper: svstr '(' e ')' { $$ = xasmop($1, pconvert(eve($3))); } + | oper ',' svstr '(' e ')' { + $$ = cmop($1, xasmop($3, pconvert(eve($5)))); + } + ; + +cnstr: svstr { $$ = xasmop($1, bcon(0)); } + | cnstr ',' svstr { $$ = cmop($1, xasmop($3, bcon(0))); } + ; + +label: C_NAME ':' attr_var { deflabel($1, $3); reached = 1; } + | C_TYPENAME ':' attr_var { deflabel($1, $3); reached = 1; } + | C_CASE e ':' { addcase(eve($2)); reached = 1; } +/* COMPAT_GCC */| C_CASE e C_ELLIPSIS e ':' { +#ifdef GCC_COMPAT + gcccase(eve($2), eve($4)); reached = 1; +#endif + } + | C_DEFAULT ':' { reached = 1; adddef(); flostat |= FDEF; } + ; + +doprefix: C_DO { + savebc(); + brklab = getlab(); + contlab = getlab(); + plabel( $$ = getlab()); + reached = 1; + } + ; +ifprefix: C_IF '(' e ')' { + xcbranch(eve($3), $$ = getlab()); + reached = 1; + } + ; +ifelprefix: ifprefix statement C_ELSE { + if (reached) + branch($$ = getlab()); + else + $$ = NOLAB; + plabel( $1); + reached = 1; + } + ; + +whprefix: C_WHILE '(' e ')' { + savebc(); + $3 = eve($3); + if ($3->n_op == ICON && glval($3) != 0) + flostat = FLOOP; + plabel( contlab = getlab()); + reached = 1; + brklab = getlab(); + if (flostat == FLOOP) + p1tfree($3); + else + xcbranch($3, brklab); + } + ; +forprefix: C_FOR '(' .e ';' .e ';' { + ++blevel; + if ($3) + ecomp($3); + savebc(); + contlab = getlab(); + brklab = getlab(); + plabel( $$ = getlab()); + reached = 1; + if ($5) + xcbranch($5, brklab); + else + flostat |= FLOOP; + } + | C_FOR '(' { ++blevel; } declaration .e ';' { + savebc(); + contlab = getlab(); + brklab = getlab(); + plabel( $$ = getlab()); + reached = 1; + if ($5) + xcbranch($5, brklab); + else + flostat |= FLOOP; + } + ; + +switchpart: C_SWITCH '(' e ')' { + P1ND *p; + int num; + TWORD t; + + savebc(); + brklab = getlab(); + $3 = eve($3); + if (!ISINTEGER($3->n_type)) { + uerror("switch expression must have integer " + "type"); + t = INT; + } else { + $3 = intprom($3); + t = $3->n_type; + } + p = tempnode(0, t, 0, 0); + num = regno(p); + ecomp(buildtree(ASSIGN, p, $3)); + branch( $$ = getlab()); + swstart(num, t); + reached = 0; + } + ; +/* EXPRESSIONS */ +.e: e { $$ = eve($1); } + | { $$=0; } + ; + +elist: { $$ = NULL; } + | e2 { $$ = $1; } + ; + +e2: e %prec ',' + | e2 ',' e { $$ = biop(CM, $1, $3); } + | e2 ',' cast_type { /* hack for stdarg */ + TYMFIX($3); + $3->n_op = TYPE; + $$ = biop(CM, $1, $3); + } + | cast_type { TYMFIX($1); $1->n_op = TYPE; $$ = $1; } + ; + +/* + * Precedence order of operators. + */ +e: e ',' e { $$ = biop(COMOP, $1, $3); } + | e '=' e { $$ = biop(ASSIGN, $1, $3); } + | e C_ASOP e { $$ = biop($2, $1, $3); } + | e '?' e ':' e { $$=biop(QUEST, $1, biop(COLON, $3, $5)); } +/* COMPAT_GCC */| e '?' ':' e { $$ = biop(BIQUEST, $1, $4); } + | e C_OROR e { $$ = biop($2, $1, $3); } + | e C_ANDAND e { $$ = biop($2, $1, $3); } + | e '|' e { $$ = biop(OR, $1, $3); } + | e '^' e { $$ = biop(ER, $1, $3); } + | e '&' e { $$ = biop(AND, $1, $3); } + | e C_EQUOP e { $$ = biop($2, $1, $3); } + | e C_RELOP e { $$ = biop($2, $1, $3); } + | e C_SHIFTOP e { $$ = biop($2, $1, $3); } + | e '+' e { $$ = biop(PLUS, $1, $3); } + | e '-' e { $$ = biop(MINUS, $1, $3); } + | e C_DIVOP e { $$ = biop($2, $1, $3); } + | e '*' e { $$ = biop(MUL, $1, $3); } + | term + ; + +xbegin: begin { + $$ = getlab(); getlab(); getlab(); + branch($$); plabel(($$)+2); + } + ; + +term: term C_INCOP { $$ = biop($2, $1, bcon(1)); } + | '*' term { $$ = biop(UMUL, $2, NULL); } + | '&' term { $$ = biop(ADDROF, $2, NULL); } + | '-' term { $$ = biop(UMINUS, $2, NULL ); } + | '+' term { $$ = biop(UPLUS, $2, NULL ); } + | C_UNOP term { $$ = biop($1, $2, NULL); } + | C_INCOP term { + $$ = biop($1 == INCR ? PLUSEQ : MINUSEQ, $2, bcon(1)); + } + | C_SIZEOF xa term { $$ = biop(SZOF, $3, bcon(0)); inattr = $2; } + | '(' cast_type ')' term %prec C_INCOP { + TYMFIX($2); + $$ = biop(CAST, $2, $4); + } + | C_SIZEOF xa '(' cast_type ')' %prec C_SIZEOF { + $$ = biop(SZOF, $4, bcon(1)); + inattr = $2; + } + | C_ALIGNOF xa '(' cast_type ')' { + int al; + TYMFIX($4); + al = talign($4->n_type, $4->n_ap); + $$ = bcon(al/SZCHAR); + inattr = $2; + p1tfree($4); + } + | '(' cast_type ')' clbrace init_list optcomma '}' { + endinit(0); + $$ = bdty(NAME, $4); + $$->n_op = CLOP; + } + | '(' cast_type ')' clbrace '}' { + endinit(0); + $$ = bdty(NAME, $4); + $$->n_op = CLOP; + } + | term '[' e ']' { $$ = biop(LB, $1, $3); } + | C_NAME '(' elist ')' { + $$ = biop($3 ? CALL : UCALL, bdty(NAME, $1), $3); + } + | term '(' elist ')' { $$ = biop($3 ? CALL : UCALL, $1, $3); } + | term C_STROP C_NAME { $$ = biop($2, $1, bdty(NAME, $3)); } + | term C_STROP C_TYPENAME { $$ = biop($2, $1, bdty(NAME, $3));} + | C_NAME %prec C_SIZEOF /* below ( */{ $$ = bdty(NAME, $1); } + | PCC_OFFSETOF '(' cast_type ',' term ')' { + TYMFIX($3); + $3->n_type = INCREF($3->n_type); + $3 = biop(CAST, $3, bcon(0)); + if ($5->n_op == NAME) { + $$ = biop(STREF, $3, $5); + } else { + P1ND *p = $5; + while (p->n_left->n_op != NAME) + p = p->n_left; + p->n_left = biop(STREF, $3, p->n_left); + $$ = $5; + } + $$ = biop(ADDROF, $$, NULL); + $3 = block(NAME, NULL, NULL, ENUNSIGN(INTPTR), 0, 0); + $$ = biop(CAST, $3, $$); + } + | C_ICON { $$ = $1; } + | C_FCON { $$ = bdty(FCON, $1); } + | svstr { $$ = bdty(STRING, $1, styp()); } + | '(' e ')' { $$=$2; } + | '(' xbegin e ';' '}' ')' { $$ = gccexpr($2, eve($3)); } + | '(' xbegin block_item_list e ';' '}' ')' { + $$ = gccexpr($2, eve($4)); + } + | '(' xbegin block_item_list '}' ')' { + $$ = gccexpr($2, voidcon()); + } + | C_ANDAND C_NAME { + struct symtab *s = lookup($2, SLBLNAME|STEMP); + if (s->soffset == 0) { + s->soffset = -getlab(); + s->sclass = STATIC; + } + savlab(s->soffset); + $$ = biop(ADDROF, bdty(GOTO, $2), NULL); + } + | C_GENERIC '(' e ',' gen_ass_list ')' { $$ = dogen($5, $3); } + ; + +gen_ass_list: gen_assoc { $$ = $1; } + | gen_ass_list ',' gen_assoc { $$ = addgen($1, $3); } + ; + +gen_assoc: cast_type ':' e { TYMFIX($1); $$ = newgen($1, $3); } + | C_DEFAULT ':' e { $$ = newgen(0, $3); } + ; + +xa: { $$ = inattr; inattr = 0; } + ; + +clbrace: '{' { P1ND *q = $-1; TYMFIX(q); $$ = clbrace(q); } + ; + +string: C_STRING { $$ = stradd(NULL, $1); } + | string C_STRING { $$ = stradd($1, $2); } + ; + +cast_type: specifier_qualifier_list { + $$ = biop(TYMERGE, $1, bdty(NAME, NULL)); + } + | specifier_qualifier_list abstract_declarator { + $$ = biop(TYMERGE, $1, aryfix($2)); + } + ; + +%% + +P1ND * +mkty(TWORD t, union dimfun *d, struct attr *sue) +{ + return block(TYPE, NULL, NULL, t, d, sue); +} + +P1ND * +bdty(int op, ...) +{ + CONSZ c; + va_list ap; + int val; + register P1ND *q; + + va_start(ap, op); + q = biop(op, NULL, NULL); + + switch (op) { + case UMUL: + case UCALL: + q->n_left = va_arg(ap, P1ND *); + q->n_rval = 0; + break; + + case FCON: + q->n_dcon = va_arg(ap, FLT *); + q->n_type = q->n_dcon->t; + break; + + case CALL: + q->n_left = va_arg(ap, P1ND *); + q->n_right = va_arg(ap, P1ND *); + break; + + case LB: + q->n_left = va_arg(ap, P1ND *); + if ((val = va_arg(ap, int)) <= 0) { + uerror("array size must be positive"); + val = 1; + } + q->n_right = bcon(val); + break; + + case GOTO: /* for named labels */ + q->n_ap = attr_add(q->n_ap, attr_new(ATTR_P1LABELS, 1)); + /* FALLTHROUGH */ + case NAME: + q->n_op = NAME; + q->n_sp = va_arg(ap, struct symtab *); /* XXX survive tymerge */ + break; + + case STRING: + q->n_type = PTR|CHAR; + q->n_name = va_arg(ap, char *); + c = va_arg(ap, TWORD); + slval(q, c); + break; + + default: + cerror("bad bdty"); + } + va_end(ap); + + return q; +} + +static void +flend(void) +{ + struct savbc *sc; + + if (!isinlining && sspflag && blevel == 2) + sspend(); +#ifdef STABS + if (gflag && blevel > 2) + stabs_rbrac(blevel); +#endif + --blevel; + if( blevel == 1 ) + blevel = 0; + symclear(blevel); /* Clean ut the symbol table */ + if (autooff > maxautooff) + maxautooff = autooff; + autooff = savctx->contlab; + blkfree(); + stmtfree(); + bkpole = savctx->bkptr; + cbkp = savctx->bkoff; + sapole = savctx->stptr; + cstp = savctx->stoff; + usdnodes = savctx->numnode; + sc = savctx->next; + free(savctx); + savctx = sc; +} + +/* + * XXX workaround routines for block level cleansing in gcc compat mode. + * Temporary should be re reserved for this value before. + */ +static P1ND * +p1mcopy(P1ND *p) +{ + P1ND *q; + + q = xmalloc(sizeof(P1ND)); + *q = *p; + + switch (coptype(q->n_op)) { + case BITYPE: + q->n_right = p1mcopy(p->n_right); + /* FALLTHROUGH */ + case UTYPE: + q->n_left = p1mcopy(p->n_left); + } + + return(q); +} + +static void +p1mfree(P1ND *p) +{ + int o = coptype(p->n_op); + if (o == BITYPE) + p1mfree(p->n_right); + if (o != LTYPE) + p1mfree(p->n_left); + free(p); +} + + +static P1ND * +gccexpr(int bn, P1ND *q) +{ + P1ND *r, *p, *s; + + branch(bn+4); + plabel(bn); + r = buildtree(COMOP, biop(GOTO, bcon(bn+2), NULL), q); + /* XXX hack to survive flend() */ + s = p1mcopy(r); + p1tfree(r); + flend(); + r = p1tcopy(s); + p1mfree(s); + q = r->n_right; + /* XXX end hack */ + if (!(q->n_op == ICON && q->n_type == STRTY) && (r->n_type != VOID)) { + p = tempnode(0, q->n_type, q->n_df, q->n_ap); + r = buildtree(ASSIGN, p1tcopy(p), r); + r = buildtree(COMOP, r, p); + } + return r; +} + +static void +savebc(void) +{ + struct savbc *bc = malloc(sizeof(struct savbc)); + + bc->brklab = brklab; + bc->contlab = contlab; + bc->flostat = flostat; + bc->next = savbc; + savbc = bc; + flostat = 0; +} + +static void +resetbc(int mask) +{ + struct savbc *bc; + + flostat = savbc->flostat | (flostat&mask); + contlab = savbc->contlab; + brklab = savbc->brklab; + bc = savbc->next; + free(savbc); + savbc = bc; +} + +struct swdef { + struct swdef *next; /* Next in list */ + int deflbl; /* Label for "default" */ + struct swents *ents; /* Linked sorted list of case entries */ + int nents; /* # of entries in list */ + int num; /* Node value will end up in */ + TWORD type; /* Type of switch expression */ +} *swpole; + +/* + * add case to switch + */ +static void +addcase(P1ND *p) +{ + struct swents **put, *w, *sw = malloc(sizeof(struct swents)); + CONSZ val; + + p = optloop(p); /* change enum to ints */ + if (p->n_op != ICON || p->n_sp != NULL) { + uerror( "non-constant case expression"); + return; + } + if (swpole == NULL) { + uerror("case not in switch"); + return; + } + + if (DEUNSIGN(swpole->type) != DEUNSIGN(p->n_type)) { + val = glval(p); + p = makety(p, swpole->type, 0, 0, 0); + if (p->n_op != ICON) + cerror("could not cast case value to type of switch " + "expression"); + if (glval(p) != val) + werror("case expression truncated"); + } + sw->sval = glval(p); + p1tfree(p); + put = &swpole->ents; + if (ISUNSIGNED(swpole->type)) { + for (w = swpole->ents; + w != NULL && (U_CONSZ)w->sval < (U_CONSZ)sw->sval; + w = w->next) + put = &w->next; + } else { + for (w = swpole->ents; w != NULL && w->sval < sw->sval; + w = w->next) + put = &w->next; + } + if (w != NULL && w->sval == sw->sval) { + uerror("duplicate case in switch"); + return; + } + plabel(sw->slab = getlab()); + *put = sw; + sw->next = w; + swpole->nents++; +} + +#ifdef GCC_COMPAT +void +gcccase(P1ND *ln, P1ND *hn) +{ + CONSZ i, l, h; + + l = icons(optim(ln)); + h = icons(optim(hn)); + + if (h < l) + i = l, l = h, h = i; + + for (i = l; i <= h; i++) + addcase(xbcon(i, NULL, hn->n_type)); +} +#endif + +/* + * add default case to switch + */ +static void +adddef(void) +{ + if (swpole == NULL) + uerror("default not inside switch"); + else if (swpole->deflbl != 0) + uerror("duplicate default in switch"); + else + plabel( swpole->deflbl = getlab()); +} + +static void +swstart(int num, TWORD type) +{ + struct swdef *sw = malloc(sizeof(struct swdef)); + + sw->deflbl = sw->nents = 0; + sw->ents = NULL; + sw->next = swpole; + sw->num = num; + sw->type = type; + swpole = sw; +} + +/* + * end a switch block + */ +static void +swend(void) +{ + struct swents *sw, **swp; + struct swdef *sp; + int i; + + sw = FUNALLO(sizeof(struct swents)); + swp = FUNALLO(sizeof(struct swents *) * (swpole->nents+1)); + + sw->slab = swpole->deflbl; + swp[0] = sw; + + for (i = 1; i <= swpole->nents; i++) { + swp[i] = swpole->ents; + swpole->ents = swpole->ents->next; + } + genswitch(swpole->num, swpole->type, swp, swpole->nents); + + FUNFREE(sw); + FUNFREE(swp); + while (swpole->ents) { + sw = swpole->ents; + swpole->ents = sw->next; + free(sw); + } + sp = swpole->next; + free(swpole); + swpole = sp; +} + +/* + * num: tempnode the value of the switch expression is in + * type: type of the switch expression + * + * p points to an array of structures, each consisting + * of a constant value and a label. + * The first is >=0 if there is a default label; + * its value is the label number + * The entries p[1] to p[n] are the nontrivial cases + * n is the number of case statements (length of list) + */ +static void +genswitch(int num, TWORD type, struct swents **p, int n) +{ + P1ND *r, *q; + int i; + + if (mygenswitch(num, type, p, n)) + return; + + /* simple switch code */ + for (i = 1; i <= n; ++i) { + /* already in 1 */ + r = tempnode(num, type, 0, 0); + q = xbcon(p[i]->sval, NULL, type); + r = buildtree(NE, r, clocal(q)); + xcbranch(r, p[i]->slab); + } + if (p[0]->slab > 0) + branch(p[0]->slab); +} + +/* + * Declare a variable or prototype. + */ +static struct symtab * +init_declarator(P1ND *tn, P1ND *p, int assign, P1ND *a, char *as) +{ + int class = glval(tn); + struct symtab *sp; + + p = aryfix(p); + p = tymerge(tn, p); + if (a) { + struct attr *ap = gcc_attr_wrapper(a); + p->n_ap = attr_add(p->n_ap, ap); + } + + p->n_sp = sp = lookup((char *)p->n_sp, 0); /* XXX */ + + if (fun_inline && ISFTN(p->n_type)) + sp->sflags |= SINLINE; + + if (!ISFTN(p->n_type)) { + if (assign) { + defid2(p, class, as); + sp = p->n_sp; + sp->sflags |= SASG; + if (sp->sflags & SDYNARRAY) + uerror("can't initialize dynamic arrays"); + lcommdel(sp); + } else + nidcl2(p, class, as); + } else { + extern P1ND *parlink; + if (assign) + uerror("cannot initialise function"); + defid2(p, uclass(class), as); + sp = p->n_sp; + if (sp->sdf->dfun == 0 && !issyshdr) + warner(Wstrict_prototypes); + if (parlink) { + /* dynamic sized arrays in prototypes */ + p1tfree(parlink); /* Free delayed tree */ + parlink = NULL; + } + } + p1tfree(p); + if (issyshdr) + sp->sflags |= SINSYS; /* declared in system header */ + return sp; +} + +/* + * Declare old-stype function arguments. + */ +static void +oldargs(P1ND *p) +{ + blevel++; + p->n_op = TYPE; + p->n_type = FARG; + p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */ + defid(p, PARAM); + blevel--; +} + +/* + * Set NAME nodes to a null name and index of LB nodes to NOOFFSET + * unless clr is one, in that case preserve variable name. + */ +static P1ND * +namekill(P1ND *p, int clr) +{ + P1ND *q; + int o = p->n_op; + + switch (coptype(o)) { + case LTYPE: + if (o == NAME) { + if (clr) + p->n_sp = NULL; + else + p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */ + } + break; + + case UTYPE: + p->n_left = namekill(p->n_left, clr); + break; + + case BITYPE: + p->n_left = namekill(p->n_left, clr); + if (o == LB) { + if (clr) { + p1tfree(p->n_right); + p->n_right = bcon(NOOFFSET); + } else + p->n_right = eve(p->n_right); + } else if (o == CALL) + p->n_right = namekill(p->n_right, 1); + else + p->n_right = namekill(p->n_right, clr); + if (o == TYMERGE) { + q = tymerge(p->n_left, p->n_right); + q->n_ap = attr_add(q->n_ap, p->n_ap); + p1tfree(p->n_left); + p1nfree(p); + p = q; + } + break; + } + return p; +} + +/* + * Declare function arguments. + */ +static P1ND * +funargs(P1ND *p) +{ + extern P1ND *arrstk[10]; + + if (p->n_op == ELLIPSIS) + return p; + + p = namekill(p, 0); + if (ISFTN(p->n_type)) + p->n_type = INCREF(p->n_type); + if (ISARY(p->n_type)) { + p->n_type += (PTR-ARY); + if (p->n_df->ddim == -1) + p1tfree(arrstk[0]), arrstk[0] = NULL; + p->n_df++; + } + if (p->n_type == VOID && p->n_sp->sname == NULL) + return p; /* sanitycheck later */ + else if (p->n_sp->sname == NULL) + uerror("argument missing"); + else + defid(p, PARAM); + return p; +} + +static P1ND * +listfw(P1ND *p, P1ND * (*f)(P1ND *)) +{ + if (p->n_op == CM) { + p->n_left = listfw(p->n_left, f); + p->n_right = (*f)(p->n_right); + } else + p = (*f)(p); + return p; +} + + +/* + * Declare a function. + */ +static void +fundef(P1ND *tp, P1ND *p) +{ + extern int prolab; + struct symtab *s; + P1ND *q, *typ; + int class = glval(tp), oclass, ctval; + + /* + * We discard all names except for those needed for + * parameter declaration. While doing that, also change + * non-constant array sizes to unknown. + */ + ctval = tvaloff; + for (q = p; coptype(q->n_op) != LTYPE && + q->n_left->n_op != NAME; q = q->n_left) { + if (q->n_op == CALL) + q->n_right = namekill(q->n_right, 1); + } + if (q->n_op != CALL && q->n_op != UCALL) { + uerror("invalid function definition"); + p = bdty(UCALL, p); + } else if (q->n_op == CALL) { + blevel = 1; + argoff = ARGINIT; + if (oldstyle == 0) + q->n_right = listfw(q->n_right, funargs); + ftnarg(q); + blevel = 0; + } + + p = typ = tymerge(tp, p); +#ifdef GCC_COMPAT + /* gcc seems to discard __builtin_ when declaring functions */ + if (strncmp("__builtin_", (char *)typ->n_sp, 10) == 0) + typ->n_sp = (struct symtab *)((char *)typ->n_sp + 10); +#endif + s = typ->n_sp = lookup((char *)typ->n_sp, 0); /* XXX */ + + oclass = s->sclass; + if (class == STATIC && oclass == EXTERN) + werror("%s was first declared extern, then static", s->sname); + + if (fun_inline) { + /* special syntax for inline functions */ + if (! strcmp(s->sname,"main")) + uerror("cannot inline main()"); + + s->sflags |= SINLINE; + inline_start(s, class); + if (class == EXTERN) + class = EXTDEF; + } else if (class == EXTERN) + class = SNULL; /* same result */ + + cftnsp = s; + defid(p, class); + if (s->sdf->dfun == 0 && !issyshdr) + warner(Wstrict_prototypes); +#ifdef GCC_COMPAT + if (attr_find(p->n_ap, GCC_ATYP_ALW_INL)) { + /* Temporary turn on temps to make always_inline work */ + alwinl = 1; + if (xtemps == 0) alwinl |= 2; + xtemps = 1; + } +#endif + prolab = getlab(); + send_passt(IP_PROLOG, -1, getexname(cftnsp), cftnsp->stype, + cftnsp->sclass == EXTDEF, prolab, ctval); + blevel++; +#ifdef STABS + if (gflag) + stabs_func(s); +#endif + p1tfree(tp); + p1tfree(p); + +} + +static void +fend(void) +{ + if (blevel) + cerror("function level error"); + ftnend(); + fun_inline = 0; + if (alwinl & 2) xtemps = 0; + alwinl = 0; + cftnsp = NULL; +} + +P1ND * +structref(P1ND *p, int f, char *name) +{ + P1ND *r; + + if (f == DOT) + p = buildtree(ADDROF, p, NULL); + r = biop(NAME, NULL, NULL); + r->n_name = name; + r = buildtree(STREF, p, r); + return r; +} + +static void +olddecl(P1ND *p, P1ND *a) +{ + struct symtab *s; + + p = namekill(p, 0); + s = p->n_sp; + if (s->slevel != 1 || s->stype == UNDEF) + uerror("parameter '%s' not defined", s->sname); + else if (s->stype != FARG) + uerror("parameter '%s' redefined", s->sname); + + s->stype = p->n_type; + s->sdf = p->n_df; + s->sap = p->n_ap; + if (ISARY(s->stype)) { + s->stype += (PTR-ARY); + s->sdf++; + } else if (s->stype == FLOAT) + s->stype = DOUBLE; + if (a) + attr_add(s->sap, gcc_attr_wrapper(a)); + p1nfree(p); +} + +void +branch(int lbl) +{ + int r = reached++; + ecomp(biop(GOTO, bcon(lbl), NULL)); + reached = r; +} + +/* + * Create a printable string based on an encoded string. + */ +static char * +mkpstr(char *str) +{ + char *os, *s; + int l = strlen(str) + 3; /* \t + \n + \0 */ + + os = s = stmtalloc(l); + *s++ = '\t'; + while (*str) { + if (*str == '\\') + *s++ = esccon(&str); + else + *s++ = *str++; + } + *s++ = '\n'; + *s = 0; + + return os; +} + +/* + * Fake a symtab entry for compound literals. + */ +static struct symtab * +clbrace(P1ND *p) +{ + struct symtab *sp; + + sp = getsymtab(simname("cl"), STEMP); + sp->stype = p->n_type; + sp->squal = p->n_qual; + sp->sdf = p->n_df; + sp->sap = p->n_ap; + p1tfree(p); + if (blevel == 0 && xnf != NULL) { + sp->sclass = STATIC; + sp->slevel = 2; + sp->soffset = getlab(); + } else { + sp->sclass = blevel ? AUTO : STATIC; + if (!ISARY(sp->stype) || sp->sdf->ddim != NOOFFSET) { + sp->soffset = NOOFFSET; + oalloc(sp, &autooff); + } + } + beginit(sp); + return sp; +} + +char * +simname(char *s) +{ + int len = strlen(s) + 10 + 1; + char *w = tmpalloc(len); /* uncommon */ + + snprintf(w, len, "%s%d", s, getlab()); + return w; +} + +P1ND * +biop(int op, P1ND *l, P1ND *r) +{ + return block(op, l, r, INT, 0, 0); +} + +static P1ND * +cmop(P1ND *l, P1ND *r) +{ + return biop(CM, l, r); +} + +static P1ND * +voidcon(void) +{ + return block(ICON, NULL, NULL, STRTY, 0, 0); +} + +/* Support for extended assembler a' la' gcc style follows below */ + +static P1ND * +xmrg(P1ND *out, P1ND *in) +{ + P1ND *p = in; + + if (p->n_op == XARG) { + in = cmop(out, p); + } else { + while (p->n_left->n_op == CM) + p = p->n_left; + p->n_left = cmop(out, p->n_left); + } + return in; +} + +/* + * Put together in and out node lists in one list, and balance it with + * the constraints on the right side of a CM node. + */ +static P1ND * +xcmop(P1ND *out, P1ND *in, P1ND *str) +{ + P1ND *p, *q; + + if (out) { + /* D out-list sanity check */ + for (p = out; p->n_op == CM; p = p->n_left) { + q = p->n_right; + if (q->n_name[0] != '=' && q->n_name[0] != '+') + uerror("output missing ="); + } + if (p->n_name[0] != '=' && p->n_name[0] != '+') + uerror("output missing ="); + if (in == NULL) + p = out; + else + p = xmrg(out, in); + } else if (in) { + p = in; + } else + p = voidcon(); + + if (str == NULL) + str = voidcon(); + return cmop(p, str); +} + +/* + * Generate a XARG node based on a string and an expression. + */ +static P1ND * +xasmop(char *str, P1ND *p) +{ + + p = biop(XARG, p, NULL); + p->n_name = str; + return p; +} + +/* + * Generate a XASM node based on a string and an expression. + */ +static void +mkxasm(char *str, P1ND *p) +{ + P1ND *q; + + q = biop(XASM, p->n_left, p->n_right); + q->n_name = str; + p1nfree(p); + ecomp(optloop(q)); +} + +static struct attr * +gcc_attr_wrapper(P1ND *p) +{ +#ifdef GCC_COMPAT + return gcc_attr_parse(p); +#else + if (p != NULL) + uerror("gcc attribute used"); + return NULL; +#endif +} + +#ifdef GCC_COMPAT +static P1ND * +tyof(P1ND *p) +{ + static struct symtab spp; + P1ND *q = block(TYPE, NULL, NULL, p->n_type, p->n_df, p->n_ap); + q->n_qual = p->n_qual; + q->n_sp = &spp; /* for typenode */ + p1walkf(p, putjops, 0); + p1tfree(p); + return q; +} + +#else +static P1ND * +tyof(P1ND *p) +{ + uerror("typeof gcc extension"); + return bcon(0); +} +#endif + +/* + * Traverse an unhandled expression tree bottom-up and call buildtree() + * or equivalent as needed. + */ +P1ND * +eve(P1ND *p) +{ + struct symtab *sp; + P1ND *r, *p1, *p2; + int x; + + p1 = p->n_left; + p2 = p->n_right; + switch (p->n_op) { + case NAME: + sp = lookup((char *)p->n_sp, + attr_find(p->n_ap, ATTR_P1LABELS) ? SLBLNAME|STEMP : 0); + if (sp->sflags & SINLINE) + inline_ref(sp); + r = nametree(sp); + if (sp->sflags & SDYNARRAY) + r = buildtree(UMUL, r, NULL); +#ifdef GCC_COMPAT + if (attr_find(sp->sap, GCC_ATYP_DEPRECATED)) + warner(Wdeprecated_declarations, sp->sname); +#endif + break; + + case DOT: + case STREF: + r = structref(eve(p1), p->n_op, (char *)p2->n_sp); + p1nfree(p2); + break; + + case CAST: + p2 = eve(p2); +#ifndef NO_COMPLEX + if (ANYCX(p1) || ANYCX(p2)) { + r = cxcast(p1, p2); + break; + } +#endif +#ifdef TARGET_TIMODE + if ((r = gcc_eval_ticast(CAST, p1, p2)) != NULL) + break; +#endif + p1 = buildtree(CAST, p1, p2); + p1nfree(p1->n_left); + r = p1->n_right; + p1nfree(p1); + break; + + + case SZOF: + x = xinline; xinline = 0; /* XXX hack */ + if (glval(p2) == 0) + p1 = eve(p1); + else + TYMFIX(p1); + p1nfree(p2); + r = doszof(p1); + xinline = x; + break; + + case LB: + p1 = eve(p1); + p2 = eve(p2); +#ifdef TARGET_TIMODE + if (isti(p2)) { + P1ND *s = block(NAME, NULL, NULL, LONG, 0, 0); + if ((r = gcc_eval_ticast(CAST, s, p2)) != NULL) + p2 = r; + p1nfree(s); + } +#endif + r = buildtree(UMUL, buildtree(PLUS, p1, p2), NULL); + break; + + case COMPL: +#ifndef NO_COMPLEX + p1 = eve(p1); + if (ANYCX(p1)) + r = cxconj(p1); + else + r = buildtree(COMPL, p1, NULL); + break; +#endif + case UPLUS: + r = eve(p1); + if (r->n_op == FLD || r->n_type < INT) + r = buildtree(PLUS, r, bcon(0)); /* must be size int */ + break; + + case UMINUS: +#ifndef NO_COMPLEX + p1 = eve(p1); + if (ANYCX(p1)) + r = cxop(UMINUS, p1, p1); + else + r = buildtree(UMINUS, p1, NULL); + break; +#endif + case NOT: + case UMUL: + p1 = eve(p1); +#ifdef TARGET_TIMODE + if ((r = gcc_eval_tiuni(p->n_op, p1)) != NULL) + break; +#endif +#ifndef NO_COMPLEX + if (p->n_op == NOT && ANYCX(p1)) + p1 = cxop(NE, p1, bcon(0)); +#endif + r = buildtree(p->n_op, p1, NULL); + break; + + case ADDROF: + r = eve(p1); + if (ISFTN(p->n_type)/* || ISARY(p->n_type) */){ +#ifdef notdef + werror( "& before array or function: ignored" ); +#endif + } else + r = buildtree(ADDROF, r, NULL); + break; + + case UCALL: + p2 = NULL; + /* FALLTHROUGH */ + case CALL: + if (p1->n_op == NAME) { + sp = lookup((char *)p1->n_sp, 0); +#ifndef NO_C_BUILTINS + if (sp->sflags & SBUILTIN) { + p1nfree(p1); + r = builtin_check(sp, p2); + break; + } +#endif + if (sp->stype == UNDEF) { + p1->n_type = FTN|INT; + p1->n_sp = sp; + p1->n_ap = NULL; + defid(p1, EXTERN); + } + p1nfree(p1); +#ifdef GCC_COMPAT + if (attr_find(sp->sap, GCC_ATYP_DEPRECATED)) + warner(Wdeprecated_declarations, sp->sname); +#endif + if (p->n_op == CALL) + p2 = eve(p2); + r = doacall(sp, nametree(sp), p2); + } else { + if (p->n_op == CALL) + p2 = eve(p2); + r = doacall(NULL, eve(p1), p2); + } + break; + +#ifndef NO_COMPLEX + case XREAL: + case XIMAG: + p1 = eve(p1); + r = cxelem(p->n_op, p1); + break; +#endif + + case COLON: + case MUL: + case DIV: + case PLUS: + case MINUS: + case ASSIGN: + case EQ: + case NE: + case OROR: + case ANDAND: +#ifndef NO_COMPLEX + p1 = eve(p1); + p2 = eve(p2); +#ifdef TARGET_TIMODE + if ((r = gcc_eval_timode(p->n_op, p1, p2)) != NULL) + break; +#endif + if (ANYCX(p1) || ANYCX(p2)) { + r = cxop(p->n_op, p1, p2); + } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) { + r = imop(p->n_op, p1, p2); + } else + r = buildtree(p->n_op, p1, p2); + break; +#endif + case MOD: + case CM: + case GT: + case GE: + case LT: + case LE: + case RS: + case LS: + case RSEQ: + case LSEQ: + case AND: + case OR: + case ER: + case EREQ: + case OREQ: + case ANDEQ: + case QUEST: + p1 = eve(p1); + p2 = eve(p2); +#ifdef TARGET_TIMODE + if ((r = gcc_eval_timode(p->n_op, p1, p2)) != NULL) + break; +#endif + r = buildtree(p->n_op, p1, p2); + break; + + case BIQUEST: /* gcc e ?: e op */ + p1 = eve(p1); + r = tempnode(0, p1->n_type, p1->n_df, p1->n_ap); + p2 = eve(biop(COLON, p1tcopy(r), p2)); + r = buildtree(QUEST, buildtree(ASSIGN, r, p1), p2); + break; + + case INCR: + case DECR: + case MODEQ: + case MINUSEQ: + case PLUSEQ: + case MULEQ: + case DIVEQ: + p1 = eve(p1); + p2 = eve(p2); +#ifdef TARGET_TIMODE + if ((r = gcc_eval_timode(p->n_op, p1, p2)) != NULL) + break; +#endif +#ifndef NO_COMPLEX + if (ANYCX(p1) || ANYCX(p2)) { + r = cxop(UNASG p->n_op, p1tcopy(p1), p2); + r = cxop(ASSIGN, p1, r); + break; + } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) { + r = imop(UNASG p->n_op, p1tcopy(p1), p2); + r = cxop(ASSIGN, p1, r); + break; + } + /* FALLTHROUGH */ +#endif + r = buildtree(p->n_op, p1, p2); + break; + + case STRING: + r = strend(p->n_name, (TWORD)glval(p)); + break; + + case COMOP: + if (p1->n_op == GOTO) { + /* inside ({ }), eve already called */ + r = buildtree(p->n_op, p1, p2); + } else { + p1 = eve(p1); + r = buildtree(p->n_op, p1, eve(p2)); + } + break; + + case TYPE: + case ICON: + case FCON: + case TEMP: + return p; + + case CLOP: + r = nametree(p->n_sp); + break; + + default: +#ifdef PCC_DEBUG + p1fwalk(p, eprint, 0); +#endif + cerror("eve"); + r = NULL; + } + p1nfree(p); + return r; +} + +int +con_e(P1ND *p) +{ + return icons(optloop(eve(p))); +} + +void +uawarn(P1ND *p, char *s) +{ + if (p == 0) + return; + if (attrwarn) + werror("unhandled %s attribute", s); + p1tfree(p); +} + +static void +dainit(P1ND *d, P1ND *a) +{ + if (d == NULL) { + asginit(a); + } else if (d->n_op == CM) { + int is = con_e(d->n_left); + int ie = con_e(d->n_right); + int i; + + p1nfree(d); + if (ie < is) + uerror("negative initializer range"); + desinit(biop(LB, NULL, bcon(is))); + for (i = is; i < ie; i++) + asginit(p1tcopy(a)); + asginit(a); + } else { + cerror("dainit"); + } +} + +/* + * Traverse down and tymerge() where appropriate. + */ +static P1ND * +tymfix(P1ND *p) +{ + P1ND *q; + int o = coptype(p->n_op); + + switch (o) { + case LTYPE: + break; + case UTYPE: + p->n_left = tymfix(p->n_left); + break; + case BITYPE: + p->n_left = tymfix(p->n_left); + p->n_right = tymfix(p->n_right); + if (p->n_op == TYMERGE) { + q = tymerge(p->n_left, p->n_right); + q->n_ap = attr_add(q->n_ap, p->n_ap); + p1tfree(p->n_left); + p1nfree(p); + p = q; + } + break; + } + return p; +} + +static P1ND * +aryfix(P1ND *p) +{ + P1ND *q; + + for (q = p; q->n_op != NAME; q = q->n_left) { + if (q->n_op == LB) { + q->n_right = optloop(eve(q->n_right)); + if ((blevel == 0 || rpole != NULL) && + !nncon(q->n_right)) + uerror("array size not constant"); + /* + * Checks according to 6.7.5.2 clause 1: + * "...the expression shall have an integer type." + * "If the expression is a constant expression, + * it shall have a value greater than zero." + */ + if (!ISINTEGER(q->n_right->n_type)) + werror("array size is not an integer"); + else if (q->n_right->n_op == ICON && + glval(q->n_right) < 0 && + glval(q->n_right) != NOOFFSET) { + uerror("array size cannot be negative"); + slval(q->n_right, 1); + } + } else if (q->n_op == CALL) + q->n_right = namekill(q->n_right, 1); + } + return p; +} + +struct labs { + struct labs *next; + int lab; +} *labp; + +static void +savlab(int lab) +{ + struct labs *l = tmpalloc(sizeof(struct labs)); /* uncommon */ + l->lab = lab < 0 ? -lab : lab; + l->next = labp; + labp = l; +} + +int * +mkclabs(void) +{ + struct labs *l; + int i, *rv; + + for (i = 0, l = labp; l; l = l->next, i++) + ; + rv = tmpalloc((i+1)*sizeof(int)); /* uncommon */ + for (i = 0, l = labp; l; l = l->next, i++) + rv[i] = l->lab; + rv[i] = 0; + labp = 0; + return rv; +} + +void +xcbranch(P1ND *p, int lab) +{ +#ifndef NO_COMPLEX + if (ANYCX(p)) + p = cxop(NE, p, bcon(0)); +#endif + cbranch(buildtree(NOT, p, NULL), bcon(lab)); +} + +/* + * New a case entry to genlist. + * tn is type, e is expression. + */ +static struct genlist * +newgen(P1ND *tn, P1ND *e) +{ + struct genlist *ng; + TWORD t; + + if (tn) { + t = tn->n_type; + p1tfree(tn); + } else + t = 0; + + /* add new entry */ + ng = malloc(sizeof(struct genlist)); + ng->next = NULL; + ng->t = t; + ng->p = e; + return ng; +} + +/* + * Add a case entry to genlist. + * g is list, ng is new entry. + */ +static struct genlist * +addgen(struct genlist *g, struct genlist *ng) +{ + struct genlist *w; + + /* search for duplicate type */ + for (w = g; w; w = w->next) { + if (w->t == ng->t) + uerror("duplicate type in _Generic"); + } + ng->next = g; + return ng; +} + +static P1ND * +dogen(struct genlist *g, P1ND *e) +{ + struct genlist *ng; + P1ND *w, *p; + + e = eve(e); + + /* search for direct match */ + for (ng = g, w = p = NULL; ng; ng = ng->next) { + if (ng->t == 0) + p = ng->p; /* save default */ + if (e->n_type == ng->t) + w = ng->p; + } + + /* if no match, use generic */ + if (w == NULL) { + if (p == NULL) { + uerror("_Generic: no default found"); + p = bcon(0); + } + w = p; + } + + /* free tree */ + while (g) { + if (g->p != w) + p1tfree(g->p); + ng = g->next; + free(g); + g = ng; + } + + p1tfree(e); + return w; +} diff --git a/lang/pcc/pcc/cc/ccom/dwarf.c b/lang/pcc/pcc/cc/ccom/dwarf.c new file mode 100644 index 000000000..faa5aad07 --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/dwarf.c @@ -0,0 +1,259 @@ +/* $Id: dwarf.c,v 1.2 2016/03/08 18:17:45 ragge Exp $ */ + +/* + * Copyright (c) 2016 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Expect just ELF for now. + */ +#include "pass1.h" + +#ifdef DWARF + +#include +#include + +#include "dwarf.h" + +/* + * Basic DWARF definitions, from specification. + */ +#define DVERSION 3 /* dwarf version */ +#define DLABEL ".LD%d" + +#define DW64 (SZPOINT(VOID)/SZCHAR == 8) + +static int dwseg = -1; +enum { DINFO, DABBREV, DSTR }; +static char *segn[] = { ".debug_info", ".debug_abbrev", ".debug_str" }; + +static int debug_info_sz, debug_info_sz_lbl; +static int debug_abbrev_beg_lbl; + +static int dwcfl, dwbtext, dwetext; + +static char *dwname; + +static int +dwlab(void) +{ + static int dwlbl; + return dwlbl++; +} + +static void +dwarfseg(int seg) +{ + if (seg == dwseg) + return; + /* XXX target code? */ + printf("\t.section\t%s,\"\",@progbits\n", segn[seg]); + lastloc = NOSEG; + dwseg = seg; +} + +static void +dwslab(int seg, int lbl) +{ + dwarfseg(seg); + printf(PRTPREF DLABEL ":\n", lbl); +} + +static void +p1b(int v) +{ + printf(PRTPREF "%s 0x%x\n", astypnames[CHAR], v); +} + +static void +p2w(int v) +{ + printf(PRTPREF "%s 0x%x\n", astypnames[SHORT], v); +} + +static int +leb128(int d) +{ + if (d > 127) + cerror("FIXME: leb128 > 127"); + p1b(d); + return 1; +} + +static void +al128(int d) +{ + dwarfseg(DABBREV); + leb128(d); +} + +static void +apair(int d, int e) +{ + dwarfseg(DABBREV); + leb128(d); + leb128(e); +} + +static void +strng(char *s) +{ + printf(PRTPREF "\t.ascii \"%s\\0\"\n", s); /* XXX common code? */ +} + +static void +istring(char *str) +{ + dwarfseg(DINFO); + strng(str); + debug_info_sz += (strlen(str) + 1); +} + +static void +dwslabstr(int lbl, char *s) +{ + dwslab(DSTR, lbl); + strng(s); +} + +static void +ilbl(int l) +{ + dwarfseg(DINFO); + printf(PRTPREF "%s " DLABEL "\n", astypnames[LONG], l); + debug_info_sz += (DW64 * 4 + 4); +} + +static void +il128(int d) +{ + dwarfseg(DINFO); + debug_info_sz += leb128(d); +} + +static void +p412l(int lbl) +{ + if (DW64) + printf(PRTPREF "%s 0xffffff00\n", astypnames[INT]); + printf(PRTPREF "%s " DLABEL "\n", astypnames[LONG], lbl); +} + +static void +info1b(int v) +{ + dwarfseg(DINFO); + p1b(v); + debug_info_sz++; +} + +static void +info2w(int v) +{ + dwarfseg(DINFO); + p2w(v); + debug_info_sz += 2; +} + +static void +info412l(int lbl) +{ + dwarfseg(DINFO); + p412l(lbl); + debug_info_sz += (DW64 * 8 + 4); +} + +void +dwarf_init(char *iname) +{ + char buf[MAXPATHLEN]; + /* + * Setup sections. + * We'll print out the basic stuff early so that not + * so much context must be kept around. + */ + dwname = iname; + debug_info_sz_lbl = dwlab(); + debug_abbrev_beg_lbl = dwlab(); + + /* begin with setting up the compilation unit header */ + info412l(debug_info_sz_lbl); debug_info_sz = 0; + info2w(DVERSION); + info412l(debug_abbrev_beg_lbl); + info1b(SZPOINT(VOID)/SZCHAR); + + /* Define abbrev table */ + dwslab(DABBREV, debug_abbrev_beg_lbl); + + /* compile unit follows, both in abbrev and info table */ + /* Recommended stuff here as in the documentation */ + al128(1); /* always first entry */ + al128(DW_TAG_compile_unit); + al128(DW_CHILDREN_yes); + + apair(DW_AT_name, DW_FORM_strp); /* file name; e.g. foo.c */ + apair(DW_AT_producer, DW_FORM_string); /* producer; PCC 1.2.3 */ + apair(DW_AT_comp_dir, DW_FORM_string); /* working directory */ + apair(DW_AT_language, DW_FORM_data1); /* C99 */ + apair(DW_AT_low_pc, DW_FORM_addr); /* start text */ + apair(DW_AT_high_pc, DW_FORM_addr); /* end text */ + apair(0, 0); + + /* Above in info table */ + il128(1); /* first entry */ + ilbl(dwcfl = dwlab()); + istring(PACKAGE_STRING); + istring(getcwd(buf, MAXPATHLEN)); + il128(DW_LANG_C99); + ilbl(dwbtext = dwlab()); + ilbl(dwetext = dwlab()); + + locctr(PROG, NULL); + printf(PRTPREF DLABEL ":\n", dwbtext); +} + +void +dwarf_file(char *fn) +{ + /* if first file name, print out as initial and remember */ + if (dwcfl) { + dwslabstr(dwcfl, fn); + dwcfl = 0; + } + /* XXX add more here */ +} + +void +dwarf_end() +{ + locctr(PROG, NULL); + printf(PRTPREF DLABEL ":\n", dwetext); + if (dwcfl) + dwslabstr(dwcfl, dwname ? dwname : ""); + printf(PRTPREF "\t.set " DLABEL ",%d\n", + debug_info_sz_lbl, debug_info_sz); +} + +#endif diff --git a/lang/pcc/pcc/cc/ccom/dwarf.h b/lang/pcc/pcc/cc/ccom/dwarf.h new file mode 100644 index 000000000..a796b5c68 --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/dwarf.h @@ -0,0 +1,196 @@ + +#define DW_TAG_array_type 0x01 +#define DW_TAG_class_type 0x02 +#define DW_TAG_entry_point 0x03 +#define DW_TAG_enumeration_type 0x04 +#define DW_TAG_formal_parameter 0x05 +#define DW_TAG_imported_declaration 0x08 +#define DW_TAG_label 0x0a +#define DW_TAG_lexical_block 0x0b +#define DW_TAG_member 0x0d +#define DW_TAG_pointer_type 0x0f +#define DW_TAG_reference_type 0x10 +#define DW_TAG_compile_unit 0x11 +#define DW_TAG_string_type 0x12 +#define DW_TAG_structure_type 0x13 +#define DW_TAG_subroutine_type 0x15 +#define DW_TAG_typedef 0x16 +#define DW_TAG_union_type 0x17 +#define DW_TAG_unspecified_parameters 0x18 +#define DW_TAG_variant 0x19 +#define DW_TAG_common_block 0x1a +#define DW_TAG_common_inclusion 0x1b +#define DW_TAG_inheritance 0x1c +#define DW_TAG_inlined_subroutine 0x1d +#define DW_TAG_module 0x1e +#define DW_TAG_ptr_to_member_type 0x1f +#define DW_TAG_set_type 0x20 +#define DW_TAG_subrange_type 0x21 +#define DW_TAG_with_stmt 0x22 +#define DW_TAG_access_declaration 0x23 +#define DW_TAG_base_type 0x24 +#define DW_TAG_catch_block 0x25 +#define DW_TAG_const_type 0x26 +#define DW_TAG_constant 0x27 +#define DW_TAG_enumerator 0x28 +#define DW_TAG_file_type 0x29 +#define DW_TAG_friend 0x2a +#define DW_TAG_namelist 0x2b +#define DW_TAG_namelist_item 0x2c +#define DW_TAG_packed_type 0x2d +#define DW_TAG_subprogram 0x2e +#define DW_TAG_template_type_parameter 0x2f +#define DW_TAG_template_value_parameter 0x30 +#define DW_TAG_thrown_type 0x31 +#define DW_TAG_try_block 0x32 +#define DW_TAG_variant_part 0x33 +#define DW_TAG_variable 0x34 +#define DW_TAG_volatile_type 0x35 +#define DW_TAG_dwarf_procedure 0x36 +#define DW_TAG_restrict_type 0x37 +#define DW_TAG_interface_type 0x38 +#define DW_TAG_namespace 0x39 +#define DW_TAG_imported_module 0x3a +#define DW_TAG_unspecified_type 0x3b +#define DW_TAG_partial_unit 0x3c +#define DW_TAG_imported_unit 0x3d +#define DW_TAG_condition 0x3f +#define DW_TAG_shared_type 0x40 +#define DW_TAG_lo_user 0x4080 +#define DW_TAG_hi_user 0xffff + +#define DW_CHILDREN_no 0 +#define DW_CHILDREN_yes 1 + +#define DW_AT_sibling 0x01 /* reference */ +#define DW_AT_location 0x02 /* block, loclistptr */ +#define DW_AT_name 0x03 /* string */ +#define DW_AT_ordering 0x09 /* constant */ +#define DW_AT_byte_size 0x0b /* block, constant, reference */ +#define DW_AT_bit_offset 0x0c /* block, constant, reference */ +#define DW_AT_bit_size 0x0d /* block, constant, reference */ +#define DW_AT_stmt_list 0x10 +#define DW_AT_low_pc 0x11 +#define DW_AT_high_pc 0x12 +#define DW_AT_language 0x13 +#define DW_AT_discr 0x15 +#define DW_AT_discr_value 0x16 +#define DW_AT_visibility 0x17 +#define DW_AT_import 0x18 +#define DW_AT_string_length 0x19 +#define DW_AT_common_reference 0x1a +#define DW_AT_comp_dir 0x1b +#define DW_AT_const_value 0x1c +#define DW_AT_containing_type 0x1d +#define DW_AT_default_value 0x1e +#define DW_AT_inline 0x20 +#define DW_AT_is_optional 0x21 +#define DW_AT_lower_bound 0x22 +#define DW_AT_producer 0x25 +#define DW_AT_prototyped 0x27 +#define DW_AT_return_addr 0x2a +#define DW_AT_start_scope 0x2c +#define DW_AT_bit_stride 0x2e +#define DW_AT_upper_bound 0x2f +#define DW_AT_abstract_origin 0x31 +#define DW_AT_accessibility 0x32 +#define DW_AT_address_class 0x33 +#define DW_AT_artificial 0x34 +#define DW_AT_base_types 0x35 +#define DW_AT_calling_convention 0x36 +#define DW_AT_count 0x37 +#define DW_AT_data_member_location 0x38 +#define DW_AT_decl_column 0x39 +#define DW_AT_decl_file 0x3a +#define DW_AT_decl_line 0x3b +#define DW_AT_declaration 0x3c +#define DW_AT_discr_list 0x3d +#define DW_AT_encoding 0x3e +#define DW_AT_external 0x3f +#define DW_AT_frame_base 0x40 +#define DW_AT_friend 0x41 +#define DW_AT_identifier_case 0x42 +#define DW_AT_macro_info 0x43 +#define DW_AT_namelist_item 0x44 +#define DW_AT_priority 0x45 +#define DW_AT_segment 0x46 +#define DW_AT_specification 0x47 +#define DW_AT_static_link 0x48 +#define DW_AT_type 0x49 +#define DW_AT_use_location 0x4a +#define DW_AT_variable_parameter 0x4b +#define DW_AT_virtuality 0x4c +#define DW_AT_vtable_elem_location 0x4d +#define DW_AT_allocated 0x4e +#define DW_AT_associated 0x4f +#define DW_AT_data_location 0x50 +#define DW_AT_byte_stride 0x51 +#define DW_AT_entry_pc 0x52 +#define DW_AT_use_UTF8 0x53 +#define DW_AT_extension 0x54 +#define DW_AT_ranges 0x55 +#define DW_AT_trampoline 0x56 +#define DW_AT_call_column 0x57 +#define DW_AT_call_file 0x58 +#define DW_AT_call_line 0x59 +#define DW_AT_description 0x5a +#define DW_AT_binary_scale 0x5b +#define DW_AT_decimal_scale 0x5c +#define DW_AT_small 0x5d +#define DW_AT_decimal_sign 0x5e +#define DW_AT_digit_count 0x5f +#define DW_AT_picture_string 0x60 +#define DW_AT_mutable 0x61 +#define DW_AT_threads_scaled 0x62 +#define DW_AT_explicit 0x63 +#define DW_AT_object_pointer 0x64 +#define DW_AT_endianity 0x65 +#define DW_AT_elemental 0x66 +#define DW_AT_pure 0x67 +#define DW_AT_recursive 0x68 /* flag */ +#define DW_AT_lo_user 0x2000 +#define DW_AT_hi_user 0x3fff + +#define DW_FORM_addr 0x01 +#define DW_FORM_block2 0x03 +#define DW_FORM_block4 0x04 +#define DW_FORM_data2 0x05 /* constant */ +#define DW_FORM_data4 0x06 /* constant, lineptr, loclistptr... */ +#define DW_FORM_data8 0x07 +#define DW_FORM_string 0x08 +#define DW_FORM_block 0x09 +#define DW_FORM_block1 0x0a +#define DW_FORM_data1 0x0b /* constant */ +#define DW_FORM_flag 0x0c +#define DW_FORM_sdata 0x0d /* constant */ +#define DW_FORM_strp 0x0e +#define DW_FORM_udata 0x0f +#define DW_FORM_ref_addr 0x10 +#define DW_FORM_ref1 0x11 +#define DW_FORM_ref2 0x12 +#define DW_FORM_ref4 0x13 +#define DW_FORM_ref8 0x14 +#define DW_FORM_ref_udata 0x15 +#define DW_FORM_indirect 0x16 + +#define DW_LANG_C89 0x01 +#define DW_LANG_C 0x02 +#define DW_LANG_Ada83 0x03 +#define DW_LANG_C_plus_plus 0x04 +#define DW_LANG_Cobol74 0x05 +#define DW_LANG_Cobol85 0x06 +#define DW_LANG_Fortran77 0x07 +#define DW_LANG_Fortran90 0x08 +#define DW_LANG_Pascal83 0x09 +#define DW_LANG_Modula2 0x0a +#define DW_LANG_Java 0x0b +#define DW_LANG_C99 0x0c +#define DW_LANG_Ada95 0x0d +#define DW_LANG_Fortran95 0x0e +#define DW_LANG_PLI 0x0f +#define DW_LANG_ObjC 0x10 +#define DW_LANG_ObjC_plus_plus 0x11 +#define DW_LANG_UPC 0x12 +#define DW_LANG_D 0x13 +#define DW_LANG_lo_user 0x8000 +#define DW_LANG_hi_user 0xffff diff --git a/lang/pcc/pcc/cc/ccom/gcc_compat.c b/lang/pcc/pcc/cc/ccom/gcc_compat.c new file mode 100644 index 000000000..374dad4c3 --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/gcc_compat.c @@ -0,0 +1,1088 @@ +/* $Id: gcc_compat.c,v 1.119 2015/11/13 17:11:40 ragge Exp $ */ +/* + * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Routines to support some of the gcc extensions to C. + */ +#ifdef GCC_COMPAT + +#include "pass1.h" +#include "cgram.h" + +#include + +#define NODE P1ND +#define nfree p1nfree +#define tfree p1tfree + +static struct kw { + char *name, *ptr; + int rv; +} kw[] = { +/* + * Do NOT change the order of these entries unless you know + * what you're doing! + */ +/* 0 */ { "__asm", NULL, C_ASM }, +/* 1 */ { "__signed", NULL, 0 }, +/* 2 */ { "__inline", NULL, 0 }, +/* 3 */ { "__const", NULL, 0 }, +/* 4 */ { "__asm__", NULL, C_ASM }, +/* 5 */ { "__inline__", NULL, 0 }, +/* 6 */ { "__thread", NULL, 0 }, +/* 7 */ { "__FUNCTION__", NULL, 0 }, +/* 8 */ { "__volatile", NULL, 0 }, +/* 9 */ { "__volatile__", NULL, 0 }, +/* 10 */{ "__restrict", NULL, -1 }, +/* 11 */{ "__typeof__", NULL, C_TYPEOF }, +/* 12 */{ "typeof", NULL, C_TYPEOF }, +/* 13 */{ "__extension__", NULL, -1 }, +/* 14 */{ "__signed__", NULL, 0 }, +/* 15 */{ "__attribute__", NULL, 0 }, +/* 16 */{ "__attribute", NULL, 0 }, +/* 17 */{ "__real__", NULL, 0 }, +/* 18 */{ "__imag__", NULL, 0 }, +/* 19 */{ "__builtin_offsetof", NULL, PCC_OFFSETOF }, +/* 20 */{ "__PRETTY_FUNCTION__", NULL, 0 }, +/* 21 */{ "__alignof__", NULL, C_ALIGNOF }, +/* 22 */{ "__typeof", NULL, C_TYPEOF }, +/* 23 */{ "__alignof", NULL, C_ALIGNOF }, +/* 24 */{ "__restrict__", NULL, -1 }, + { NULL, NULL, 0 }, +}; + +/* g77 stuff */ +#if SZFLOAT == SZLONG +#define G77_INTEGER LONG +#define G77_UINTEGER ULONG +#elif SZFLOAT == SZINT +#define G77_INTEGER INT +#define G77_UINTEGER UNSIGNED +#else +#error fix g77 stuff +#endif +#if SZFLOAT*2 == SZLONG +#define G77_LONGINT LONG +#define G77_ULONGINT ULONG +#elif SZFLOAT*2 == SZLONGLONG +#define G77_LONGINT LONGLONG +#define G77_ULONGINT ULONGLONG +#else +#error fix g77 long stuff +#endif + +static TWORD g77t[] = { G77_INTEGER, G77_UINTEGER, G77_LONGINT, G77_ULONGINT }; +static char *g77n[] = { "__g77_integer", "__g77_uinteger", + "__g77_longint", "__g77_ulongint" }; + +#ifdef TARGET_TIMODE +static char *loti, *hiti, *TISTR; +static struct symtab *tisp, *ucmpti2sp, *cmpti2sp, *subvti3sp, + *addvti3sp, *mulvti3sp, *divti3sp, *udivti3sp, *modti3sp, *umodti3sp, + *ashldi3sp, *ashrdi3sp, *lshrdi3sp, *floatuntixfsp; + +static struct symtab * +addftn(char *n, TWORD t) +{ + NODE *p = block(TYPE, 0, 0, 0, 0, 0); + struct symtab *sp; + + sp = lookup(addname(n), 0); + p->n_type = INCREF(t) + (FTN-PTR); + p->n_sp = sp; + p->n_df = memset(permalloc(sizeof(union dimfun)), 0, + sizeof(union dimfun)); + defid(p, EXTERN); + nfree(p); + return sp; +} + +static struct symtab * +addstr(char *n) +{ + NODE *p = block(NAME, NIL, NIL, FLOAT, 0, 0); + struct symtab *sp; + NODE *q; + struct attr *ap; + struct rstack *rp; + extern struct rstack *rpole; + + p->n_type = ctype(ULONGLONG); + rpole = rp = bstruct(NULL, STNAME, NULL); + soumemb(p, loti, 0); + soumemb(p, hiti, 0); + q = dclstruct(rp); + sp = q->n_sp = lookup(addname(n), 0); + defid(q, TYPEDEF); + ap = attr_new(GCC_ATYP_MODE, 3); + ap->sarg(0) = addname("TI"); + ap->iarg(1) = 0; + sp->sap = attr_add(sp->sap, ap); + nfree(q); + nfree(p); + + return sp; +} +#endif + +void +gcc_init(void) +{ + struct kw *kwp; + NODE *p; + TWORD t; + int i, d_debug; + + d_debug = ddebug; + ddebug = 0; + for (kwp = kw; kwp->name; kwp++) + kwp->ptr = addname(kwp->name); + + for (i = 0; i < 4; i++) { + struct symtab *sp; + t = ctype(g77t[i]); + p = block(NAME, NIL, NIL, t, NULL, 0); + sp = lookup(addname(g77n[i]), 0); + p->n_sp = sp; + defid(p, TYPEDEF); + nfree(p); + } + ddebug = d_debug; +#ifdef TARGET_TIMODE + { + struct attr *ap; + + loti = addname("__loti"); + hiti = addname("__hiti"); + TISTR = addname("TI"); + + tisp = addstr("0ti"); + + cmpti2sp = addftn("__cmpti2", INT); + ucmpti2sp = addftn("__ucmpti2", INT); + + addvti3sp = addftn("__addvti3", STRTY); + addvti3sp->sap = tisp->sap; + subvti3sp = addftn("__subvti3", STRTY); + subvti3sp->sap = tisp->sap; + mulvti3sp = addftn("__mulvti3", STRTY); + mulvti3sp->sap = tisp->sap; + divti3sp = addftn("__divti3", STRTY); + divti3sp->sap = tisp->sap; + modti3sp = addftn("__modti3", STRTY); + modti3sp->sap = tisp->sap; + + ap = attr_new(GCC_ATYP_MODE, 3); + ap->sarg(0) = TISTR; + ap->iarg(1) = 1; + ap = attr_add(tisp->sap, ap); + udivti3sp = addftn("__udivti3", STRTY); + udivti3sp->sap = ap; + umodti3sp = addftn("__umodti3", STRTY); + umodti3sp->sap = ap; + ashldi3sp = addftn("__ashldi3", ctype(LONGLONG)); + ashldi3sp->sap = ap; + ashrdi3sp = addftn("__ashrdi3", ctype(LONGLONG)); + ashrdi3sp->sap = ap; + lshrdi3sp = addftn("__lshrdi3", ctype(LONGLONG)); + lshrdi3sp->sap = ap; + + floatuntixfsp = addftn("__floatuntixf", LDOUBLE); + } +#endif +} + +#define TS "\n#pragma tls\n# %d\n" +#define TLLEN sizeof(TS)+10 +/* + * See if a string matches a gcc keyword. + */ +int +gcc_keyword(char *str) +{ + extern int inattr, parlvl, parbal; + char tlbuf[TLLEN], *tw; + struct kw *kwp; + int i; + + /* XXX hack, should pass everything in expressions */ + if (str == kw[21].ptr) + return kw[21].rv; + + if (inattr) + return 0; + + for (i = 0, kwp = kw; kwp->name; kwp++, i++) + if (str == kwp->ptr) + break; + if (kwp->name == NULL) + return 0; + if (kwp->rv) + return kwp->rv; + switch (i) { + case 1: /* __signed */ + case 14: /* __signed__ */ + yylval.type = SIGNED; + return C_TYPE; + case 2: /* __inline */ + case 5: /* __inline__ */ + yylval.type = INLINE; + return C_FUNSPEC; + case 3: /* __const */ + yylval.type = CON; + return C_QUALIFIER; + case 6: /* __thread */ + snprintf(tlbuf, TLLEN, TS, lineno); + tw = &tlbuf[strlen(tlbuf)]; + while (tw > tlbuf) + cunput(*--tw); + return -1; + case 7: /* __FUNCTION__ */ + case 20: /* __PRETTY_FUNCTION__ */ + if (cftnsp == NULL) { + uerror("%s outside function", kwp->name); + yylval.strp = ""; + } else + yylval.strp = cftnsp->sname; /* XXX - not C99 */ + return C_STRING; + case 8: /* __volatile */ + case 9: /* __volatile__ */ + yylval.type = VOL; + return C_QUALIFIER; + case 15: /* __attribute__ */ + case 16: /* __attribute */ + inattr = 1; + parlvl = parbal; + return C_ATTRIBUTE; + case 17: /* __real__ */ + yylval.intval = XREAL; + return C_UNOP; + case 18: /* __imag__ */ + yylval.intval = XIMAG; + return C_UNOP; + } + cerror("gcc_keyword"); + return 0; +} + +#ifndef TARGET_ATTR +#define TARGET_ATTR(p, sue) 0 +#endif +#ifndef ALMAX +#define ALMAX (ALLDOUBLE > ALLONGLONG ? ALLDOUBLE : ALLONGLONG) +#endif + +/* allowed number of args */ +#define A_0ARG 0x01 +#define A_1ARG 0x02 +#define A_2ARG 0x04 +#define A_3ARG 0x08 +/* arg # is a name */ +#define A1_NAME 0x10 +#define A2_NAME 0x20 +#define A3_NAME 0x40 +#define A_MANY 0x80 +/* arg # is "string" */ +#define A1_STR 0x100 +#define A2_STR 0x200 +#define A3_STR 0x400 + +#ifdef __MSC__ +#define CS(x) +#else +#define CS(x) [x] = +#endif + +struct atax { + int typ; + char *name; +} atax[GCC_ATYP_MAX] = { + CS(ATTR_NONE) { 0, NULL }, + CS(ATTR_COMPLEX) { 0, NULL }, + CS(xxxATTR_BASETYP) { 0, NULL }, + CS(ATTR_QUALTYP) { 0, NULL }, + CS(ATTR_STRUCT) { 0, NULL }, + CS(ATTR_ALIGNED) { A_0ARG|A_1ARG, "aligned" }, + CS(ATTR_NORETURN) { A_0ARG, "noreturn" }, + CS(ATTR_P1LABELS) { A_0ARG, "p1labels" }, + CS(ATTR_SONAME) { A_1ARG|A1_STR, "soname" }, + CS(GCC_ATYP_PACKED) { A_0ARG|A_1ARG, "packed" }, + CS(GCC_ATYP_SECTION) { A_1ARG|A1_STR, "section" }, + CS(GCC_ATYP_TRANSP_UNION) { A_0ARG, "transparent_union" }, + CS(GCC_ATYP_UNUSED) { A_0ARG, "unused" }, + CS(GCC_ATYP_DEPRECATED) { A_0ARG, "deprecated" }, + CS(GCC_ATYP_MAYALIAS) { A_0ARG, "may_alias" }, + CS(GCC_ATYP_MODE) { A_1ARG|A1_NAME, "mode" }, + CS(GCC_ATYP_FORMAT) { A_3ARG|A1_NAME, "format" }, + CS(GCC_ATYP_NONNULL) { A_MANY, "nonnull" }, + CS(GCC_ATYP_SENTINEL) { A_0ARG|A_1ARG, "sentinel" }, + CS(GCC_ATYP_WEAK) { A_0ARG, "weak" }, + CS(GCC_ATYP_FORMATARG) { A_1ARG, "format_arg" }, + CS(GCC_ATYP_GNU_INLINE) { A_0ARG, "gnu_inline" }, + CS(GCC_ATYP_MALLOC) { A_0ARG, "malloc" }, + CS(GCC_ATYP_NOTHROW) { A_0ARG, "nothrow" }, + CS(GCC_ATYP_CONST) { A_0ARG, "const" }, + CS(GCC_ATYP_PURE) { A_0ARG, "pure" }, + CS(GCC_ATYP_CONSTRUCTOR) { A_0ARG, "constructor" }, + CS(GCC_ATYP_DESTRUCTOR) { A_0ARG, "destructor" }, + CS(GCC_ATYP_VISIBILITY) { A_1ARG|A1_STR, "visibility" }, + CS(GCC_ATYP_STDCALL) { A_0ARG, "stdcall" }, + CS(GCC_ATYP_CDECL) { A_0ARG, "cdecl" }, + CS(GCC_ATYP_WARN_UNUSED_RESULT) { A_0ARG, "warn_unused_result" }, + CS(GCC_ATYP_USED) { A_0ARG, "used" }, + CS(GCC_ATYP_NO_INSTR_FUN) { A_0ARG, "no_instrument_function" }, + CS(GCC_ATYP_NOINLINE) { A_0ARG, "noinline" }, + CS(GCC_ATYP_ALIAS) { A_1ARG|A1_STR, "alias" }, + CS(GCC_ATYP_WEAKREF) { A_0ARG|A_1ARG|A1_STR, "weakref" }, + CS(GCC_ATYP_ALLOCSZ) { A_1ARG|A_2ARG, "alloc_size" }, + CS(GCC_ATYP_ALW_INL) { A_0ARG, "always_inline" }, + CS(GCC_ATYP_TLSMODEL) { A_1ARG|A1_STR, "tls_model" }, + CS(GCC_ATYP_ALIASWEAK) { A_1ARG|A1_STR, "aliasweak" }, + CS(GCC_ATYP_RETURNS_TWICE) { A_0ARG, "returns_twice" }, + CS(GCC_ATYP_WARNING) { A_1ARG|A1_STR, "warning" }, + CS(GCC_ATYP_NOCLONE) { A_0ARG, "noclone" }, + CS(GCC_ATYP_REGPARM) { A_1ARG, "regparm" }, + CS(GCC_ATYP_FASTCALL) { A_0ARG, "fastcall" }, + + CS(GCC_ATYP_BOUNDED) { A_3ARG|A_MANY|A1_NAME, "bounded" }, + + CS(GCC_ATYP_WEAKIMPORT) { A_0ARG, "weak_import" }, +}; + +#if SZPOINT(CHAR) == SZLONGLONG +#define GPT LONGLONG +#else +#define GPT INT +#endif + +struct atax mods[] = { + { 0, NULL }, + { INT, "SI" }, + { INT, "word" }, + { GPT, "pointer" }, + { CHAR, "byte" }, + { CHAR, "QI" }, + { SHORT, "HI" }, + { LONGLONG, "DI" }, + { FLOAT, "SF" }, + { DOUBLE, "DF" }, + { LDOUBLE, "XF" }, + { FCOMPLEX, "SC" }, + { COMPLEX, "DC" }, + { LCOMPLEX, "XC" }, + { INT, "libgcc_cmp_return" }, + { INT, "libgcc_shift_count" }, + { LONG, "unwind_word" }, +#ifdef TARGET_TIMODE + { 800, "TI" }, +#endif +#ifdef TARGET_MODS + TARGET_MODS +#endif +}; +#define ATSZ (sizeof(mods)/sizeof(mods[0])) + +static int +amatch(char *s, struct atax *at, int mx) +{ + int i, len; + + if (s[0] == '_' && s[1] == '_') + s += 2; + len = strlen(s); + if (len > 2 && s[len-1] == '_' && s[len-2] == '_') + len -= 2; + for (i = 0; i < mx; i++) { + char *t = at[i].name; + if (t != NULL && strncmp(s, t, len) == 0 && t[len] == 0) + return i; + } + return 0; +} + +static void +setaarg(int str, union aarg *aa, NODE *p) +{ + if (str) { + if (((str & (A1_STR|A2_STR|A3_STR)) && p->n_op != STRING) || + ((str & (A1_NAME|A2_NAME|A3_NAME)) && p->n_op != NAME)) + uerror("bad arg to attribute"); + if (p->n_op == STRING) { + aa->sarg = p->n_name; /* saved in cgram.y */ + } else + aa->sarg = (char *)p->n_sp; + nfree(p); + } else + aa->iarg = (int)icons(eve(p)); +} + +/* + * Parse attributes from an argument list. + */ +static struct attr * +gcc_attribs(NODE *p) +{ + NODE *q, *r; + struct attr *ap; + char *name = NULL, *c; + int cw, attr, narg; + + if (p->n_op == NAME) { + name = (char *)p->n_sp; + } else if (p->n_op == CALL || p->n_op == UCALL) { + name = (char *)p->n_left->n_sp; + } else if (p->n_op == ICON && p->n_type == STRTY) { + return NULL; + } else + cerror("bad variable attribute"); + + if ((attr = amatch(name, atax, GCC_ATYP_MAX)) == 0) { + warner(Wattributes, name); + ap = NULL; + goto out; + } + narg = 0; + if (p->n_op == CALL) + for (narg = 1, q = p->n_right; q->n_op == CM; q = q->n_left) + narg++; + + cw = atax[attr].typ; + if (!(cw & A_MANY) && ((narg > 3) || ((cw & (1 << narg)) == 0))) { + uerror("wrong attribute arg count"); + return NULL; + } + ap = attr_new(attr, 3); /* XXX should be narg */ + q = p->n_right; + + switch (narg) { + default: + /* XXX */ + while (narg-- > 3) { + r = q; + q = q->n_left; + tfree(r->n_right); + nfree(r); + } + /* FALLTHROUGH */ + case 3: + setaarg(cw & (A3_NAME|A3_STR), &ap->aa[2], q->n_right); + r = q; + q = q->n_left; + nfree(r); + /* FALLTHROUGH */ + case 2: + setaarg(cw & (A2_NAME|A2_STR), &ap->aa[1], q->n_right); + r = q; + q = q->n_left; + nfree(r); + /* FALLTHROUGH */ + case 1: + setaarg(cw & (A1_NAME|A1_STR), &ap->aa[0], q); + p->n_op = UCALL; + /* FALLTHROUGH */ + case 0: + break; + } + + /* some attributes must be massaged special */ + switch (attr) { + case ATTR_ALIGNED: + if (narg == 0) + ap->aa[0].iarg = ALMAX; + else + ap->aa[0].iarg *= SZCHAR; + break; + case GCC_ATYP_PACKED: + if (narg == 0) + ap->aa[0].iarg = 1; /* bitwise align */ + else + ap->aa[0].iarg *= SZCHAR; + break; + + case GCC_ATYP_VISIBILITY: + c = ap->aa[0].sarg; + if (strcmp(c, "default") && strcmp(c, "hidden") && + strcmp(c, "internal") && strcmp(c, "protected")) + werror("unknown visibility %s", c); + break; + + case GCC_ATYP_TLSMODEL: + c = ap->aa[0].sarg; + if (strcmp(c, "global-dynamic") && strcmp(c, "local-dynamic") && + strcmp(c, "initial-exec") && strcmp(c, "local-exec")) + werror("unknown tls model %s", c); + break; + + default: + break; + } +out: + return ap; +} + +/* + * Extract attributes from a node tree and return attribute entries + * based on its contents. + */ +struct attr * +gcc_attr_parse(NODE *p) +{ + struct attr *b, *c; + + if (p == NIL) + return NULL; + + if (p->n_op != CM) { + b = gcc_attribs(p); + tfree(p); + } else { + b = gcc_attr_parse(p->n_left); + c = gcc_attr_parse(p->n_right); + nfree(p); + b = b ? attr_add(b, c) : c; + } + return b; +} + +/* + * Fixup struct/unions depending on attributes. + */ +void +gcc_tcattrfix(NODE *p) +{ + struct symtab *sp; + struct attr *ap; + int sz, coff, csz, al, oal, mxal; + + if (!ISSOU(p->n_type)) /* only for structs or unions */ + return; + if ((ap = attr_find(p->n_ap, GCC_ATYP_PACKED)) == NULL) + return; /* nothing to fix */ + + al = ap->iarg(0); + mxal = 0; + + /* Must repack struct */ + coff = csz = 0; + for (sp = strmemb(ap); sp; sp = sp->snext) { + oal = talign(sp->stype, sp->sap); + if (oal > al) + oal = al; + if (mxal < oal) + mxal = oal; + if (sp->sclass & FIELD) + sz = sp->sclass&FLDSIZ; + else + sz = (int)tsize(sp->stype, sp->sdf, sp->sap); + sp->soffset = upoff(sz, oal, &coff); + if (coff > csz) + csz = coff; + if (p->n_type == UNIONTY) + coff = 0; + } + if (mxal < ALCHAR) + mxal = ALCHAR; /* for bitfields */ + SETOFF(csz, mxal); /* Roundup to whatever */ + + ap = attr_find(p->n_ap, ATTR_STRUCT); + ap->amsize = csz; + ap = attr_find(p->n_ap, ATTR_ALIGNED); + ap->iarg(0) = mxal; + +} + +/* + * gcc-specific pragmas. + */ +int +pragmas_gcc(char *t) +{ + char u; + extern char *pragstore; + + if (strcmp((t = pragtok(NULL)), "diagnostic") == 0) { + int warn, err; + + if (strcmp((t = pragtok(NULL)), "ignored") == 0) + warn = 0, err = 0; + else if (strcmp(t, "warning") == 0) + warn = 1, err = 0; + else if (strcmp(t, "error") == 0) + warn = 1, err = 1; + else + return 1; + + if (eat('\"') || eat('-')) + return 1; + + for (t = pragstore; *t && *t != '\"'; t++) + ; + + u = *t; + *t = 0; + Wset(pragstore + 1, warn, err); + *t = u; + } else if (strcmp(t, "poison") == 0) { + /* currently ignore */; + } else if (strcmp(t, "visibility") == 0) { + /* currently ignore */; + } else if (strcmp(t, "system_header") == 0) { + /* currently ignore */; + } else + werror("gcc pragma unsupported"); + return 0; +} + +/* + * Fixup types when modes given in defid(). + */ +void +gcc_modefix(NODE *p) +{ + struct attr *ap; +#ifdef TARGET_TIMODE + struct attr *a2; +#endif + struct symtab *sp; + char *s; + int i, u; + + if ((ap = attr_find(p->n_ap, GCC_ATYP_MODE)) == NULL) + return; + + u = ISUNSIGNED(BTYPE(p->n_type)); + if ((i = amatch(ap->aa[0].sarg, mods, ATSZ)) == 0) { + werror("unknown mode arg %s", ap->aa[0].sarg); + return; + } + i = mods[i].typ; + if (i >= 1 && i <= MAXTYPES) { + MODTYPE(p->n_type, ctype(i)); + if (u) + p->n_type = ENUNSIGN(p->n_type); + } else switch (i) { +#ifdef TARGET_TIMODE + case 800: + if (BTYPE(p->n_type) == STRTY) + break; + MODTYPE(p->n_type, tisp->stype); + p->n_df = tisp->sdf; + p->n_ap = tisp->sap; + if (ap->iarg(1) == u) + break; + /* must add a new mode struct to avoid overwriting */ + a2 = attr_new(GCC_ATYP_MODE, 3); + a2->sarg(0) = ap->sarg(0); + a2->iarg(1) = u; + p->n_ap = attr_add(p->n_ap, a2); + break; +#endif + case FCOMPLEX: + case COMPLEX: + case LCOMPLEX: + /* Destination should have been converted to a struct already */ + if (BTYPE(p->n_type) != STRTY) + uerror("gcc_modefix: complex not STRTY"); + i -= (FCOMPLEX-FLOAT); + ap = strattr(p->n_ap); + sp = ap->amlist; + if (sp->stype == (unsigned)i) + return; /* Already correct type */ + /* we must change to another struct */ + s = i == FLOAT ? "0f" : + i == DOUBLE ? "0d" : + i == LDOUBLE ? "0l" : 0; + sp = lookup(addname(s), 0); + for (ap = sp->sap; ap != NULL; ap = ap->next) + p->n_ap = attr_add(p->n_ap, attr_dup(ap)); + break; + + default: + cerror("gcc_modefix"); + } +} + +#ifdef TARGET_TIMODE + +/* + * Return ap if this node is a TI node, else NULL. + */ +struct attr * +isti(NODE *p) +{ + struct attr *ap; + + if (p->n_type != STRTY) + return NULL; + if ((ap = attr_find(p->n_ap, GCC_ATYP_MODE)) == NULL) + return NULL; + if (strcmp(ap->sarg(0), TISTR)) + return NULL; + return ap; +} + +static char * +tistack(void) +{ + struct symtab *sp, *sp2; + char buf[12]; + NODE *q; + char *n; + + /* allocate space on stack */ + snprintf(buf, 12, "%d", getlab()); + n = addname(buf); + sp = lookup(n, 0); + sp2 = tisp; + q = block(TYPE, NIL, NIL, sp2->stype, sp2->sdf, sp2->sap); + q->n_sp = sp; + nidcl2(q, AUTO, 0); + nfree(q); + return n; +} + +#define biop(x,y,z) block(x, y, z, INT, 0, 0) +/* + * Create a ti node from something not a ti node. + * This usually means: allocate space on stack, store val, give stack address. + */ +static NODE * +ticast(NODE *p, int u) +{ + CONSZ val; + NODE *q; + char *n; + int u2; + + n = tistack(); + + /* store val */ + switch (p->n_op) { + case ICON: + val = 0; + if (u == 0 && p->n_lval < 0) + val = -1; + q = eve(biop(DOT, bdty(NAME, n), bdty(NAME, loti))); + q = buildtree(ASSIGN, q, p); + p = biop(DOT, bdty(NAME, n), bdty(NAME, hiti)); + p = eve(biop(ASSIGN, p, bcon(val))); + q = buildtree(COMOP, q, p); + p = buildtree(COMOP, q, eve(bdty(NAME, n))); + break; + + default: + u2 = ISUNSIGNED(p->n_type); + q = eve(biop(DOT, bdty(NAME, n), bdty(NAME, loti))); + q = buildtree(ASSIGN, q, p); + p = biop(DOT, bdty(NAME, n), bdty(NAME, hiti)); + if (u2) { + p = eve(biop(ASSIGN, p, bcon(0))); + } else { + q = buildtree(ASSIGN, eve(ccopy(p)), q); + p = buildtree(RSEQ, eve(p), bcon(SZLONG-1)); + } + q = buildtree(COMOP, q, p); + p = buildtree(COMOP, q, eve(bdty(NAME, n))); + break; + } + return p; +} + +/* + * Check if we may have to do a cast to/from TI. + */ +NODE * +gcc_eval_ticast(int op, NODE *p1, NODE *p2) +{ + struct attr *a1, *a2; + int t; + + if ((a1 = isti(p1)) == NULL && (a2 = isti(p2)) == NULL) + return NIL; + + if (op == RETURN) + p1 = ccopy(p1); + if (a1 == NULL) { + if (a2 == NULL) + cerror("gcc_eval_ticast error"); + switch (p1->n_type) { + case LDOUBLE: + p2 = doacall(floatuntixfsp, + nametree(floatuntixfsp), p2); + tfree(p1); + break; + case ULONG: + case LONG: + p2 = cast(structref(p2, DOT, loti), p1->n_type, 0); + tfree(p1); + break; + case VOID: + return NIL; + default: + uerror("gcc_eval_ticast: %d", p1->n_type); + } + return p2; + } + /* p2 can be anything, but we must cast it to p1 */ + t = a1->iarg(1); + + if (p2->n_type == STRTY && + (a2 = attr_find(p2->n_ap, GCC_ATYP_MODE)) && + strcmp(a2->sarg(0), TISTR) == 0) { + /* Already TI, just add extra mode bits */ + a2 = attr_new(GCC_ATYP_MODE, 3); + a2->sarg(0) = TISTR; + a2->iarg(1) = t; + p2->n_ap = attr_add(p2->n_ap, a2); + } else { + p2 = ticast(p2, t); + } + tfree(p1); + return p2; +} + +/* + * Apply a unary op on a TI value. + */ +NODE * +gcc_eval_tiuni(int op, NODE *p1) +{ + struct attr *a1; + NODE *p; + + if ((a1 = isti(p1)) == NULL) + return NULL; + + switch (op) { + case UMINUS: + p = ticast(bcon(0), 0); + p = buildtree(CM, p, p1); + p = doacall(subvti3sp, nametree(subvti3sp), p); + break; + + case UMUL: + p = NULL; + default: + uerror("unsupported unary TI mode op %d", op); + p = NULL; + } + return p; +} + +/* + * Evaluate AND/OR/ER. p1 and p2 are pointers to ti struct. + */ +static NODE * +gcc_andorer(int op, NODE *p1, NODE *p2) +{ + char *n = tistack(); + NODE *p, *t1, *t2, *p3; + + t1 = tempnode(0, p1->n_type, p1->n_df, p1->n_ap); + t2 = tempnode(0, p2->n_type, p2->n_df, p2->n_ap); + + p1 = buildtree(ASSIGN, ccopy(t1), p1); + p2 = buildtree(ASSIGN, ccopy(t2), p2); + p = buildtree(COMOP, p1, p2); + + p3 = buildtree(ADDROF, eve(bdty(NAME, n)), NIL); + p1 = buildtree(ASSIGN, structref(ccopy(p3), STREF, hiti), + buildtree(op, structref(ccopy(t1), STREF, hiti), + structref(ccopy(t2), STREF, hiti))); + p = buildtree(COMOP, p, p1); + p1 = buildtree(ASSIGN, structref(ccopy(p3), STREF, loti), + buildtree(op, structref(t1, STREF, loti), + structref(t2, STREF, loti))); + p = buildtree(COMOP, p, p1); + p = buildtree(COMOP, p, buildtree(UMUL, p3, NIL)); + return p; +} + +/* + * Ensure that a 128-bit assign succeeds. + * If left is not TI, make right not TI, + * else if left _is_ TI, make right TI, + * else do nothing. + */ +static NODE * +timodeassign(NODE *p1, NODE *p2) +{ + struct attr *a1, *a2; + + a1 = isti(p1); + a2 = isti(p2); + if (a1 && a2 == NULL) { + p2 = ticast(p2, a1->iarg(1)); + } else if (a1 == NULL && a2) { + if (ISFTY(p1->n_type)) + cerror("cannot TI float convert"); + p2 = structref(p2, DOT, loti); + } + return buildtree(ASSIGN, p1, p2); +} + +/* + * Evaluate 128-bit operands. + */ +NODE * +gcc_eval_timode(int op, NODE *p1, NODE *p2) +{ + struct attr *a1, *a2; + struct symtab *sp; + NODE *p; + int isu = 0, gotti, isaop; + + if (op == CM) + return buildtree(op, p1, p2); + + a1 = isti(p1); + a2 = isti(p2); + + if (a1 == NULL && a2 == NULL) + return NULL; + + if (op == ASSIGN) + return timodeassign(p1, p2); + + gotti = (a1 != NULL); + gotti += (a2 != NULL); + + if (gotti == 0) + return NULL; + + if (a1 != NULL) + isu = a1->iarg(1); + if (a2 != NULL && !isu) + isu = a2->iarg(1); + + if (a1 == NULL) { + p1 = ticast(p1, isu); + a1 = attr_find(p1->n_ap, GCC_ATYP_MODE); + } + if (a2 == NULL && (cdope(op) & SHFFLG) == 0) { + p2 = ticast(p2, isu); + a2 = attr_find(p2->n_ap, GCC_ATYP_MODE); + } + + switch (op) { + case GT: + case GE: + case LT: + case LE: + case EQ: + case NE: + /* change to call */ + sp = isu ? ucmpti2sp : cmpti2sp; + p = doacall(sp, nametree(sp), buildtree(CM, p1, p2)); + p = buildtree(op, p, bcon(1)); + break; + + case AND: + case ER: + case OR: + if (!ISPTR(p1->n_type)) + p1 = buildtree(ADDROF, p1, NIL); + if (!ISPTR(p2->n_type)) + p2 = buildtree(ADDROF, p2, NIL); + p = gcc_andorer(op, p1, p2); + break; + + case LSEQ: + case RSEQ: + case LS: + case RS: + sp = op == LS || op == LSEQ ? ashldi3sp : + isu ? lshrdi3sp : ashrdi3sp; + p2 = cast(p2, INT, 0); + /* XXX p1 ccopy may have side effects */ + p = doacall(sp, nametree(sp), buildtree(CM, ccopy(p1), p2)); + if (op == LSEQ || op == RSEQ) { + p = buildtree(ASSIGN, p1, p); + } else + tfree(p1); + break; + + case PLUSEQ: + case MINUSEQ: + case MULEQ: + case DIVEQ: + case MODEQ: + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + isaop = (cdope(op)&ASGOPFLG); + if (isaop) + op = UNASG op; + sp = op == PLUS ? addvti3sp : + op == MINUS ? subvti3sp : + op == MUL ? mulvti3sp : + op == DIV ? (isu ? udivti3sp : divti3sp) : + op == MOD ? (isu ? umodti3sp : modti3sp) : 0; + /* XXX p1 ccopy may have side effects */ + p = doacall(sp, nametree(sp), buildtree(CM, ccopy(p1), p2)); + if (isaop) + p = buildtree(ASSIGN, p1, p); + else + tfree(p1); + break; + + default: + uerror("unsupported TImode op %d", op); + p = bcon(0); + } + return p; +} +#endif + +#ifdef PCC_DEBUG +void +dump_attr(struct attr *ap) +{ + printf("attributes; "); + for (; ap; ap = ap->next) { + if (ap->atype >= GCC_ATYP_MAX) { + printf("bad type %d, ", ap->atype); + } else if (atax[ap->atype].name == 0) { + char *c = ap->atype == ATTR_COMPLEX ? "complex" : + ap->atype == ATTR_STRUCT ? "struct" : "badtype"; + printf("%s, ", c); + } else { + printf("%s: ", atax[ap->atype].name); + if (atax[ap->atype].typ & A1_STR) + printf("%s ", ap->sarg(0)); + else + printf("%d %d %d, ", ap->iarg(0), + ap->iarg(1), ap->iarg(2)); + } + } + printf("\n"); +} +#endif +#endif diff --git a/lang/pcc/pcc/cc/ccom/init.c b/lang/pcc/pcc/cc/ccom/init.c new file mode 100644 index 000000000..a18a5572c --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/init.c @@ -0,0 +1,1284 @@ +/* $Id: init.c,v 1.99 2015/11/17 19:19:40 ragge Exp $ */ + +/* + * Copyright (c) 2004, 2007 Anders Magnusson (ragge@ludd.ltu.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 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. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "pass1.h" +#include "unicode.h" +#include + +#define NODE P1ND +#define tfree p1tfree +#define nfree p1nfree +#define fwalk p1fwalk + +/* + * The following machine-dependent routines may be called during + * initialization: + * + * zbits(OFFSZ, int) - sets int bits of zero at position OFFSZ. + * infld(CONSZ off, int fsz, CONSZ val) + * - sets the bitfield val starting at off and size fsz. + * ninval(CONSZ off, int fsz, NODE *) + * - prints an integer constant which may have + * a label associated with it, located at off and + * size fsz. + * + * Initialization may be of different kind: + * - Initialization at compile-time, all values are constants and laid + * out in memory. Static or extern variables outside functions. + * - Initialization at run-time, written to their values as code. + * + * Currently run-time-initialized variables are only initialized by using + * move instructions. An optimization might be to detect that it is + * initialized with constants and therefore copied from readonly memory. + */ + +/* + * The base element(s) of an initialized variable is kept in a linked + * list, allocated while initialized. + * + * When a scalar is found, entries are popped of the instk until it's + * possible to find an entry for a new scalar; then onstk() is called + * to get the correct type and size of that scalar. + * + * If a right brace is found, pop the stack until a matching left brace + * were found while filling the elements with zeros. This left brace is + * also marking where the current level is for designated initializations. + * + * Position entries are increased when traversing back down into the stack. + */ + +/* + * Good-to-know entries from symtab: + * soffset - # of bits from beginning of this structure. + */ + +/* + * TO FIX: + * - Alignment of structs on like i386 char members. + */ + +/* + * Struct used in array initialisation. + */ +static struct instk { + struct instk *in_prev; /* linked list */ + struct symtab *in_lnk; /* member in structure initializations */ + struct symtab *in_sym; /* symtab index */ + union dimfun *in_df; /* dimenston of array */ + TWORD in_t; /* type for this level */ + int in_n; /* number of arrays seen so far */ + int in_fl; /* flag which says if this level is controlled by {} */ +} *pstk, pbase; + +int doing_init, statinit; +static struct symtab *csym; + +#ifdef PCC_DEBUG +static void prtstk(struct instk *in); +#endif + +/* + * Linked lists for initializations. + */ +struct ilist { + struct ilist *next; + CONSZ off; /* bit offset of this entry */ + int fsz; /* bit size of this entry */ + NODE *n; /* node containing this data info */ +}; + +struct llist { + SLIST_ENTRY(llist) next; + CONSZ begsz; /* bit offset of this entry */ + struct ilist *il; +}; +static SLIST_HEAD(llh, llist) lpole; +static CONSZ basesz; +static int numents; /* # of array entries allocated */ + +static struct initctx { + struct initctx *prev; + struct instk *pstk; + struct symtab *psym; + struct llh lpole; + CONSZ basesz; + int numents; +} *inilnk; + +static struct ilist * +getil(struct ilist *next, CONSZ b, int sz, NODE *n) +{ + struct ilist *il = tmpalloc(sizeof(struct ilist)); + + il->off = b; + il->fsz = sz; + il->n = n; + il->next = next; + return il; +} + +/* + * Allocate a new struct defining a block of initializers appended to the + * end of the llist. Return that entry. + */ +static struct llist * +getll(void) +{ + struct llist *ll; + + ll = tmpalloc(sizeof(struct llist)); + ll->begsz = numents * basesz; + ll->il = NULL; + SLIST_INSERT_LAST(&lpole, ll, next); + numents++; + return ll; +} + +/* + * Return structure containing off bitnumber. + * Allocate more entries, if needed. + */ +static struct llist * +setll(OFFSZ off) +{ + struct llist *ll = NULL; + + /* Ensure that we have enough entries */ + while (off >= basesz * numents) + ll = getll(); + + if (ll != NULL && ll->begsz <= off && ll->begsz + basesz > off) + return ll; + + SLIST_FOREACH(ll, &lpole, next) + if (ll->begsz <= off && ll->begsz + basesz > off) + break; + return ll; /* ``cannot fail'' */ +} +char *astypnames[] = { 0, 0, "\t.byte", "\t.byte", "\t.short", "\t.short", + "\t.word", "\t.word", "\t.long", "\t.long", "\t.quad", "\t.quad", + "ERR", "ERR", "ERR", +}; + +void +inval(CONSZ off, int fsz, NODE *p) +{ + struct symtab *sp; + CONSZ val; + TWORD t; + +#ifndef NO_COMPLEX + if (ANYCX(p) && p->n_left->n_right->n_right->n_op == FCON && + p->n_left->n_left->n_right->n_op == FCON) { + NODE *r = p->n_left->n_right->n_right; + int sz = (int)tsize(r->n_type, r->n_df, r->n_ap); + ninval(off, sz, p->n_left->n_left->n_right); + ninval(off, sz, r); + tfree(p); + return; + } +#endif + + if (p->n_op != ICON && p->n_op != FCON) { + uerror("constant required"); + return; + } + if (p->n_type == BOOL) { + if ((U_CONSZ)glval(p) > 1) + slval(p, 1); + p->n_type = BOOL_TYPE; + } + if (ninval(off, fsz, p)) + return; /* dealt with in local.c */ + t = p->n_type; + if (t > BTMASK) + t = INTPTR; + + val = (CONSZ)(glval(p) & SZMASK(sztable[t])); + if (t <= ULONGLONG) { + sp = p->n_sp; + printf(PRTPREF "%s ",astypnames[t]); + if (val || sp == NULL) + printf(CONFMT, val); + if (val && sp != NULL) + printf("+"); + if (sp != NULL) { + if ((sp->sclass == STATIC && sp->slevel > 0)) { + /* fix problem with &&label not defined yet */ + int o = sp->soffset; + printf(LABFMT, o < 0 ? -o : o); + if ((sp->sflags & SMASK) == SSTRING) + sp->sflags |= SASG; + } else + printf("%s", getexname(sp)); + } + printf("\n"); + } else + cerror("inval: unhandled type %d", (int)t); +} + +#ifndef MYBFINIT + +static int inbits; +static CONSZ xinval; +/* + * Initialize a bitfield. + * XXX - use U_CONSZ? + */ +void +infld(CONSZ off, int fsz, CONSZ val) +{ +#ifdef PCC_DEBUG + if (idebug) + printf("infld off " CONFMT ", fsz %d, val " CONFMT " inbits %d\n", + off, fsz, val, inbits); +#endif + val &= SZMASK(fsz); +#if TARGET_ENDIAN == TARGET_BE + while (fsz + inbits >= SZCHAR) { + int shsz = SZCHAR-inbits; + xinval = (xinval << shsz) | (val >> (fsz - shsz)); + printf(PRTPREF "%s " CONFMT "\n", + astypnames[CHAR], xinval & SZMASK(SZCHAR)); + fsz -= shsz; + val &= SZMASK(fsz); + xinval = inbits = 0; + } + if (fsz) { + xinval = (xinval << fsz) | val; + inbits += fsz; + } +#else + while (fsz + inbits >= SZCHAR) { + int shsz = SZCHAR-inbits; + xinval |= (val << inbits); + printf(PRTPREF "%s " CONFMT "\n", + astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR))); + fsz -= shsz; + val >>= shsz; + xinval = inbits = 0; + } + if (fsz) { + xinval |= (val << inbits); + inbits += fsz; + } +#endif +} + +char *asspace = "\t.space"; + +/* + * set fsz bits in sequence to zero. + */ +void +zbits(OFFSZ off, int fsz) +{ + int m; + +#ifdef PCC_DEBUG + if (idebug) + printf("zbits off " CONFMT ", fsz %d inbits %d\n", off, fsz, inbits); +#endif +#if TARGET_ENDIAN == TARGET_BE + if ((m = (inbits % SZCHAR))) { + m = SZCHAR - m; + if (fsz < m) { + inbits += fsz; + xinval <<= fsz; + return; + } else { + fsz -= m; + xinval <<= m; + printf(PRTPREF "%s " CONFMT "\n", + astypnames[CHAR], xinval & SZMASK(SZCHAR)); + xinval = inbits = 0; + } + } +#else + if ((m = (inbits % SZCHAR))) { + m = SZCHAR - m; + if (fsz < m) { + inbits += fsz; + return; + } else { + fsz -= m; + printf(PRTPREF "%s " CONFMT "\n", + astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR))); + xinval = inbits = 0; + } + } +#endif + if (fsz >= SZCHAR) { + printf(PRTPREF "%s %d\n", asspace, fsz/SZCHAR); + fsz -= (fsz/SZCHAR) * SZCHAR; + } + if (fsz) { + xinval = 0; + inbits = fsz; + } +} +#endif + +/* + * beginning of initialization; allocate space to store initialized data. + * remember storage class for writeout in endinit(). + * p is the newly declarated type. + */ +void +beginit(struct symtab *sp) +{ + struct initctx *ict; + struct instk *is = &pbase; + +#ifdef PCC_DEBUG + if (idebug) + printf("beginit(%p), sclass %s\n", sp, scnames(sp->sclass)); +#endif + + if (pstk) { +#ifdef PCC_DEBUG + if (idebug) + printf("beginit: saving ctx pstk %p\n", pstk); +#endif + /* save old context */ + ict = tmpalloc(sizeof(struct initctx)); + ict->prev = inilnk; + inilnk = ict; + ict->pstk = pstk; + ict->psym = csym; + ict->lpole = lpole; + ict->basesz = basesz; + ict->numents = numents; + is = tmpalloc(sizeof(struct instk)); + } + csym = sp; + + numents = 0; /* no entries in array list */ + if (ISARY(sp->stype)) { + basesz = tsize(DECREF(sp->stype), sp->sdf+1, sp->sap); + if (basesz == 0) { + uerror("array has incomplete type"); + basesz = SZINT; + } + } else + basesz = tsize(sp->stype, sp->sdf, sp->sap); + SLIST_INIT(&lpole); + + /* first element */ + if (ISSOU(sp->stype)) { + is->in_lnk = strmemb(sp->sap); + } else + is->in_lnk = NULL; + is->in_n = 0; + is->in_t = sp->stype; + is->in_sym = sp; + is->in_df = sp->sdf; + is->in_fl = 0; + is->in_prev = NULL; + pstk = is; + doing_init++; + if (sp->sclass == STATIC || sp->sclass == EXTDEF) + statinit++; +} + +/* + * Push a new entry on the initializer stack. + * The new entry will be "decremented" to the new sub-type of the previous + * entry when called. + * Popping of entries is done elsewhere. + */ +static void +stkpush(void) +{ + struct instk *is; + struct symtab *sq, *sp; + TWORD t; + + if (pstk == NULL) { + sp = csym; + t = 0; + } else { + t = pstk->in_t; + sp = pstk->in_sym; + } + +#ifdef PCC_DEBUG + if (idebug) { + printf("stkpush: '%s' %s ", sp->sname, scnames(sp->sclass)); + tprint(t, 0); + } +#endif + + /* + * Figure out what the next initializer will be, and push it on + * the stack. If this is an array, just decrement type, if it + * is a struct or union, extract the next element. + */ + is = tmpalloc(sizeof(struct instk)); + is->in_fl = 0; + is->in_n = 0; + if (pstk == NULL) { + /* stack empty */ + is->in_lnk = ISSOU(sp->stype) ? strmemb(sp->sap) : NULL; + is->in_t = sp->stype; + is->in_sym = sp; + is->in_df = sp->sdf; + } else if (ISSOU(t)) { + sq = pstk->in_lnk; + if (sq == NULL) { + uerror("excess of initializing elements"); + } else { + is->in_lnk = ISSOU(sq->stype) ? strmemb(sq->sap) : NULL; + is->in_t = sq->stype; + is->in_sym = sq; + is->in_df = sq->sdf; + } + } else if (ISARY(t)) { + is->in_lnk = ISSOU(DECREF(t)) ? strmemb(pstk->in_sym->sap) : 0; + is->in_t = DECREF(t); + is->in_sym = sp; + if (pstk->in_df->ddim != NOOFFSET && pstk->in_df->ddim && + pstk->in_n >= pstk->in_df->ddim) { + werror("excess of initializing elements"); + pstk->in_n--; + } + is->in_df = pstk->in_df+1; + } else + uerror("too many left braces"); + is->in_prev = pstk; + pstk = is; + +#ifdef PCC_DEBUG + if (idebug) { + printf(" newtype "); + tprint(is->in_t, 0); + printf("\n"); + } +#endif +} + +/* + * pop down to either next level that can handle a new initializer or + * to the next braced level. + */ +static void +stkpop(void) +{ +#ifdef PCC_DEBUG + if (idebug) + printf("stkpop\n"); +#endif + for (; pstk; pstk = pstk->in_prev) { + if (pstk->in_t == STRTY && pstk->in_lnk != NULL) { + pstk->in_lnk = pstk->in_lnk->snext; + if (pstk->in_lnk != NULL) + break; + } + if (ISSOU(pstk->in_t) && pstk->in_fl) + break; /* need } */ + if (ISARY(pstk->in_t)) { + pstk->in_n++; + if (pstk->in_fl) + break; + if (pstk->in_df->ddim == NOOFFSET || + pstk->in_n < pstk->in_df->ddim) + break; /* ger more elements */ + } + } +#ifdef PCC_DEBUG + if (idebug > 1) + prtstk(pstk); +#endif +} + +/* + * Count how many elements an array may consist of. + */ +static int +acalc(struct instk *is, int n) +{ + if (is == NULL || !ISARY(is->in_t)) + return 0; + return acalc(is->in_prev, n * is->in_df->ddim) + n * is->in_n; +} + +/* + * Find current bit offset of the top element on the stack from + * the beginning of the aggregate. + */ +static CONSZ +findoff(void) +{ + struct instk *is; + OFFSZ off; + +#ifdef PCC_DEBUG + if (ISARY(pstk->in_t)) + cerror("findoff on bad type %x", pstk->in_t); +#endif + + /* + * Offset calculations. If: + * - previous type is STRTY, soffset has in-struct offset. + * - this type is ARY, offset is ninit*stsize. + */ + for (off = 0, is = pstk; is; is = is->in_prev) { + if (is->in_prev && is->in_prev->in_t == STRTY) + off += is->in_sym->soffset; + if (ISARY(is->in_t)) { + /* suesize is the basic type, so adjust */ + TWORD t = is->in_t; + OFFSZ o; + while (ISARY(t)) + t = DECREF(t); + if (ISPTR(t)) { + o = SZPOINT(t); /* XXX use tsize() */ + } else { + o = tsize(t, is->in_sym->sdf, is->in_sym->sap); + } + off += o * acalc(is, 1); + while (is->in_prev && ISARY(is->in_prev->in_t)) { + if (is->in_prev->in_prev && + is->in_prev->in_prev->in_t == STRTY) + off += is->in_sym->soffset; + is = is->in_prev; + } + } + } +#ifdef PCC_DEBUG + if (idebug>1) { + printf("findoff: off " CONFMT "\n", off); + prtstk(pstk); + } +#endif + return off; +} + +/* + * Insert the node p with size fsz at position off. + * Bit fields are already dealt with, so a node of correct type + * with correct alignment and correct bit offset is given. + */ +static void +nsetval(CONSZ off, int fsz, NODE *p) +{ + struct llist *ll; + struct ilist *il; + + if (idebug>1) + printf("setval: off " CONFMT " fsz %d p %p\n", off, fsz, p); + + if (fsz == 0) + return; + + ll = setll(off); + off -= ll->begsz; + if (ll->il == NULL) { + ll->il = getil(NULL, off, fsz, p); + } else { + il = ll->il; + if (il->off > off) { + ll->il = getil(ll->il, off, fsz, p); + } else { + for (il = ll->il; il->next; il = il->next) + if (il->off <= off && il->next->off > off) + break; + if (il->off == off) { + /* replace */ + nfree(il->n); + il->n = p; + } else + il->next = getil(il->next, off, fsz, p); + } + } +} + +/* + * take care of generating a value for the initializer p + * inoff has the current offset (last bit written) + * in the current word being generated + * Returns the offset. + */ +CONSZ +scalinit(NODE *p) +{ + CONSZ woff; + NODE *q; + int fsz; + +#ifdef PCC_DEBUG + if (idebug > 2) { + printf("scalinit(%p)\n", p); + fwalk(p, eprint, 0); + prtstk(pstk); + } +#endif + + if (nerrors) + return 0; + + p = optim(p); + +#ifdef notdef /* leave to the target to decide if useable */ + if (csym->sclass != AUTO && p->n_op != ICON && + p->n_op != FCON && p->n_op != NAME) + cerror("scalinit not leaf"); +#endif + + /* Out of elements? */ + if (pstk == NULL) { + uerror("excess of initializing elements"); + return 0; + } + + /* + * Get to the simple type if needed. + */ + while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) { + stkpush(); + /* If we are doing auto struct init */ + if (ISSOU(pstk->in_t) && ISSOU(p->n_type) && + suemeq(pstk->in_sym->sap, p->n_ap)) { + pstk->in_lnk = NULL; /* this elem is initialized */ + break; + } + } + + if (ISSOU(pstk->in_t) == 0) { + /* let buildtree do typechecking (and casting) */ + q = block(NAME, NIL,NIL, pstk->in_t, pstk->in_df, + pstk->in_sym->sap); + p = buildtree(ASSIGN, q, p); + nfree(p->n_left); + q = p->n_right; + nfree(p); + } else + q = p; + + q = optloop(q); + + woff = findoff(); + + /* bitfield sizes are special */ + if (pstk->in_sym->sclass & FIELD) + fsz = -(pstk->in_sym->sclass & FLDSIZ); + else + fsz = (int)tsize(pstk->in_t, pstk->in_sym->sdf, + pstk->in_sym->sap); + + nsetval(woff, fsz, q); + if (q->n_op == ICON && q->n_sp && + ((q->n_sp->sflags & SMASK) == SSTRING)) + q->n_sp->sflags |= SASG; + + stkpop(); +#ifdef PCC_DEBUG + if (idebug > 2) { + printf("scalinit e(%p)\n", q); + } +#endif + return woff; +} + +/* + * Generate code to insert a value into a bitfield. + */ +static void +insbf(OFFSZ off, int fsz, int val) +{ + struct symtab sym; + NODE *p, *r; + TWORD typ; + +#ifdef PCC_DEBUG + if (idebug > 1) + printf("insbf: off " CONFMT " fsz %d val %d\n", off, fsz, val); +#endif + + if (fsz == 0) + return; + + /* small opt: do char instead of bf asg */ + if ((off & (ALCHAR-1)) == 0 && fsz == SZCHAR) + typ = CHAR; + else + typ = INT; + /* Fake a struct reference */ + p = buildtree(ADDROF, nametree(csym), NIL); + sym.stype = typ; + sym.squal = 0; + sym.sdf = 0; + sym.sap = NULL; + sym.soffset = (int)off; + sym.sclass = (char)(typ == INT ? FIELD | fsz : MOU); + r = xbcon(0, &sym, typ); + p = block(STREF, p, r, INT, 0, 0); + ecomp(buildtree(ASSIGN, stref(p), bcon(val))); +} + +/* + * Clear a bitfield, starting at off and size fsz. + */ +static void +clearbf(OFFSZ off, OFFSZ fsz) +{ + /* Pad up to the next even initializer */ + if ((off & (ALCHAR-1)) || (fsz < SZCHAR)) { + int ba = (int)(((off + (SZCHAR-1)) & ~(SZCHAR-1)) - off); + if (ba > fsz) + ba = (int)fsz; + insbf(off, ba, 0); + off += ba; + fsz -= ba; + } + while (fsz >= SZCHAR) { + insbf(off, SZCHAR, 0); + off += SZCHAR; + fsz -= SZCHAR; + } + if (fsz) + insbf(off, fsz, 0); +} + +/* + * final step of initialization. + * print out init nodes and generate copy code (if needed). + */ +void +endinit(int seg) +{ + struct llist *ll; + struct ilist *il; + int fsz; + OFFSZ lastoff, tbit; + +#ifdef PCC_DEBUG + if (idebug) + printf("endinit()\n"); +#endif + + /* Calculate total block size */ + if (ISARY(csym->stype) && csym->sdf->ddim == NOOFFSET) { + tbit = numents*basesz; /* open-ended arrays */ + csym->sdf->ddim = numents; + if (csym->sclass == AUTO) { /* Get stack space */ + csym->soffset = NOOFFSET; + oalloc(csym, &autooff); + } + } else + tbit = tsize(csym->stype, csym->sdf, csym->sap); + + /* Setup symbols */ + if (csym->sclass != AUTO) { + locctr(seg ? UDATA : DATA, csym); + defloc(csym); + } + + /* Traverse all entries and print'em out */ + lastoff = 0; + SLIST_FOREACH(ll, &lpole, next) { + for (il = ll->il; il; il = il->next) { +#ifdef PCC_DEBUG + if (idebug > 1) { + printf("off " CONFMT " size %d val " CONFMT " type ", + ll->begsz+il->off, il->fsz, glval(il->n)); + tprint(il->n->n_type, 0); + printf("\n"); + } +#endif + fsz = il->fsz; + if (csym->sclass == AUTO) { + struct symtab sym; + NODE *p, *r, *n; + + if (ll->begsz + il->off > lastoff) + clearbf(lastoff, + (ll->begsz + il->off) - lastoff); + + /* Fake a struct reference */ + p = buildtree(ADDROF, nametree(csym), NIL); + n = il->n; + sym.stype = n->n_type; + sym.squal = n->n_qual; + sym.sdf = n->n_df; + sym.sap = n->n_ap; + sym.soffset = (int)(ll->begsz + il->off); + sym.sclass = (char)(fsz < 0 ? FIELD | -fsz : 0); + r = xbcon(0, &sym, INT); + p = block(STREF, p, r, INT, 0, 0); + ecomp(buildtree(ASSIGN, stref(p), il->n)); + if (fsz < 0) + fsz = -fsz; + + } else { + if (ll->begsz + il->off > lastoff) + zbits(lastoff, + (ll->begsz + il->off) - lastoff); + if (fsz < 0) { + fsz = -fsz; + infld(il->off, fsz, glval(il->n)); + } else + inval(il->off, fsz, il->n); + tfree(il->n); + } + lastoff = ll->begsz + il->off + fsz; + } + } + if (csym->sclass == AUTO) { + clearbf(lastoff, tbit-lastoff); + } else + zbits(lastoff, tbit-lastoff); + + doing_init--; + if (csym->sclass == STATIC || csym->sclass == EXTDEF) + statinit--; + endictx(); +} + +void +endictx(void) +{ + struct initctx *ict = inilnk; + + if (ict == NULL) + return; + + pstk = ict->pstk; + csym = ict->psym; + lpole = ict->lpole; + basesz = ict->basesz; + numents = ict->numents; + inilnk = inilnk->prev; +#ifdef PCC_DEBUG + if (idebug) + printf("endinit: restoring ctx pstk %p\n", pstk); +#endif +} + +/* + * process an initializer's left brace + */ +void +ilbrace(void) +{ +#ifdef PCC_DEBUG + if (idebug) + printf("ilbrace()\n"); +#endif + + if (pstk == NULL) + return; + + stkpush(); + pstk->in_fl = 1; /* mark lbrace */ +#ifdef PCC_DEBUG + if (idebug > 1) + prtstk(pstk); +#endif +} + +/* + * called when a '}' is seen + */ +void +irbrace(void) +{ +#ifdef PCC_DEBUG + if (idebug) + printf("irbrace()\n"); + if (idebug > 2) + prtstk(pstk); +#endif + + if (pstk == NULL) + return; + + /* Got right brace, search for corresponding in the stack */ + for (; pstk->in_prev != NULL; pstk = pstk->in_prev) { + if(!pstk->in_fl) + continue; + + /* we have one now */ + + pstk->in_fl = 0; /* cancel { */ + if (ISARY(pstk->in_t)) + pstk->in_n = pstk->in_df->ddim; + else if (pstk->in_t == STRTY) { + while (pstk->in_lnk != NULL && + pstk->in_lnk->snext != NULL) + pstk->in_lnk = pstk->in_lnk->snext; + } + stkpop(); + return; + } +} + +/* + * Create a new init stack based on given elements. + */ +static void +mkstack(NODE *p) +{ + +#ifdef PCC_DEBUG + if (idebug) { + printf("mkstack: %p\n", p); + if (idebug > 1 && p) + fwalk(p, eprint, 0); + } +#endif + + if (p == NULL) + return; + mkstack(p->n_left); + + switch (p->n_op) { + case LB: /* Array index */ + if (p->n_right->n_op != ICON) + cerror("mkstack"); + if (!ISARY(pstk->in_t)) + uerror("array indexing non-array"); + pstk->in_n = (int)glval(p->n_right); + nfree(p->n_right); + break; + + case NAME: + if (pstk->in_lnk) { + for (; pstk->in_lnk; pstk->in_lnk = pstk->in_lnk->snext) + if (pstk->in_lnk->sname == (char *)p->n_sp) + break; + if (pstk->in_lnk == NULL) + uerror("member missing"); + } else { + uerror("not a struct/union"); + } + break; + default: + cerror("mkstack2"); + } + nfree(p); + stkpush(); + +} + +/* + * Initialize a specific element, as per C99. + */ +void +desinit(NODE *p) +{ + int op = p->n_op; + + if (pstk == NULL) + stkpush(); /* passed end of array */ + while (pstk->in_prev && pstk->in_fl == 0) + pstk = pstk->in_prev; /* Empty stack */ + + if (ISSOU(pstk->in_t)) + pstk->in_lnk = strmemb(pstk->in_sym->sap); + + mkstack(p); /* Setup for assignment */ + + /* pop one step if SOU, ilbrace will push */ + if (op == NAME || op == LB) + pstk = pstk->in_prev; + +#ifdef PCC_DEBUG + if (idebug > 1) { + printf("desinit e\n"); + prtstk(pstk); + } +#endif +} + +/* + * Convert a string to an array of char/wchar for asginit. + */ +static void +strcvt(NODE *p) +{ + NODE *q = p; + char *s; + int i; + +#ifdef mach_arm + /* XXX */ + if (p->n_op == UMUL && p->n_left->n_op == ADDROF) + p = p->n_left->n_left; +#endif + + for (s = p->n_sp->sname; *s != 0; ) { + if (p->n_type == ARY+WCHAR_TYPE) + i = u82cp(&s); + else if (*s == '\\') + i = esccon(&s); + else + i = (unsigned char)*s++; + asginit(bcon(i)); + } + tfree(q); +} + +/* + * Do an assignment to a struct element. + */ +void +asginit(NODE *p) +{ + int g; + +#ifdef PCC_DEBUG + if (idebug) + printf("asginit %p\n", p); + if (idebug > 1 && p) + fwalk(p, eprint, 0); +#endif + + /* convert string to array of char/wchar */ + if (p && (DEUNSIGN(p->n_type) == ARY+CHAR || + p->n_type == ARY+WCHAR_TYPE)) { + struct instk *is; + TWORD t; + + t = p->n_type == ARY+WCHAR_TYPE ? ARY+WCHAR_TYPE : ARY+CHAR; + /* + * ...but only if next element is ARY+CHAR, otherwise + * just fall through. + */ + + /* HACKHACKHACK */ + is = pstk; + + if (pstk == NULL) + stkpush(); + while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) + stkpush(); + if (pstk->in_prev && + (DEUNSIGN(pstk->in_prev->in_t) == t || + pstk->in_prev->in_t == t)) { + pstk = pstk->in_prev; + if ((g = pstk->in_fl) == 0) + pstk->in_fl = 1; /* simulate ilbrace */ + + strcvt(p); + if (g == 0) + irbrace(); /* will fill with zeroes */ + return; + } else + pstk = is; /* no array of char */ + /* END HACKHACKHACK */ + } + + if (p == NULL) { /* only end of compound stmt */ + irbrace(); + } else /* assign next element */ + scalinit(p); +} + +#ifdef PCC_DEBUG +void +prtstk(struct instk *in) +{ + int i, o = 0; + + printf("init stack:\n"); + for (; in != NULL; in = in->in_prev) { + for (i = 0; i < o; i++) + printf(" "); + printf("%p) '%s' ", in, in->in_sym->sname); + tprint(in->in_t, 0); + printf(" %s ", scnames(in->in_sym->sclass)); + if (in->in_df /* && in->in_df->ddim */) + printf("arydim=%d ", in->in_df->ddim); + printf("ninit=%d ", in->in_n); + if (BTYPE(in->in_t) == STRTY || ISARY(in->in_t)) + printf("stsize=%d ", + (int)tsize(in->in_t, in->in_df, in->in_sym->sap)); + if (in->in_fl) printf("{ "); + printf("soff=%d ", in->in_sym->soffset); + if (in->in_t == STRTY) { + if (in->in_lnk) + printf("curel %s ", in->in_lnk->sname); + else + printf("END struct"); + } + printf("\n"); + o++; + } +} +#endif + +/* + * Do a simple initialization. + * At block 0, just print out the value, at higher levels generate + * appropriate code. + */ +void +simpleinit(struct symtab *sp, NODE *p) +{ + NODE *q, *r, *nt; + TWORD t; + int sz; + + /* May be an initialization of an array of char by a string */ + if ((DEUNSIGN(p->n_type) == ARY+CHAR && + DEUNSIGN(sp->stype) == ARY+CHAR) || + (DEUNSIGN(p->n_type) == DEUNSIGN(ARY+WCHAR_TYPE) && + DEUNSIGN(sp->stype) == DEUNSIGN(ARY+WCHAR_TYPE))) { + /* Handle "aaa" as { 'a', 'a', 'a' } */ + beginit(sp); + strcvt(p); + if (csym->sdf->ddim == NOOFFSET) + scalinit(bcon(0)); /* Null-term arrays */ + endinit(0); + return; + } + + nt = nametree(sp); + switch (sp->sclass) { + case STATIC: + case EXTDEF: + q = nt; + locctr(DATA, sp); + defloc(sp); +#ifndef NO_COMPLEX + if (ANYCX(q) || ANYCX(p)) { + r = cxop(ASSIGN, q, p); + /* XXX must unwind the code generated here */ + /* We can rely on correct code generated */ + p = r->n_left->n_right->n_left; + r->n_left->n_right->n_left = bcon(0); + tfree(r); + r = p->n_left->n_right; + sz = (int)tsize(r->n_type, r->n_df, r->n_ap); + inval(0, sz, r); + inval(0, sz, p->n_right->n_right); + tfree(p); + break; + } else if (ISITY(p->n_type) || ISITY(q->n_type)) { + /* XXX merge this with code from imop() */ + int li = 0, ri = 0; + if (ISITY(p->n_type)) + li = 1, p->n_type = p->n_type - (FIMAG-FLOAT); + if (ISITY(q->n_type)) + ri = 1, q->n_type = q->n_type - (FIMAG-FLOAT); + if (!(li && ri)) { + tfree(p); + p = bcon(0); + } + /* continue below */ + } +#endif +#ifdef TARGET_TIMODE + struct attr *ap; + if ((ap = attr_find(sp->sap, GCC_ATYP_MODE)) && + strcmp(ap->aa[0].sarg, "TI") == 0) { + if (p->n_op != ICON) + uerror("need to handle TImode initializer "); + sz = (int)tsize(sp->stype, sp->sdf, sp->sap); + p->n_type = ctype(LONGLONG); + inval(0, sz/2, p); + p->n_lval = 0; /* XXX fix signed types */ + inval(0, sz/2, p); + tfree(p); + tfree(q); + break; + } +#endif + if (p->n_op == NAME && p->n_sp && + (p->n_sp->sflags & SMASK) == SSTRING) + p->n_sp->sflags |= SASG; + p = optloop(buildtree(ASSIGN, nt, p)); + q = p->n_right; + t = q->n_type; + sz = (int)tsize(t, q->n_df, q->n_ap); + inval(0, sz, q); + tfree(p); + break; + + case AUTO: + case REGISTER: + if (ISARY(sp->stype)) + cerror("no array init"); + q = nt; +#ifdef TARGET_TIMODE + if ((r = gcc_eval_timode(ASSIGN, q, p)) != NULL) + ; + else +#endif +#ifndef NO_COMPLEX + + if (ANYCX(q) || ANYCX(p)) + r = cxop(ASSIGN, q, p); + else if (ISITY(p->n_type) || ISITY(q->n_type)) + r = imop(ASSIGN, q, p); + else +#endif + r = buildtree(ASSIGN, q, p); + ecomp(r); + break; + + default: + uerror("illegal initialization"); + } +} diff --git a/lang/pcc/pcc/cc/ccom/inline.c b/lang/pcc/pcc/cc/ccom/inline.c new file mode 100644 index 000000000..7b6f3e8cd --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/inline.c @@ -0,0 +1,667 @@ +/* $Id: inline.c,v 1.65 2015/11/17 19:19:40 ragge Exp $ */ +/* + * Copyright (c) 2003, 2008 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#include + +/* + * Simple description of how the inlining works: + * A function found with the keyword "inline" is always saved. + * If it also has the keyword "extern" it is written out thereafter. + * If it has the keyword "static" it will be written out if it is referenced. + * inlining will only be done if -xinline is given, and only if it is + * possible to inline the function. + */ +static void printip(struct interpass *pole); + +struct ntds { + int temp; + TWORD type; + union dimfun *df; + struct attr *attr; +}; + +/* + * ilink from ipole points to the next struct in the list of functions. + */ +static struct istat { + SLIST_ENTRY(istat) link; + struct symtab *sp; + int flags; +#define CANINL 1 /* function is possible to inline */ +#define WRITTEN 2 /* function is written out */ +#define REFD 4 /* Referenced but not yet written out */ + struct ntds *nt;/* Array of arg temp type data */ + int nargs; /* number of args in array */ + int retval; /* number of return temporary, if any */ + struct interpass shead; +} *cifun; + +static SLIST_HEAD(, istat) ipole = { NULL, &ipole.q_forw }; +static int nlabs, svclass; + +#define IP_REF (MAXIP+1) +#ifdef PCC_DEBUG +#define SDEBUG(x) if (sdebug) printf x +#else +#define SDEBUG(x) +#endif + +int isinlining; +int inlstatcnt; + +#define SZSI sizeof(struct istat) +int istatsz = SZSI; +#define ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++ + +/* + * Get prolog/epilog for a function. + */ +static struct interpass_prolog * +getprol(struct istat *is, int type) +{ + struct interpass *ip; + + DLIST_FOREACH(ip, &is->shead, qelem) + if (ip->type == type) + return (struct interpass_prolog *)ip; + cerror("getprol: %d not found", type); + return 0; /* XXX */ +} + +static struct istat * +findfun(struct symtab *sp) +{ + struct istat *is; + + SLIST_FOREACH(is, &ipole, link) + if (is->sp == sp) + return is; + return NULL; +} + +static void +refnode(struct symtab *sp) +{ + struct interpass *ip; + + SDEBUG(("refnode(%s)\n", sp->sname)); + + ip = permalloc(sizeof(*ip)); + ip->type = IP_REF; + ip->ip_name = (char *)sp; + inline_addarg(ip); +} + +/* + * Save attributes permanent. + */ +static struct attr * +inapcopy(struct attr *ap) +{ + struct attr *nap = attr_dup(ap); + + if (ap->next) + nap->next = inapcopy(ap->next); + return nap; +} + +/* + * Copy a tree onto the permanent heap to save for inline. + */ +static NODE * +intcopy(NODE *p) +{ + NODE *q = permalloc(sizeof(NODE)); + int o = coptype(p->n_op); /* XXX pass2 optype? */ + + *q = *p; + if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) && + regno(p) == FPREG) + SLIST_FIRST(&ipole)->flags &= ~CANINL; /* no stack refs */ + if (q->n_ap) + q->n_ap = inapcopy(q->n_ap); + if (q->n_op == NAME || q->n_op == ICON || + q->n_op == XASM || q->n_op == XARG) { + if (*q->n_name) + q->n_name = xstrdup(q->n_name); /* XXX permstrdup */ + else + q->n_name = ""; + } + if (o == BITYPE) + q->n_right = intcopy(q->n_right); + if (o != LTYPE) + q->n_left = intcopy(q->n_left); + return q; +} + +void +inline_addarg(struct interpass *ip) +{ + struct interpass_prolog *ipp; + NODE *q; + static int g = 0; + extern P1ND *cftnod; + + SDEBUG(("inline_addarg(%p)\n", ip)); + DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem); + switch (ip->type) { + case IP_ASM: + ip->ip_asm = xstrdup(ip->ip_asm); + break; + case IP_DEFLAB: + nlabs++; + break; + case IP_NODE: + q = ip->ip_node; + ip->ip_node = intcopy(ip->ip_node); + tfree(q); + break; + case IP_EPILOG: + ipp = (struct interpass_prolog *)ip; + if (ipp->ip_labels[0]) + uerror("no computed goto in inlined functions"); + ipp->ip_labels = &g; + break; + } + if (cftnod) + cifun->retval = regno(cftnod); +} + +/* + * Called to setup for inlining of a new function. + */ +void +inline_start(struct symtab *sp, int class) +{ + struct istat *is; + + SDEBUG(("inline_start(\"%s\")\n", sp->sname)); + + if (isinlining) + cerror("already inlining function"); + + svclass = class; + if ((is = findfun(sp)) != 0) { + if (!DLIST_ISEMPTY(&is->shead, qelem)) + uerror("inline function already defined"); + } else { + is = ialloc(); + is->sp = sp; + SLIST_INSERT_FIRST(&ipole, is, link); + DLIST_INIT(&is->shead, qelem); + } + cifun = is; + nlabs = 0; + isinlining++; +} + +/* + * End of an inline function. In C99 an inline function declared "extern" + * should also have external linkage and are therefore printed out. + * + * Gcc inline syntax is a mess, see matrix below on emitting functions: + * without extern + * -std= - gnu89 gnu99 + * gcc 3.3.5: ja ja ja + * gcc 4.1.3: ja ja ja + * gcc 4.3.1 ja ja nej + * + * with extern + * gcc 3.3.5: nej nej nej + * gcc 4.1.3: nej nej nej + * gcc 4.3.1 nej nej ja + * + * The above is only true if extern is given on the same line as the + * function declaration. If given as a separate definition it do not count. + * + * The attribute gnu_inline sets gnu89 behaviour. + * Since pcc mimics gcc 4.3.1 that is the behaviour we emulate. + */ +void +inline_end(void) +{ + struct symtab *sp = cifun->sp; + + SDEBUG(("inline_end()\n")); + + if (sdebug)printip(&cifun->shead); + isinlining = 0; + + if (xgnu89 && svclass == SNULL) + sp->sclass = EXTERN; + +#ifdef GCC_COMPAT + if (sp->sclass != STATIC && + (attr_find(sp->sap, GCC_ATYP_GNU_INLINE) || xgnu89)) { + if (sp->sclass == EXTDEF) + sp->sclass = EXTERN; + else + sp->sclass = EXTDEF; + } +#endif + + if (sp->sclass == EXTDEF) { + cifun->flags |= REFD; + inline_prtout(); + } +} + +/* + * Called when an inline function is found, to be sure that it will + * be written out. + * The function may not be defined when inline_ref() is called. + */ +void +inline_ref(struct symtab *sp) +{ + struct istat *w; + + SDEBUG(("inline_ref(\"%s\")\n", sp->sname)); + if (sp->sclass == SNULL) + return; /* only inline, no references */ + if (isinlining) { + refnode(sp); + } else { + SLIST_FOREACH(w,&ipole, link) { + if (w->sp != sp) + continue; + w->flags |= REFD; + return; + } + /* function not yet defined, print out when found */ + w = ialloc(); + w->sp = sp; + w->flags |= REFD; + SLIST_INSERT_FIRST(&ipole, w, link); + DLIST_INIT(&w->shead, qelem); + } +} + +static void +puto(struct istat *w) +{ + struct interpass_prolog *ipp, *epp, *pp; + struct interpass *ip, *nip; + extern int crslab; + int lbloff = 0; + + /* Copy the saved function and print it out */ + ipp = 0; /* XXX data flow analysis */ + DLIST_FOREACH(ip, &w->shead, qelem) { + switch (ip->type) { + case IP_EPILOG: + case IP_PROLOG: + if (ip->type == IP_PROLOG) { + ipp = (struct interpass_prolog *)ip; + /* fix label offsets */ + lbloff = crslab - ipp->ip_lblnum; + } else { + epp = (struct interpass_prolog *)ip; + crslab += (epp->ip_lblnum - ipp->ip_lblnum); + } + pp = xmalloc(sizeof(struct interpass_prolog)); + memcpy(pp, ip, sizeof(struct interpass_prolog)); + pp->ip_lblnum += lbloff; +#ifdef PCC_DEBUG + if (ip->type == IP_EPILOG && crslab != pp->ip_lblnum) + cerror("puto: %d != %d", crslab, pp->ip_lblnum); +#endif + pass2_compile((struct interpass *)pp); + break; + + case IP_REF: + inline_ref((struct symtab *)ip->ip_name); + break; + + default: + nip = xmalloc(sizeof(struct interpass)); + *nip = *ip; + if (nip->type == IP_NODE) { + NODE *p; + + p = nip->ip_node = tcopy(nip->ip_node); + if (p->n_op == GOTO) + slval(p->n_left, + glval(p->n_left) + lbloff); + else if (p->n_op == CBRANCH) + slval(p->n_right, + glval(p->n_right) + lbloff); + } else if (nip->type == IP_DEFLAB) + nip->ip_lbl += lbloff; + pass2_compile(nip); + break; + } + } + w->flags |= WRITTEN; +} + +/* + * printout functions that are referenced. + */ +void +inline_prtout(void) +{ + struct istat *w; + int gotone = 0; + + SLIST_FOREACH(w, &ipole, link) { + if ((w->flags & (REFD|WRITTEN)) == REFD && + !DLIST_ISEMPTY(&w->shead, qelem)) { + locctr(PROG, w->sp); + defloc(w->sp); + puto(w); + w->flags |= WRITTEN; + gotone++; + } + } + if (gotone) + inline_prtout(); +} + +#if 1 +static void +printip(struct interpass *pole) +{ + static char *foo[] = { + 0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" }; + struct interpass *ip; + struct interpass_prolog *ipplg, *epplg; + + DLIST_FOREACH(ip, pole, qelem) { + if (ip->type > MAXIP) + printf("IP(%d) (%p): ", ip->type, ip); + else + printf("%s (%p): ", foo[ip->type], ip); + switch (ip->type) { + case IP_NODE: printf("\n"); +#ifdef PCC_DEBUG +#ifndef TWOPASS + { extern void e2print(NODE *p, int down, int *a, int *b); + fwalk(ip->ip_node, e2print, 0); break; } +#endif +#endif + case IP_PROLOG: + ipplg = (struct interpass_prolog *)ip; + printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n", + ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "", + (long)ipplg->ipp_regs[0], ipplg->ipp_autos, + ipplg->ip_tmpnum, ipplg->ip_lblnum); + break; + case IP_EPILOG: + epplg = (struct interpass_prolog *)ip; + printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n", + epplg->ipp_name, epplg->ipp_vis ? "(local)" : "", + (long)epplg->ipp_regs[0], epplg->ipp_autos, + epplg->ip_tmpnum, epplg->ip_lblnum); + break; + case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break; + case IP_DEFNAM: printf("\n"); break; + case IP_ASM: printf("%s", ip->ip_asm); break; + default: + break; + } + } +} +#endif + +static int toff; + +static P1ND * +mnode(struct ntds *nt, P1ND *p) +{ + P1ND *q; + int num = nt->temp + toff; + + if (p->n_op == CM) { + q = p->n_right; + q = tempnode(num, nt->type, nt->df, nt->attr); + nt--; + p->n_right = buildtree(ASSIGN, q, p->n_right); + p->n_left = mnode(nt, p->n_left); + p->n_op = COMOP; + } else { + p = pconvert(p); + q = tempnode(num, nt->type, nt->df, nt->attr); + p = buildtree(ASSIGN, q, p); + } + return p; +} + +static void +rtmps(NODE *p, void *arg) +{ + if (p->n_op == TEMP) + regno(p) += toff; +} + +/* + * Inline a function. Returns the return value. + * There are two major things that must be converted when + * inlining a function: + * - Label numbers must be updated with an offset. + * - The stack block must be relocated (add to REG or OREG). + * - Temporaries should be updated (but no must) + * + * Extra tricky: The call is P1ND, nut the resulting tree is already NODE... + */ +P1ND * +inlinetree(struct symtab *sp, P1ND *f, P1ND *ap) +{ + extern int crslab, tvaloff; + struct istat *is = findfun(sp); + struct interpass *ip, *ipf, *ipl; + struct interpass_prolog *ipp, *ipe; + int lmin, l0, l1, l2, gainl, n; + NODE *pp; + P1ND *p, *rp; + + if (is == NULL || nerrors) { + inline_ref(sp); /* prototype of not yet declared inline ftn */ + return NULL; + } + + SDEBUG(("inlinetree(%p,%p) OK %d\n", f, ap, is->flags & CANINL)); + +#ifdef GCC_COMPAT + gainl = attr_find(sp->sap, GCC_ATYP_ALW_INL) != NULL; +#else + gainl = 0; +#endif + + n = nerrors; + if ((is->flags & CANINL) == 0 && gainl) + werror("cannot inline but always_inline"); + nerrors = n; + + if ((is->flags & CANINL) == 0 || (xinline == 0 && gainl == 0)) { + if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC) + inline_ref(sp); + return NULL; + } + + if (isinlining && cifun->sp == sp) { + /* Do not try to inline ourselves */ + inline_ref(sp); + return NULL; + } + +#ifdef mach_i386 + if (kflag) { + is->flags |= REFD; /* if static inline, emit */ + return NULL; /* XXX cannot handle hidden ebx arg */ + } +#endif + + /* emit jumps to surround inline function */ + branch(l0 = getlab()); + plabel(l1 = getlab()); + l2 = getlab(); + SDEBUG(("branch labels %d,%d,%d\n", l0, l1, l2)); + + /* From here it is NODE */ + + ipp = getprol(is, IP_PROLOG); + ipe = getprol(is, IP_EPILOG); + + /* Fix label & temp offsets */ + + SDEBUG(("pre-offsets crslab %d tvaloff %d\n", crslab, tvaloff)); + lmin = crslab - ipp->ip_lblnum; + crslab += (ipe->ip_lblnum - ipp->ip_lblnum) + 2; + toff = tvaloff - ipp->ip_tmpnum; + tvaloff += (ipe->ip_tmpnum - ipp->ip_tmpnum) + 1; + SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n", + crslab, lmin, tvaloff, toff)); + + /* traverse until first real label */ + n = 0; + DLIST_FOREACH(ipf, &is->shead, qelem) { + if (ipf->type == IP_REF) + inline_ref((struct symtab *)ipf->ip_name); + if (ipf->type == IP_DEFLAB && n++ == 1) + break; + } + + /* traverse backwards to last label */ + DLIST_FOREACH_REVERSE(ipl, &is->shead, qelem) { + if (ipl->type == IP_REF) + inline_ref((struct symtab *)ipl->ip_name); + if (ipl->type == IP_DEFLAB) + break; + } + + /* So, walk over all statements and emit them */ + for (ip = ipf; ip != ipl; ip = DLIST_NEXT(ip, qelem)) { + switch (ip->type) { + case IP_NODE: + pp = tcopy(ip->ip_node); + if (pp->n_op == GOTO) + slval(pp->n_left, glval(pp->n_left) + lmin); + else if (pp->n_op == CBRANCH) + slval(pp->n_right, glval(pp->n_right) + lmin); + walkf(pp, rtmps, 0); +#ifdef PCC_DEBUG +#ifndef TWOPASS + if (sdebug) { + extern void e2print(NODE *p, int down, int *a, int *b); + printf("converted node\n"); + fwalk(ip->ip_node, e2print, 0); + fwalk(pp, e2print, 0); + } +#endif +#endif + send_passt(IP_NODE, pp); + break; + + case IP_DEFLAB: + SDEBUG(("converted label %d to %d\n", + ip->ip_lbl, ip->ip_lbl + lmin)); + send_passt(IP_DEFLAB, ip->ip_lbl + lmin); + break; + + case IP_ASM: + send_passt(IP_ASM, ip->ip_asm); + break; + + case IP_REF: + inline_ref((struct symtab *)ip->ip_name); + break; + + default: + cerror("bad inline stmt %d", ip->type); + } + } + SDEBUG(("last label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin)); + send_passt(IP_DEFLAB, ip->ip_lbl + lmin); + + branch(l2); + plabel(l0); + + /* Here we are P1ND again */ + rp = block(GOTO, bcon(l1), NULL, INT, 0, 0); + if (is->retval) + p = tempnode(is->retval + toff, DECREF(sp->stype), + sp->sdf, sp->sap); + else + p = xbcon(0, NULL, DECREF(sp->stype)); + rp = buildtree(COMOP, rp, p); + + if (is->nargs) { + p = mnode(&is->nt[is->nargs-1], ap); + rp = buildtree(COMOP, p, rp); + } + + p1tfree(f); + return rp; +} + +void +inline_args(struct symtab **sp, int nargs) +{ + union arglist *al; + struct istat *cf; + TWORD t; + int i; + + SDEBUG(("inline_args\n")); + cf = cifun; + /* + * First handle arguments. We currently do not inline anything if: + * - function has varargs + * - function args are volatile, checked if no temp node is asg'd. + */ + /* XXX - this is ugly, invent something better */ + if (cf->sp->sdf->dfun == NULL) + return; /* no prototype */ + for (al = cf->sp->sdf->dfun; al->type != TNULL; al++) { + t = al->type; + if (t == TELLIPSIS) + return; /* cannot inline */ + if (ISSOU(BTYPE(t))) + al++; + for (; t > BTMASK; t = DECREF(t)) + if (ISARY(t) || ISFTN(t)) + al++; + } + + if (nargs) { + for (i = 0; i < nargs; i++) + if ((sp[i]->sflags & STNODE) == 0) + return; /* not temporary */ + cf->nt = permalloc(sizeof(struct ntds)*nargs); + for (i = 0; i < nargs; i++) { + cf->nt[i].temp = sp[i]->soffset; + cf->nt[i].type = sp[i]->stype; + cf->nt[i].df = sp[i]->sdf; + cf->nt[i].attr = sp[i]->sap; + } + } + cf->nargs = nargs; + cf->flags |= CANINL; +} diff --git a/lang/pcc/pcc/cc/ccom/main.c b/lang/pcc/pcc/cc/ccom/main.c new file mode 100644 index 000000000..70f32a7df --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/main.c @@ -0,0 +1,431 @@ +/* $Id: main.c,v 1.133 2016/02/21 11:04:01 ragge Exp $ */ + +/* + * Copyright (c) 2002 Anders Magnusson. All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "config.h" + +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#include "pass1.h" +#include "pass2.h" + +int bdebug, ddebug, edebug, idebug, ndebug; +int odebug, pdebug, sdebug, tdebug, xdebug, wdebug; +int b2debug, c2debug, e2debug, f2debug, g2debug, o2debug; +int r2debug, s2debug, t2debug, u2debug, x2debug; +int gflag, kflag; +int pflag, sflag; +int sspflag; +int xssa, xtailcall, xtemps, xdeljumps, xdce, xinline, xccp, xgnu89, xgnu99; +int xuchar; +int freestanding; +char *prgname, *ftitle; + +static void prtstats(void); + +static void +usage(void) +{ + (void)fprintf(stderr, "usage: %s [option] [infile] [outfile]...\n", + prgname); + exit(1); +} + +static void +segvcatch(int a) +{ + char buf[1024]; + + snprintf(buf, sizeof buf, "%sinternal compiler error: %s, line %d\n", + nerrors ? "" : "major ", ftitle, lineno); + (void)write(STDERR_FILENO, buf, strlen(buf)); + _exit(1); +} + +static void +xopt(char *str) +{ + if (strcmp(str, "ssa") == 0) + xssa++; + else if (strcmp(str, "tailcall") == 0) + xtailcall++; + else if (strcmp(str, "temps") == 0) + xtemps++; + else if (strcmp(str, "deljumps") == 0) + xdeljumps++; + else if (strcmp(str, "dce") == 0) + xdce++; + else if (strcmp(str, "inline") == 0) + xinline++; + else if (strcmp(str, "ccp") == 0) + xccp++; + else if (strcmp(str, "gnu89") == 0) + xgnu89++; + else if (strcmp(str, "gnu99") == 0) + xgnu99++; + else if (strcmp(str, "uchar") == 0) + xuchar++; + else { + fprintf(stderr, "unknown -x option '%s'\n", str); + usage(); + } +} + +static void +fflags(char *str) +{ + int flagval = 1; + + if (strncmp("no-", str, 3) == 0) { + str += 3; + flagval = 0; + } + +#ifndef PASS2 + if (strcmp(str, "stack-protector") == 0) + sspflag = flagval; + else if (strcmp(str, "stack-protector-all") == 0) + sspflag = flagval; + else if (strncmp(str, "pack-struct", 11) == 0) + pragma_allpacked = (strlen(str) > 12 ? atoi(str+12) : 1); + else if (strcmp(str, "freestanding") == 0) + freestanding = flagval; + else { + fprintf(stderr, "unknown -f option '%s'\n", str); + usage(); + } +#endif +} + +/* control multiple files */ +int +main(int argc, char *argv[]) +{ + int ch; + +//kflag = 1; +#ifdef TIMING + struct timeval t1, t2; + + (void)gettimeofday(&t1, NULL); +#endif + + prgname = argv[0]; + + while ((ch = getopt(argc, argv, "OT:VW:X:Z:f:gkm:psvwx:")) != -1) { + switch (ch) { +#ifndef PASS2 + case 'X': /* pass1 debugging */ + while (*optarg) + switch (*optarg++) { + case 'b': ++bdebug; break; /* buildtree */ + case 'd': ++ddebug; break; /* declarations */ + case 'e': ++edebug; break; /* pass1 exit */ + case 'i': ++idebug; break; /* initializations */ + case 'n': ++ndebug; break; /* node allocation */ + case 'o': ++odebug; break; /* optim */ + case 'p': ++pdebug; break; /* prototype */ + case 's': ++sdebug; break; /* inline */ + case 't': ++tdebug; break; /* type match */ + case 'x': ++xdebug; break; /* MD code */ + default: + fprintf(stderr, "unknown -X flag '%c'\n", + optarg[-1]); + exit(1); + } + break; +#endif +#ifndef PASS1 + case 'Z': /* pass2 debugging */ + while (*optarg) + switch (*optarg++) { + case 'b': /* basic block and SSA building */ + ++b2debug; + break; + case 'c': /* code printout */ + ++c2debug; + break; + case 'e': /* print tree upon pass2 enter */ + ++e2debug; + break; + case 'f': /* instruction matching */ + ++f2debug; + break; + case 'g': /* print flow graphs */ + ++g2debug; + break; + case 'n': /* node allocation */ + ++ndebug; + break; + case 'o': /* instruction generator */ + ++o2debug; + break; + case 'r': /* register alloc/graph coloring */ + ++r2debug; + break; + case 's': /* shape matching */ + ++s2debug; + break; + case 't': /* type matching */ + ++t2debug; + break; + case 'u': /* Sethi-Ullman debugging */ + ++u2debug; + break; + case 'x': /* target specific */ + ++x2debug; + break; + default: + fprintf(stderr, "unknown -Z flag '%c'\n", + optarg[-1]); + exit(1); + } + break; +#endif + case 'f': /* Language */ + fflags(optarg); + break; + + case 'g': /* Debugging */ + ++gflag; + break; + + case 'k': /* PIC code */ + ++kflag; + break; + + case 'm': /* Target-specific */ + mflags(optarg); + break; + + case 'p': /* Profiling */ + ++pflag; + break; + + case 's': /* Statistics */ + ++sflag; + break; + + case 'w': /* No warnings emitted */ + ++wdebug; + break; + + case 'W': /* Enable different warnings */ + Wflags(optarg); + break; + + case 'x': /* Different settings */ + xopt(optarg); + break; + + case 'v': + printf("ccom: %s\n", VERSSTR); + break; + + case '?': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + ftitle = xstrdup(""); + if (argc > 0 && strcmp(argv[0], "-") != 0) { + if (freopen(argv[0], "r", stdin) == NULL) { + fprintf(stderr, "open input file '%s':", + argv[0]); + perror(NULL); + exit(1); + } + } + if (argc > 1 && strcmp(argv[1], "-") != 0) { + if (freopen(argv[1], "w", stdout) == NULL) { + fprintf(stderr, "open output file '%s':", + argv[1]); + perror(NULL); + exit(1); + } + } + + mkdope(); + signal(SIGSEGV, segvcatch); +#ifdef SIGBUS + signal(SIGBUS, segvcatch); +#endif + +#ifndef PASS2 + lineno = 1; +#ifdef GCC_COMPAT + gcc_init(); +#endif + + /* starts past any of the above */ + reached = 1; + + bjobcode(); +#ifndef TARGET_VALIST + { + P1ND *p = block(NAME, NULL, NULL, PTR|CHAR, NULL, 0); + struct symtab *sp = lookup(addname("__builtin_va_list"), 0); + p->n_sp = sp; + defid(p, TYPEDEF); + p1nfree(p); + } +#endif + complinit(); + kwinit(); +#ifndef NO_BUILTIN + builtin_init(); +#endif + +#ifdef DWARF + if (gflag) + dwarf_init(argc ? argv[0] : ""); +#endif +#ifdef STABS + if (gflag) { + stabs_file(argc ? argv[0] : ""); + stabs_init(); + } +#endif + + if (sspflag) + sspinit(); +#endif /* PASS2 */ + +#ifndef PASS1 + fregs = FREGS; /* number of free registers */ +#ifdef PASS2 + mainp2(); +#endif +#endif + +#ifndef PASS2 + (void) yyparse(); + yyaccpt(); + + if (!nerrors) { + lcommprint(); +#ifndef NO_STRING_SAVE + strprint(); +#endif + } +#endif + +#ifndef PASS2 +#ifdef STABS + if (gflag) + stabs_efile(argc ? argv[0] : ""); +#endif + ejobcode( nerrors ? 1 : 0 ); +#endif + +#ifdef TIMING + (void)gettimeofday(&t2, NULL); + t2.tv_sec -= t1.tv_sec; + t2.tv_usec -= t1.tv_usec; + if (t2.tv_usec < 0) { + t2.tv_usec += 1000000; + t2.tv_sec -= 1; + } + fprintf(stderr, "ccom total time: %ld s %ld us\n", + t2.tv_sec, t2.tv_usec); +#endif +#ifdef DWARF + if (gflag) + dwarf_end(); +#endif + + if (sflag) + prtstats(); + + return(nerrors?1:0); +} + +void +prtstats(void) +{ +#ifndef PASS2 + extern int nametabs, namestrlen, treestrsz; + extern int arglistcnt, dimfuncnt, inlstatcnt; + extern int symtabcnt, suedefcnt, strtabs, strstrlen; + extern int blkalloccnt, lcommsz, istatsz; + extern int savstringsz, newattrsz, nodesszcnt, symtreecnt; +#endif + extern size_t permallocsize, tmpallocsize, lostmem; + + /* common allocations */ + fprintf(stderr, "Permanent allocated memory: %zu B\n", permallocsize); + fprintf(stderr, "Temporary allocated memory: %zu B\n", tmpallocsize); + fprintf(stderr, "Lost memory: %zu B\n", lostmem); + +#ifndef PASS2 + /* pass1 allocations */ + fprintf(stderr, "Name table entries: %d pcs\n", nametabs); + fprintf(stderr, "String table entries: %d pcs\n", strtabs); + fprintf(stderr, "Argument list unions: %d pcs\n", arglistcnt); + fprintf(stderr, "Dimension/function unions: %d pcs\n", dimfuncnt); + fprintf(stderr, "Struct/union/enum blocks: %d pcs\n", suedefcnt); + fprintf(stderr, "Inline control blocks: %d pcs\n", inlstatcnt); + fprintf(stderr, "Permanent symtab entries: %d pcs\n", symtabcnt); + fprintf(stderr, "\n"); + fprintf(stderr, "Name table tree size: %d B\n", + nametabs * treestrsz); + fprintf(stderr, "Name string size: %d B\n", namestrlen); + fprintf(stderr, "String table tree size: %d B\n", + strtabs * treestrsz); + fprintf(stderr, "String size: %d B\n", strstrlen); + fprintf(stderr, "Inline control block size: %d B\n", + inlstatcnt * istatsz); + fprintf(stderr, "Argument list size: %d B\n", + arglistcnt * (int)sizeof(union arglist)); + fprintf(stderr, "Dimension/function size: %d B\n", + dimfuncnt * (int)sizeof(union dimfun)); + fprintf(stderr, "Permanent symtab size: %d B\n", + symtabcnt * (int)sizeof(struct symtab)); + fprintf(stderr, "Symtab tree size: %d B\n", + symtreecnt * treestrsz); + fprintf(stderr, "lcomm struct size: %d B\n", lcommsz); + fprintf(stderr, "blkalloc size: %d B\n", blkalloccnt); + fprintf(stderr, "(saved strings size): %d B\n", savstringsz); + fprintf(stderr, "attribute size: %d B\n", newattrsz); + fprintf(stderr, "nodes size: %d B\n", nodesszcnt); + fprintf(stderr, "\n"); + fprintf(stderr, "Not accounted for: %d B\n", + (int)permallocsize-(nametabs * treestrsz)-namestrlen-strstrlen- + (arglistcnt * (int)sizeof(union arglist))-(strtabs * treestrsz)- + (dimfuncnt * (int)sizeof(union dimfun))-(inlstatcnt * istatsz)- + (symtabcnt * (int)sizeof(struct symtab))-(symtreecnt * treestrsz)- + lcommsz-blkalloccnt-newattrsz-nodesszcnt); +#endif +} diff --git a/lang/pcc/pcc/cc/ccom/optim.c b/lang/pcc/pcc/cc/ccom/optim.c new file mode 100644 index 000000000..b91e6cd7a --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/optim.c @@ -0,0 +1,499 @@ +/* $Id: optim.c,v 1.61 2016/02/09 17:57:35 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "pass1.h" + +#define NODE P1ND +#define nfree p1nfree +#define tfree p1tfree + +# define SWAP(p,q) {sp=p; p=q; q=sp;} +# define RCON(p) (p->n_right->n_op==ICON) +# define RO(p) p->n_right->n_op +# define RV(p) getlval(p->n_right) +# define LCON(p) (p->n_left->n_op==ICON) +# define LO(p) p->n_left->n_op +# define LV(p) getlval(p->n_left) + +/* remove left node */ +static NODE * +zapleft(NODE *p) +{ + NODE *q; + + q = p->n_left; + nfree(p->n_right); + nfree(p); + return q; +} + +/* + * fortran function arguments + */ +static NODE * +fortarg(NODE *p) +{ + if( p->n_op == CM ){ + p->n_left = fortarg( p->n_left ); + p->n_right = fortarg( p->n_right ); + return(p); + } + + while( ISPTR(p->n_type) ){ + p = buildtree( UMUL, p, NIL ); + } + return( optim(p) ); +} + + /* mapping relationals when the sides are reversed */ +short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT }; + +/* + * local optimizations, most of which are probably + * machine independent + */ +NODE * +optim(NODE *p) +{ + int o, ty; + NODE *sp, *q; + OFFSZ sz; + int i; + + if (odebug) return(p); + + ty = coptype(p->n_op); + if( ty == LTYPE ) return(p); + + if( ty == BITYPE ) p->n_right = optim(p->n_right); + p->n_left = optim(p->n_left); + + /* collect constants */ +again: o = p->n_op; + switch(o){ + + case SCONV: + if (concast(p->n_left, p->n_type)) { + q = p->n_left; + nfree(p); + p = q; + break; + } + /* FALLTHROUGH */ + case PCONV: + if (p->n_type != VOID) + p = clocal(p); + break; + + case FORTCALL: + p->n_right = fortarg( p->n_right ); + break; + + case ADDROF: + if (LO(p) == TEMP) + break; + if( LO(p) != NAME ) cerror( "& error" ); + + if( !andable(p->n_left) && !statinit) + break; + + LO(p) = ICON; + + setuleft: + /* paint over the type of the left hand side with the type of the top */ + p->n_left->n_type = p->n_type; + p->n_left->n_df = p->n_df; + p->n_left->n_ap = p->n_ap; + q = p->n_left; + nfree(p); + p = q; + break; + + case NOT: + case UMINUS: + case COMPL: + if (LCON(p) && conval(p->n_left, o, p->n_left)) + p = nfree(p); + break; + + case UMUL: + /* Do not discard ADDROF TEMP's */ + if (LO(p) == ADDROF && LO(p->n_left) != TEMP) { + q = p->n_left->n_left; + nfree(p->n_left); + nfree(p); + p = q; + break; + } + if( LO(p) != ICON ) break; + LO(p) = NAME; + goto setuleft; + + case RS: + if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right)) + goto zapright; + + sz = tsize(p->n_type, p->n_df, p->n_ap); + + if (LO(p) == RS && RCON(p->n_left) && RCON(p) && + (RV(p) + RV(p->n_left)) < sz) { + /* two right-shift by constants */ + RV(p) += RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#if 0 + else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { + RV(p) -= RV(p->n_left); + if (RV(p) < 0) + o = p->n_op = LS, RV(p) = -RV(p); + p->n_left = zapleft(p->n_left); + } +#endif + if (RO(p) == ICON) { + if (RV(p) < 0) { + RV(p) = -RV(p); + p->n_op = LS; + goto again; + } +#ifdef notyet /* must check for side effects, --a >> 32; */ + if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) && + ISUNSIGNED(p->n_type)) { /* ignore signed shifts */ + /* too many shifts */ + tfree(p->n_left); + nfree(p->n_right); + p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL; + } else +#endif + /* avoid larger shifts than type size */ + if (RV(p) >= sz) + werror("shift larger than type"); + if (RV(p) == 0) + p = zapleft(p); + } + break; + + case LS: + if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right)) + goto zapright; + + sz = tsize(p->n_type, p->n_df, p->n_ap); + + if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { + /* two left-shift by constants */ + RV(p) += RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#if 0 + else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) { + RV(p) -= RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#endif + if (RO(p) == ICON) { + if (RV(p) < 0) { + RV(p) = -RV(p); + p->n_op = RS; + goto again; + } +#ifdef notyet /* must check for side effects */ + if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) { + /* too many shifts */ + tfree(p->n_left); + nfree(p->n_right); + p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL; + } else +#endif + /* avoid larger shifts than type size */ + if (RV(p) >= sz) + werror("shift larger than type"); + if (RV(p) == 0) + p = zapleft(p); + } + break; + + case QUEST: + if (!LCON(p)) + break; + if (LV(p) == 0) { + q = p->n_right->n_right; + } else { + q = p->n_right->n_left; + p->n_right->n_left = p->n_right->n_right; + } + p->n_right->n_op = UMUL; /* for tfree() */ + tfree(p); + p = q; + break; + + case MINUS: + if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) { + /* link-time constants, but both are the same */ + /* solve it now by forgetting the symbols */ + p->n_left->n_sp = p->n_right->n_sp = NULL; + } + if( !nncon(p->n_right) ) break; + RV(p) = -RV(p); + o = p->n_op = PLUS; + /* FALLTHROUGH */ + case MUL: + /* + * Check for u=(x-y)+z; where all vars are pointers to + * the same struct. This has two advantages: + * 1: avoid a mul+div + * 2: even if not allowed, people may get surprised if this + * calculation do not give correct result if using + * unaligned structs. + */ + if (o == MUL && p->n_type == INTPTR && RCON(p) && + LO(p) == DIV && RCON(p->n_left) && + RV(p) == RV(p->n_left) && + LO(p->n_left) == MINUS) { + q = p->n_left->n_left; + if (q->n_left->n_type == PTR+STRTY && + q->n_right->n_type == PTR+STRTY && + strmemb(q->n_left->n_ap) == + strmemb(q->n_right->n_ap)) { + p = zapleft(p); + p = zapleft(p); + } + } + /* FALLTHROUGH */ + case PLUS: + case AND: + case OR: + case ER: + /* commutative ops; for now, just collect constants */ + /* someday, do it right */ + if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) ) + SWAP( p->n_left, p->n_right ); + /* make ops tower to the left, not the right */ + if( RO(p) == o ){ + SWAP(p->n_left, p->n_right); +#ifdef notdef + /* Yetch, this breaks type correctness in trees */ + /* Code was probably written before types */ + /* All we can do here is swap and pray */ + NODE *t1, *t2, *t3; + t1 = p->n_left; + sp = p->n_right; + t2 = sp->n_left; + t3 = sp->n_right; + /* now, put together again */ + p->n_left = sp; + sp->n_left = t1; + sp->n_right = t2; + sp->n_type = p->n_type; + p->n_right = t3; +#endif + } + if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) && + conval(p->n_right, MINUS, p->n_left->n_right)){ + zapleft: + + q = p->n_left->n_left; + nfree(p->n_left->n_right); + nfree(p->n_left); + p->n_left = q; + } + if( RCON(p) && LO(p)==o && RCON(p->n_left) && + conval( p->n_right, o, p->n_left->n_right ) ){ + goto zapleft; + } + else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){ + zapright: + nfree(p->n_right); + q = makety(p->n_left, p->n_type, p->n_qual, + p->n_df, p->n_ap); + nfree(p); + p = clocal(q); + break; + } + + /* change muls to shifts */ + + if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){ + if( i == 0 ) { /* multiplication by 1 */ + goto zapright; + } + o = p->n_op = LS; + p->n_right->n_type = INT; + p->n_right->n_df = NULL; + RV(p) = i; + } + + /* change +'s of negative consts back to - */ + if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){ + RV(p) = -RV(p); + o = p->n_op = MINUS; + } + + /* remove ops with RHS 0 */ + if ((o == PLUS || o == MINUS || o == OR || o == ER) && + nncon(p->n_right) && RV(p) == 0) { + goto zapright; + } + break; + + case DIV: + if( nncon( p->n_right ) && getlval(p->n_right) == 1 ) + goto zapright; + if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right)) + goto zapright; + if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) { + p->n_op = RS; + RV(p) = i; + q = p->n_right; + if(tsize(q->n_type, q->n_df, q->n_ap) > SZINT) + p->n_right = makety(q, INT, 0, 0, 0); + + break; + } + break; + + case MOD: + if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) { + p->n_op = AND; + RV(p) = RV(p) -1; + break; + } + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + case ULT: + case ULE: + case UGT: + case UGE: + if (LCON(p) && RCON(p) && + !ISPTR(p->n_left->n_type) && !ISPTR(p->n_right->n_type)) { + /* Do constant evaluation */ + q = p->n_left; + if (conval(q, o, p->n_right)) { + nfree(p->n_right); + nfree(p); + p = q; + break; + } + } + + if( !LCON(p) ) break; + + /* exchange operands */ + + sp = p->n_left; + p->n_left = p->n_right; + p->n_right = sp; + p->n_op = revrel[p->n_op - EQ ]; + break; + + case CBRANCH: + if (LCON(p)) { + if (LV(p) == 0) { + tfree(p); + p = bcon(0); + } else { + tfree(p->n_left); + p->n_left = p->n_right; + p->n_op = GOTO; + } + } + break; + + +#ifdef notyet + case ASSIGN: + /* Simple test to avoid two branches */ + if (RO(p) != NE) + break; + q = p->n_right; + if (RCON(q) && RV(q) == 0 && LO(q) == AND && + RCON(q->n_left) && (i = ispow2(RV(q->n_left))) && + q->n_left->n_type == INT) { + q->n_op = RS; + RV(q) = i; + } + break; +#endif + + case ANDAND: + if (!nncon(p->n_left)) + break; + if (LV(p) == 0) { /* right not evaluated */ + p1walkf(p, putjops, 0); + p1tfree(p); + p = bcon(0); + } else { + q = p->n_right; + nfree(nfree(p)); + p = cast(q, INT, 0); + } + break; + case OROR: + if (!nncon(p->n_left)) + break; + if (LV(p) != 0) { /* right not evaluated */ + p1walkf(p, putjops, 0); + p1tfree(p); + p = bcon(1); + } else { + q = p->n_right; + nfree(nfree(p)); + p = cast(q, INT, 0); + } + break; + } + + return(p); + } + +int +ispow2(CONSZ c) +{ + int i; + if( c <= 0 || (c&(c-1)) ) return(-1); + for( i=0; c>1; ++i) c >>= 1; + return(i); +} + +int +nncon(NODE *p) +{ + /* is p a constant without a name */ + return( p->n_op == ICON && p->n_sp == NULL ); +} diff --git a/lang/pcc/pcc/cc/ccom/pass1.h b/lang/pcc/pcc/cc/ccom/pass1.h new file mode 100644 index 000000000..335716fdb --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/pass1.h @@ -0,0 +1,771 @@ +/* $Id: pass1.h,v 1.295 2016/03/08 18:17:45 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "config.h" + +#include +#include +#include +#ifdef HAVE_STDINT_H +#include +#endif +#include + +#ifndef MKEXT +#include "external.h" +#else +typedef unsigned int bittype; /* XXX - for basicblock */ +#endif +#include "manifest.h" +#include "softfloat.h" + +/* + * Storage classes + */ +#define SNULL 0 +#define AUTO 1 +#define EXTERN 2 +#define STATIC 3 +#define REGISTER 4 +#define EXTDEF 5 +#define THLOCAL 6 +#define KEYWORD 7 +#define MOS 8 +#define PARAM 9 +#define STNAME 10 +#define MOU 11 +#define UNAME 12 +#define TYPEDEF 13 +/* #define FORTRAN 14 */ +#define ENAME 15 +#define MOE 16 +/* #define UFORTRAN 17 */ +#define USTATIC 18 + + /* field size is ORed in */ +#define FIELD 0200 +#define FLDSIZ 0177 +extern char *scnames(int); + +/* + * Symbol table flags + */ +#define SNORMAL 0 +#define STAGNAME 01 +#define SLBLNAME 02 +#define SMOSNAME 03 +#define SSTRING 04 +#define NSTYPES 05 +#define SMASK 07 + +#define STLS 00010 /* Thread Local Support variable */ +#define SINSYS 00020 /* Declared in system header */ +#define SSTMT SINSYS /* Allocate symtab on statement stack */ +#define SNOCREAT 00040 /* don't create a symbol in lookup() */ +#define STEMP 00100 /* Allocate symtab from temp or perm mem */ +#define SDYNARRAY 00200 /* symbol is dynamic array on stack */ +#define SINLINE 00400 /* function is of type inline */ +#define SBLK SINLINE /* Allocate symtab from blk mem */ +#define STNODE 01000 /* symbol shall be a temporary node */ +#define SBUILTIN 02000 /* this is a builtin function */ +#define SASG 04000 /* symbol is assigned to already */ +#define SLOCAL1 010000 +#define SLOCAL2 020000 +#define SLOCAL3 040000 + + /* alignment of initialized quantities */ +#ifndef AL_INIT +#define AL_INIT ALINT +#endif + +struct rstack; +struct symtab; +union arglist; +#ifdef GCC_COMPAT +struct gcc_attr_pack; +#endif + +/* + * Dimension/prototype information. + * ddim > 0 holds the dimension of an array. + * ddim < 0 is a dynamic array and refers to a tempnode. + * ...unless: + * ddim == NOOFFSET, an array without dimenston, "[]" + * ddim == -1, dynamic array while building before defid. + */ +union dimfun { + int ddim; /* Dimension of an array */ + union arglist *dfun; /* Prototype index */ +}; + +/* + * Argument list member info when storing prototypes. + */ +union arglist { + TWORD type; + union dimfun *df; + struct attr *sap; +}; +#define TNULL INCREF(FARG) /* pointer to FARG -- impossible type */ +#define TELLIPSIS INCREF(INCREF(FARG)) + +/* + * Symbol table definition. + */ +struct symtab { + struct symtab *snext; /* link to other symbols in the same scope */ + int soffset; /* offset or value */ + char sclass; /* storage class */ + char slevel; /* scope level */ + short sflags; /* flags, see below */ + char *sname; /* Symbol name */ + TWORD stype; /* type word */ + TWORD squal; /* qualifier word */ + union dimfun *sdf; /* ptr to the dimension/prototype array */ + struct attr *sap; /* the base type attribute list */ +}; + +#define ISSOU(ty) ((ty) == STRTY || (ty) == UNIONTY) + +/* + * External definitions + */ +struct swents { /* switch table */ + struct swents *next; /* Next struct in linked list */ + CONSZ sval; /* case value */ + int slab; /* associated label */ +}; +int mygenswitch(int, TWORD, struct swents **, int); + +extern int blevel; +extern int oldstyle; + +extern int lineno, nerrors, issyshdr; + +extern char *ftitle; +extern struct symtab *cftnsp; +extern int autooff, maxautooff, argoff; + +extern OFFSZ inoff; + +extern int reached; +extern int isinlining; +extern int xinline, xgnu89, xgnu99; +extern int bdebug, ddebug, edebug, idebug, ndebug; +extern int odebug, pdebug, sdebug, tdebug, xdebug; + +/* various labels */ +extern int brklab; +extern int contlab; +extern int flostat; +extern int retlab; +extern int doing_init, statinit; +extern short sztable[]; +extern char *astypnames[]; + +/* pragma globals */ +extern int pragma_allpacked, pragma_packed, pragma_aligned; + +/* + * Flags used in the (elementary) flow analysis ... + */ +#define FBRK 02 +#define FCONT 04 +#define FDEF 010 +#define FLOOP 020 + +/* + * Location counters + */ +#define NOSEG -1 +#define PROG 0 /* (ro) program segment */ +#define DATA 1 /* (rw) data segment */ +#define RDATA 2 /* (ro) data segment */ +#define LDATA 3 /* (rw) local data */ +#define UDATA 4 /* (rw) uninitialized data */ +#define STRNG 5 /* (ro) string segment */ +#define PICDATA 6 /* (rw) relocatable data segment */ +#define PICRDATA 7 /* (ro) relocatable data segment */ +#define PICLDATA 8 /* (rw) local relocatable data */ +#define TLSDATA 9 /* (rw) TLS data segment */ +#define TLSUDATA 10 /* (rw) TLS uninitialized segment */ +#define CTORS 11 /* constructor */ +#define DTORS 12 /* destructor */ +#define NMSEG 13 /* other (named) segment */ + +extern int lastloc; +void locctr(int type, struct symtab *sp); +void setseg(int type, char *name); +void defalign(int al); +void symdirec(struct symtab *sp); + +/* + * Tree struct for pass1. + */ +struct flt; + +typedef struct p1node { + int n_op; + TWORD n_type; + TWORD n_qual; + union { + char * _name; + union dimfun *_df; + } n_5; + struct attr *n_ap; + union { + struct { + union { + struct p1node *_left; + CONSZ _val; + } n_l; + union { + struct p1node *_right; + int _rval; + struct symtab *_sp; + } n_r; + } n_u; + struct { + struct flt *_dcon; + struct flt *_ccon; + }; + } n_f; +} P1ND; + +#define glval(p) ((p)->n_f.n_u.n_l._val) +#define slval(p,v) ((p)->n_f.n_u.n_l._val = (v)) +#define n_ccon n_f._ccon + + +/* mark an offset which is undefined */ + +#define NOOFFSET (-10201) + +/* declarations of various functions */ +extern P1ND + *buildtree(int, P1ND *, P1ND *r), + *mkty(unsigned, union dimfun *, struct attr *), + *rstruct(char *, int), + *dclstruct(struct rstack *), + *strend(char *, TWORD), + *tymerge(P1ND *, P1ND *), + *stref(P1ND *), +#ifdef WORD_ADDRESSED + *offcon(OFFSZ, TWORD, union dimfun *, struct attr *), +#endif + *bcon(int), + *xbcon(CONSZ, struct symtab *, TWORD), + *bpsize(P1ND *), + *convert(P1ND *, int), + *pconvert(P1ND *), + *oconvert(P1ND *), + *ptmatch(P1ND *), + *makety(P1ND *, TWORD, TWORD, union dimfun *, struct attr *), + *block(int, P1ND *, P1ND *, TWORD, union dimfun *, struct attr *), + *doszof(P1ND *), + *p1alloc(void), + *optim(P1ND *), + *clocal(P1ND *), + *tempnode(int, TWORD, union dimfun *, struct attr *), + *eve(P1ND *), + *doacall(struct symtab *, P1ND *, P1ND *); +P1ND *intprom(P1ND *); +OFFSZ tsize(TWORD, union dimfun *, struct attr *), + psize(P1ND *); +P1ND * typenode(P1ND *new); +void spalloc(P1ND *, P1ND *, OFFSZ); +char *exname(char *); +struct flt *floatcon(char *); +struct flt *fhexcon(char *); +P1ND *bdty(int op, ...); +extern struct rstack *rpole; + +int oalloc(struct symtab *, int *); +void deflabel(char *, P1ND *); +void gotolabel(char *); +unsigned int esccon(char **); +void inline_start(struct symtab *, int class); +void inline_end(void); +void inline_addarg(struct interpass *); +void inline_ref(struct symtab *); +void inline_prtout(void); +void inline_args(struct symtab **, int); +P1ND *inlinetree(struct symtab *, P1ND *, P1ND *); +void ftnarg(P1ND *); +struct rstack *bstruct(char *, int, P1ND *); +void moedef(char *); +void beginit(struct symtab *); +void simpleinit(struct symtab *, P1ND *); +struct symtab *lookup(char *, int); +struct symtab *getsymtab(char *, int); +char *addstring(char *); +char *addname(char *); +void symclear(int); +struct symtab *hide(struct symtab *); +void soumemb(P1ND *, char *, int); +int talign(unsigned int, struct attr *); +void bfcode(struct symtab **, int); +int chkftn(union arglist *, union arglist *); +void branch(int); +void cbranch(P1ND *, P1ND *); +void extdec(struct symtab *); +void defzero(struct symtab *); +int falloc(struct symtab *, int, P1ND *); +TWORD ctype(TWORD); +void inval(CONSZ, int, P1ND *); +int ninval(CONSZ, int, P1ND *); +void infld(CONSZ, int, CONSZ); +void zbits(CONSZ, int); +void instring(struct symtab *); +void inwstring(struct symtab *); +void plabel(int); +void bjobcode(void); +void ejobcode(int); +void calldec(P1ND *, P1ND *); +int cisreg(TWORD); +void asginit(P1ND *); +void desinit(P1ND *); +void endinit(int); +void endictx(void); +void sspinit(void); +void sspstart(void); +void sspend(void); +void ilbrace(void); +void irbrace(void); +CONSZ scalinit(P1ND *); +void p1print(char *, ...); +char *copst(int); +int cdope(int); +void myp2tree(P1ND *); +void lcommprint(void), strprint(void); +void lcommdel(struct symtab *); +P1ND *funcode(P1ND *); +struct symtab *enumhd(char *); +P1ND *enumdcl(struct symtab *); +P1ND *enumref(char *); +CONSZ icons(P1ND *); +CONSZ valcast(CONSZ v, TWORD t); +int mypragma(char *); +char *pragtok(char *); +int eat(int); +void fixdef(struct symtab *); +int cqual(TWORD, TWORD); +void defloc(struct symtab *); +int fldchk(int); +int nncon(P1ND *); +void cunput(char); +P1ND *nametree(struct symtab *sp); +void pass1_lastchance(struct interpass *); +void fldty(struct symtab *p); +struct suedef *sueget(struct suedef *p); +void complinit(void); +void kwinit(void); +P1ND *structref(P1ND *p, int f, char *name); +P1ND *cxop(int op, P1ND *l, P1ND *r); +P1ND *imop(int op, P1ND *l, P1ND *r); +P1ND *cxelem(int op, P1ND *p); +P1ND *cxconj(P1ND *p); +P1ND *cxcast(P1ND *p1, P1ND *p2); +P1ND *cxret(P1ND *p, P1ND *q); +P1ND *imret(P1ND *p, P1ND *q); +P1ND *cast(P1ND *p, TWORD t, TWORD q); +P1ND *ccast(P1ND *p, TWORD t, TWORD u, union dimfun *df, struct attr *sue); +int andable(P1ND *); +int conval(P1ND *, int, P1ND *); +int ispow2(CONSZ); +void defid(P1ND *q, int class); +void defid2(P1ND *q, int class, char *astr); +void efcode(void); +void ecomp(P1ND *p); +int upoff(int size, int alignment, int *poff); +void nidcl(P1ND *p, int class); +void nidcl2(P1ND *p, int class, char *astr); +void eprint(P1ND *, int, int *, int *); +int uclass(int class); +int notlval(P1ND *); +void ecode(P1ND *p); +void ftnend(void); +void dclargs(void); +int suemeq(struct attr *s1, struct attr *s2); +struct symtab *strmemb(struct attr *ap); +int yylex(void); +void yyerror(char *); +int pragmas_gcc(char *t); +int concast(P1ND *p, TWORD t); +char *stradd(char *old, char *new); +#ifdef WORD_ADDRESSED +#define rmpconv(p) (p) +#else +P1ND *rmpconv(P1ND *); +#endif +P1ND *optloop(P1ND *); +P1ND *nlabel(int label); +TWORD styp(void); +void *stmtalloc(size_t); +void *blkalloc(size_t); +void stmtfree(void); +void blkfree(void); +char *getexname(struct symtab *sp); +void putjops(P1ND *p, void *arg); + +void p1walkf(P1ND *, void (*f)(P1ND *, void *), void *); +void p1fwalk(P1ND *t, void (*f)(P1ND *, int, int *, int *), int down); +void p1listf(P1ND *p, void (*f)(P1ND *)); +void p1flist(P1ND *p, void (*f)(P1ND *, void *), void *); +P1ND *p1nfree(P1ND *); +void p1tfree(P1ND *); +P1ND *p1tcopy(P1ND *); + +struct flt { + union { + long double fp; + struct softfloat sf; + }; + TWORD t; +}; +typedef struct flt FLT; +FLT flt_zero; +#define fltallo() stmtalloc(sizeof(FLT)) +#define FLOAT_ZERO (&flt_zero) +#define FCAST(x) ((FLT *)(x)) + +#ifdef NATIVE_FLOATING_POINT +#define FLOAT_PLUS(p1,p2) ((p1)->n_dcon->fp += (p2)->n_dcon->fp) +#define FLOAT_MINUS(p1,p2) ((p1)->n_dcon->fp -= (p2)->n_dcon->fp) +#define FLOAT_MUL(p1,p2) ((p1)->n_dcon->fp *= (p2)->n_dcon->fp) +#define FLOAT_DIV(p1,p2) ((p1)->n_dcon->fp /= (p2)->n_dcon->fp) +#define FLOAT_ISZERO(p) ((p)->fp == 0.0) +#define FLOAT_FP2FP(f,t) (f->fp = (t == FLOAT ? (float)f->fp : \ + t == DOUBLE ? (double)f->fp : f->fp)) +#define FLOAT_INT2FP(d,p,v) (ISUNSIGNED(v) ? \ + (d->fp = (long double)(U_CONSZ)(p)) : (d->fp = (long double)(CONSZ)(p))) +#define FLOAT_FP2INT(i,d,t) (ISUNSIGNED(t) ? \ + (i = (U_CONSZ)(d->fp)) : (i = d->fp)) +#define FLOAT_EQ(d1,d2) (d1->fp == d2->fp) +#define FLOAT_NE(d1,d2) (d1->fp != d2->fp) +#define FLOAT_GE(d1,d2) (d1->fp >= d2->fp) +#define FLOAT_GT(d1,d2) (d1->fp > d2->fp) +#define FLOAT_LE(d1,d2) (d1->fp <= d2->fp) +#define FLOAT_LT(d1,d2) (d1->fp < d2->fp) +#define FLOAT_NEG(p) (p->fp = -p->fp) +#define FLOAT_SETZERO(d) (d)->fp = FLOAT_ZERO + +#else +#define FLOAT_PLUS(p1,p2) p1->n_dcon->sf = \ + soft_plus(p1->n_dcon->sf, p2->n_dcon->sf) +#define FLOAT_MINUS(p1,p2) p1->n_dcon->sf = \ + soft_minus(p1->n_dcon->sf, p2->n_dcon->sf) +#define FLOAT_MUL(p1,p2) p1->n_dcon->sf = \ + soft_mul(p1->n_dcon->sf, p2->n_dcon->sf) +#define FLOAT_DIV(p1,p2) p1->n_dcon->sf = \ + soft_div(p1->n_dcon->sf, p2->n_dcon->sf) +#define FLOAT_ISZERO(p) soft_isz(p->sf) +#define FLOAT_FP2FP(f,t) f->sf = soft_fp2fp(f->sf, t) +#define FLOAT_INT2FP(f,p,t) f->sf = soft_int2fp(p, t) +#define FLOAT_FP2INT(i,d,t) i = soft_fp2int(d->sf, t) /* XXX fp format */ +#define FLOAT_EQ(d1,d2) soft_cmp(d1->sf, d2->sf, EQ) +#define FLOAT_NE(d1,d2) soft_cmp(d1->sf, d2->sf, NE) +#define FLOAT_GE(d1,d2) soft_cmp(d1->sf, d2->sf, GE) +#define FLOAT_GT(d1,d2) soft_cmp(d1->sf, d2->sf, GT) +#define FLOAT_LE(d1,d2) soft_cmp(d1->sf, d2->sf, LE) +#define FLOAT_LT(d1,d2) soft_cmp(d1->sf, d2->sf, LT) +#define FLOAT_NEG(flt) flt->sf = soft_neg(flt->sf) +#define FLOAT_SETZERO(d) (d)->sf = FLOAT_ZERO + +#endif + +enum { ATTR_FIRST = ATTR_MI_MAX + 1, + + /* PCC used attributes */ + ATTR_COMPLEX, /* Internal definition of complex */ + xxxATTR_BASETYP, /* Internal; see below */ + ATTR_QUALTYP, /* Internal; const/volatile, see below */ + ATTR_ALIGNED, /* Internal; also used as gcc type attribute */ + ATTR_NORETURN, /* Function does not return */ + ATTR_STRUCT, /* Internal; element list */ +#define ATTR_MAX ATTR_STRUCT + + ATTR_P1LABELS, /* used to store stuff while parsing */ + ATTR_SONAME, /* output name of symbol */ + +#ifdef GCC_COMPAT + /* type attributes */ + GCC_ATYP_PACKED, + GCC_ATYP_SECTION, + GCC_ATYP_TRANSP_UNION, + GCC_ATYP_UNUSED, + GCC_ATYP_DEPRECATED, + GCC_ATYP_MAYALIAS, + + /* variable attributes */ + GCC_ATYP_MODE, + + /* function attributes */ + GCC_ATYP_FORMAT, + GCC_ATYP_NONNULL, + GCC_ATYP_SENTINEL, + GCC_ATYP_WEAK, + GCC_ATYP_FORMATARG, + GCC_ATYP_GNU_INLINE, + GCC_ATYP_MALLOC, + GCC_ATYP_NOTHROW, + GCC_ATYP_CONST, + GCC_ATYP_PURE, + GCC_ATYP_CONSTRUCTOR, + GCC_ATYP_DESTRUCTOR, + GCC_ATYP_VISIBILITY, + GCC_ATYP_WARN_UNUSED_RESULT, + GCC_ATYP_USED, + GCC_ATYP_NO_INSTR_FUN, + GCC_ATYP_NOINLINE, + GCC_ATYP_ALIAS, + GCC_ATYP_WEAKREF, + GCC_ATYP_ALLOCSZ, + GCC_ATYP_ALW_INL, + GCC_ATYP_TLSMODEL, + GCC_ATYP_ALIASWEAK, + GCC_ATYP_RETURNS_TWICE, + GCC_ATYP_WARNING, + GCC_ATYP_NOCLONE, + GCC_ATYP_REGPARM, + GCC_ATYP_FASTCALL, + + /* other stuff */ + GCC_ATYP_BOUNDED, /* OpenBSD extra boundary checks */ + + /* OSX toolchain */ + GCC_ATYP_WEAKIMPORT, + + GCC_ATYP_MAX, +#endif +#ifdef ATTR_P1_TARGET + ATTR_P1_TARGET, +#endif + ATTR_P1_MAX +}; + +/* +#ifdef notdef + * ATTR_BASETYP has the following layout: + * aa[0].iarg has size + * aa[1].iarg has alignment +#endif + * ATTR_QUALTYP has the following layout: + * aa[0].iarg has CON/VOL + FUN/ARY/PTR + * Not defined yet... + * aa[3].iarg is dimension for arrays (XXX future) + * aa[3].varg is function defs for functions. + */ +#ifdef notdef +#define atypsz aa[0].iarg +#define aalign aa[1].iarg +#endif + +/* + * ATTR_STRUCT member list. + */ +#define amlist aa[0].varg +#define amsize aa[1].iarg +#define strattr(x) (attr_find(x, ATTR_STRUCT)) + +void gcc_init(void); +int gcc_keyword(char *); +struct attr *gcc_attr_parse(P1ND *); +void gcc_tcattrfix(P1ND *); +struct gcc_attrib *gcc_get_attr(struct suedef *, int); +void dump_attr(struct attr *gap); +void gcc_modefix(P1ND *); +P1ND *gcc_eval_timode(int op, P1ND *, P1ND *); +P1ND *gcc_eval_ticast(int op, P1ND *, P1ND *); +P1ND *gcc_eval_tiuni(int op, P1ND *); +struct attr *isti(P1ND *p); + +#ifndef NO_C_BUILTINS +struct bitable { + char *name; + P1ND *(*fun)(const struct bitable *, P1ND *a); + short flags; +#define BTNOPROTO 001 +#define BTNORVAL 002 +#define BTNOEVE 004 +#define BTGNUONLY 010 + short narg; + TWORD *tp; + TWORD rt; +}; + +P1ND *builtin_check(struct symtab *, P1ND *a); +void builtin_init(void); + +/* Some builtins targets need to implement */ +P1ND *builtin_frame_address(const struct bitable *bt, P1ND *a); +P1ND *builtin_return_address(const struct bitable *bt, P1ND *a); +P1ND *builtin_cfa(const struct bitable *bt, P1ND *a); +#endif + + +#ifdef STABS +void stabs_init(void); +void stabs_file(char *); +void stabs_efile(char *); +void stabs_line(int); +void stabs_rbrac(int); +void stabs_lbrac(int); +void stabs_func(struct symtab *); +void stabs_newsym(struct symtab *); +void stabs_chgsym(struct symtab *); +void stabs_struct(struct symtab *, struct attr *); +#endif +#ifdef DWARF +void dwarf_init(char *); +void dwarf_file(char *); +void dwarf_end(void); +#endif + +#ifndef CHARCAST +/* to make character constants into character connstants */ +/* this is a macro to defend against cross-compilers, etc. */ +#define CHARCAST(x) (char)(x) +#endif + +/* sometimes int is smaller than pointers */ +#if SZPOINT(CHAR) <= SZINT +#define INTPTR INT +#elif SZPOINT(CHAR) <= SZLONG +#define INTPTR LONG +#elif SZPOINT(CHAR) <= SZLONGLONG +#define INTPTR LONGLONG +#else +#error int size unknown +#endif + +/* Generate a bitmask from a given type size */ +#define SZMASK(y) ((((1LL << ((y)-1))-1) << 1) | 1) + +/* + * finction specifiers. + */ +#define INLINE 1 +#define NORETURN 2 + +/* + * C compiler first pass extra defines. + */ +#define QUALIFIER (MAXOP+1) +#define CLASS (MAXOP+2) +#define RB (MAXOP+3) +#define DOT (MAXOP+4) +#define ELLIPSIS (MAXOP+5) +#define TYPE (MAXOP+6) +#define LB (MAXOP+7) +#define COMOP (MAXOP+8) +#define QUEST (MAXOP+9) +#define COLON (MAXOP+10) +#define ANDAND (MAXOP+11) +#define OROR (MAXOP+12) +#define NOT (MAXOP+13) +#define CAST (MAXOP+14) +#define STRING (MAXOP+15) + +/* The following must be in the same order as their NOASG counterparts */ +#define PLUSEQ (MAXOP+16) +#define MINUSEQ (MAXOP+17) +#define DIVEQ (MAXOP+18) +#define MODEQ (MAXOP+19) +#define MULEQ (MAXOP+20) +#define ANDEQ (MAXOP+21) +#define OREQ (MAXOP+22) +#define EREQ (MAXOP+23) +#define LSEQ (MAXOP+24) +#define RSEQ (MAXOP+25) + +#define UNASG (-(PLUSEQ-PLUS))+ + +#define INCR (MAXOP+26) +#define DECR (MAXOP+27) +#define SZOF (MAXOP+28) +#define CLOP (MAXOP+29) +#define ATTRIB (MAXOP+30) +#define XREAL (MAXOP+31) +#define XIMAG (MAXOP+32) +#define TYMERGE (MAXOP+33) +#define LABEL (MAXOP+34) +#define BIQUEST (MAXOP+35) +#define UPLUS (MAXOP+36) +#define ALIGN (MAXOP+37) +#define FUNSPEC (MAXOP+38) +#define STREF (MAXOP+39) + +/* + * The following types are only used in pass1. + */ +#define SIGNED (MAXTYPES+1) +#define FARG (MAXTYPES+2) +#define FIMAG (MAXTYPES+3) +#define IMAG (MAXTYPES+4) +#define LIMAG (MAXTYPES+5) +#define FCOMPLEX (MAXTYPES+6) +#define COMPLEX (MAXTYPES+7) +#define LCOMPLEX (MAXTYPES+8) +#define ENUMTY (MAXTYPES+9) + +#define ISFTY(x) ((x) >= FLOAT && (x) <= LDOUBLE) +#define ISCTY(x) ((x) >= FCOMPLEX && (x) <= LCOMPLEX) +#define ISITY(x) ((x) >= FIMAG && (x) <= LIMAG) +#define ANYCX(p) (p->n_type == STRTY && attr_find(p->n_ap, ATTR_COMPLEX)) + +#define coptype(o) (cdope(o)&TYFLG) +#define clogop(o) (cdope(o)&LOGFLG) +#define casgop(o) (cdope(o)&ASGFLG) + +#ifdef TWOPASS +#define PRTPREF "* " +#else +#define PRTPREF "" +#endif + +/* + * Allocation routines. + */ +#if defined(__PCC__) || defined(__GNUC__) +#define FUNALLO(x) __builtin_alloca(x) +#define FUNFREE(x) +#elif defined(HAVE_ALLOCA) +#define FUNALLO(x) alloca(x) +#define FUNFREE(x) +#else +#define FUNALLO(x) malloc(x) +#define FUNFREE(x) free(x) +#endif diff --git a/lang/pcc/pcc/cc/ccom/pftn.c b/lang/pcc/pcc/cc/ccom/pftn.c new file mode 100644 index 000000000..ac60d33a0 --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/pftn.c @@ -0,0 +1,3585 @@ +/* $Id: pftn.c,v 1.421 2016/03/05 15:31:24 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ + +/* + * Many changes from the 32V sources, among them: + * - New symbol table manager (moved to another file). + * - Prototype saving/checks. + */ + +# include "pass1.h" +#include "unicode.h" + +#include +#include + +#include "cgram.h" + +#define NODE P1ND +#define tfree p1tfree +#define nfree p1nfree +#define ccopy p1tcopy +#define flist p1flist +#define fwalk p1fwalk + +struct symtab *cftnsp; +int arglistcnt, dimfuncnt; /* statistics */ +int symtabcnt, suedefcnt; /* statistics */ +int lcommsz, blkalloccnt; +int autooff, /* the next unused automatic offset */ + maxautooff, /* highest used automatic offset in function */ + argoff; /* the next unused argument offset */ +int retlab = NOLAB; /* return label for subroutine */ +int brklab; +int contlab; +int flostat; +int blevel; +int reached, prolab; + +struct params; + +#ifdef NATIVE_FLOATING_POINT +FLT flt_zero = { { .fp = 0.0, }, LDOUBLE }; +#endif + +#define MKTY(p, t, d, s) r = p1alloc(); *r = *p; \ + r = argcast(r, t, d, s); *p = *r; nfree(r); + +/* + * Linked list stack while reading in structs. + */ +struct rstack { + struct rstack *rnext; + int rsou; + int rstr; + struct symtab *rsym; + struct symtab *rb; + struct attr *ap; + int flags; +#define LASTELM 1 +} *rpole; + +/* + * Linked list for parameter (and struct elements) declaration. + */ +static struct params { + struct params *prev; + struct symtab *sym; +} *lparam; +static int nparams; + +/* defines used for getting things off of the initialization stack */ + +NODE *arrstk[10]; +int arrstkp; +static int intcompare; +NODE *parlink; + +void fixtype(NODE *p, int class); +int fixclass(int class, TWORD type); +static void dynalloc(struct symtab *p, int *poff); +static void evalidx(struct symtab *p); +int isdyn(struct symtab *p); +void inforce(OFFSZ n); +void vfdalign(int n); +static void ssave(struct symtab *); +#ifdef PCC_DEBUG +static void alprint(union arglist *al, int in); +#endif +static void lcommadd(struct symtab *sp); +static NODE *mkcmplx(NODE *p, TWORD dt); +static void cxargfixup(NODE *arg, TWORD dt, struct attr *ap); +extern int fun_inline; + +void +defid(NODE *q, int class) +{ + defid2(q, class, 0); +} + +static void +addsoname(struct symtab *sp, char *so) +{ + struct attr *ap = attr_new(ATTR_SONAME, 1); + ap->sarg(0) = so; + sp->sap = attr_add(sp->sap, ap); +} + +/* + * Declaration of an identifier. Handles redeclarations, hiding, + * incomplete types and forward declarations. + * + * q is a TYPE node setup after parsing with n_type, n_df and n_ap. + * n_sp is a pointer to the not-yet initalized symbol table entry + * unless it's a redeclaration or supposed to hide a variable. + */ + +void +defid2(NODE *q, int class, char *astr) +{ + struct attr *ap; + struct symtab *p; + TWORD type, qual; + TWORD stp, stq; + int scl; + union dimfun *dsym, *ddef; + int slev, temp, changed; + + if (q == NIL) + return; /* an error was detected */ + +#ifdef GCC_COMPAT + gcc_modefix(q); +#endif + p = q->n_sp; + + if (p->sname == NULL) + cerror("defining null identifier"); + +#ifdef PCC_DEBUG + if (ddebug) { + printf("defid(%s '%s'(%p), ", p->sname, "soname" , p); + tprint(q->n_type, q->n_qual); + printf(", %s, (%p)), level %d\n\t", scnames(class), + q->n_df, blevel); +#ifdef GCC_COMPAT + dump_attr(q->n_ap); +#endif + } +#endif + + fixtype(q, class); + + type = q->n_type; + qual = q->n_qual; + class = fixclass(class, type); + + stp = p->stype; + stq = p->squal; + slev = p->slevel; + +#ifdef PCC_DEBUG + if (ddebug) { + printf(" modified to "); + tprint(type, qual); + printf(", %s\n", scnames(class)); + printf(" previous def'n: "); + tprint(stp, stq); + printf(", %s, (%p,%p)), level %d\n", + scnames(p->sclass), p->sdf, p->sap, slev); + } +#endif + + if (blevel == 1) { + switch (class) { + default: + if (!(class&FIELD) && !ISFTN(type)) + uerror("declared argument %s missing", + p->sname ); + break; + case MOS: + case MOU: + cerror("field5"); + case TYPEDEF: + case PARAM: + break; + } + } + + if (stp == UNDEF) + goto enter; /* New symbol */ + + if (type != stp) + goto mismatch; + + if (blevel > slev && (class == AUTO || class == REGISTER)) + /* new scope */ + goto mismatch; + + /* + * test (and possibly adjust) dimensions. + * also check that prototypes are correct. + */ + dsym = p->sdf; + ddef = q->n_df; + changed = 0; + for (temp = type; temp & TMASK; temp = DECREF(temp)) { + if (ISARY(temp)) { + if (dsym->ddim == NOOFFSET) { + dsym->ddim = ddef->ddim; + changed = 1; + } else if (ddef->ddim != NOOFFSET && + dsym->ddim!=ddef->ddim) { + goto mismatch; + } + ++dsym; + ++ddef; + } else if (ISFTN(temp)) { + /* add a late-defined prototype here */ + if (!oldstyle && dsym->dfun == NULL) + dsym->dfun = ddef->dfun; + if (!oldstyle && ddef->dfun != NULL && + chkftn(dsym->dfun, ddef->dfun)) + uerror("declaration doesn't match prototype"); + dsym++, ddef++; + } + } +#ifdef STABS + if (changed && gflag) + stabs_chgsym(p); /* symbol changed */ +#endif + + /* check that redeclarations are to the same structure */ + if (temp == STRTY || temp == UNIONTY) { + if (strmemb(p->sap) != strmemb(q->n_ap)) + goto mismatch; + } + + scl = p->sclass; + +#ifdef PCC_DEBUG + if (ddebug) + printf(" previous class: %s\n", scnames(scl)); +#endif + + /* + * Its allowed to add attributes to existing declarations. + * Be careful though not to trash existing attributes. + * XXX - code below is probably not correct. + */ + if (p->sap && p->sap->atype <= ATTR_MAX) { + /* nothing special, just overwrite */ + p->sap = q->n_ap; + } else { + if (p->slevel == blevel) { + for (ap = q->n_ap; ap; ap = ap->next) { + if (ap->atype > ATTR_MAX) + p->sap = attr_add(p->sap, attr_dup(ap)); + } + } else + p->sap = q->n_ap; + } + + if (class & FIELD) + cerror("field1"); + switch(class) { + + case EXTERN: + if (astr) + addsoname(p, astr); + switch( scl ){ + case STATIC: + case USTATIC: + if( slev==0 ) + goto done; + break; + case EXTDEF: + case EXTERN: + goto done; + case SNULL: + if (p->sflags & SINLINE) { + p->sclass = EXTDEF; + inline_ref(p); + goto done; + } + break; + } + break; + + case STATIC: + if (astr) + addsoname(p, astr); + if (scl==USTATIC || (scl==EXTERN && blevel==0)) { + p->sclass = STATIC; + goto done; + } + if (changed || (scl == STATIC && blevel == slev)) + goto done; /* identical redeclaration */ + break; + + case USTATIC: + if (scl==STATIC || scl==USTATIC) + goto done; + break; + + case TYPEDEF: + if (scl == class) + goto done; + break; + + case MOU: + case MOS: + cerror("field6"); + + case EXTDEF: + switch (scl) { + case EXTERN: + p->sclass = EXTDEF; + goto done; + case USTATIC: + p->sclass = STATIC; + goto done; + case SNULL: +#ifdef GCC_COMPAT + /* + * Handle redeclarations of inlined functions. + * This is allowed if the previous declaration is of + * type gnu_inline. + */ + if (attr_find(p->sap, GCC_ATYP_GNU_INLINE)) + goto done; +#endif + break; + } + break; + + case AUTO: + case REGISTER: + break; /* mismatch.. */ + case SNULL: + if (fun_inline && ISFTN(type)) { + if (scl == EXTERN) { + p->sclass = EXTDEF; + inline_ref(p); + } + goto done; + } + break; + } + + mismatch: + + /* + * Only allowed for automatic variables. + */ + if ((blevel == 2 && slev == 1) || blevel <= slev || class == EXTERN) { + uerror("redeclaration of %s", p->sname); + return; + } + if ((ISFTN(p->stype) && ISFTN(type)) || + (!ISFTN(p->stype) && !ISFTN(type))) + warner(Wshadow, p->sname, p->slevel ? "local" : "global"); + q->n_sp = p = hide(p); + + enter: /* make a new entry */ + + if (type == VOID && class != TYPEDEF) + uerror("void not allowed for variables"); + +#ifdef PCC_DEBUG + if(ddebug) + printf(" new entry made\n"); +#endif + p->stype = type; + p->squal = qual; + p->sclass = (char)class; + p->slevel = (char)blevel; + p->soffset = NOOFFSET; + if (q->n_ap) + p->sap = attr_add(q->n_ap, p->sap); + + /* copy dimensions */ + p->sdf = q->n_df; + /* Do not save param info for old-style functions */ + if (ISFTN(type) && oldstyle) + p->sdf->dfun = NULL; + + if (arrstkp) + evalidx(p); + + /* allocate offsets */ + if (class&FIELD) { + cerror("field2"); /* new entry */ + } else switch (class) { + + case REGISTER: + if (astr != NULL) + werror("no register assignment (yet)"); + p->sclass = class = AUTO; + /* FALLTHROUGH */ + case AUTO: + if (isdyn(p)) { + p->sflags |= SDYNARRAY; + dynalloc(p, &autooff); + } else + oalloc(p, &autooff); + break; + + case PARAM: + if (q->n_type != FARG) + oalloc(p, &argoff); + break; + + case STATIC: + case EXTDEF: + case EXTERN: + p->soffset = getlab(); + /* FALLTHROUGH */ + case USTATIC: + if (astr) + addsoname(p, astr); + break; + + case MOU: + case MOS: + cerror("field7"); + case SNULL: +#ifdef notdef + if (fun_inline) { + p->slevel = 1; + p->soffset = getlab(); + } +#endif + break; + } + +#ifdef STABS + if (gflag && p->stype != FARG) + stabs_newsym(p); +#endif + +done: + fixdef(p); /* Leave last word to target */ +#ifndef HAVE_WEAKREF + { + struct attr *at; + + /* Refer renamed function */ + if ((at = attr_find(p->sap, GCC_ATYP_WEAKREF))) + addsoname(p, at->sarg(0)); + } +#endif +#ifdef PCC_DEBUG + if (ddebug) { + printf( " sdf, offset: %p, %d\n\t", + p->sdf, p->soffset); +#ifdef GCC_COMPAT + dump_attr(p->sap); +#endif + } +#endif +} + +void +ssave(struct symtab *sym) +{ + struct params *p; + + p = tmpalloc(sizeof(struct params)); + p->prev = lparam; + p->sym = sym; + lparam = p; +} + +/* + * end of function + */ +void +ftnend(void) +{ +#ifdef GCC_COMPAT + struct attr *gc, *gd; +#endif + extern int *mkclabs(void); + extern NODE *cftnod; + extern struct savbc *savbc; + extern struct swdef *swpole; + extern int tvaloff; + char *c; + + if (retlab != NOLAB && nerrors == 0) { /* inside a real function */ + plabel(retlab); + if (cftnod) + ecomp(buildtree(FORCE, p1tcopy(cftnod), NIL)); + efcode(); /* struct return handled here */ + c = getexname(cftnsp); + SETOFF(maxautooff, ALCHAR); + send_passt(IP_EPILOG, maxautooff/SZCHAR, c, + cftnsp->stype, cftnsp->sclass == EXTDEF, + retlab, tvaloff, mkclabs()); + } + + cftnod = NIL; + tcheck(); + brklab = contlab = retlab = NOLAB; + flostat = 0; + if (nerrors == 0) { + if (savbc != NULL) + cerror("bcsave error"); + if (lparam != NULL) + cerror("parameter reset error"); + if (swpole != NULL) + cerror("switch error"); + } +#ifdef GCC_COMPAT + if (cftnsp) { + gc = attr_find(cftnsp->sap, GCC_ATYP_CONSTRUCTOR); + gd = attr_find(cftnsp->sap, GCC_ATYP_DESTRUCTOR); + if (gc || gd) { + struct symtab sts = *cftnsp; + NODE *p; + sts.stype = INCREF(sts.stype); + p = nametree(&sts); + p->n_op = ICON; + if (gc) { + locctr(CTORS, NULL); + inval(0, SZPOINT(0), p); + } + if (gd) { + locctr(DTORS, NULL); + inval(0, SZPOINT(0), p); + } + tfree(p); + } + } +#endif + savbc = NULL; + lparam = NULL; + cftnsp = NULL; + maxautooff = autooff = AUTOINIT; + reached = 1; + + if (isinlining) + inline_end(); + inline_prtout(); + + tmpfree(); /* Release memory resources */ +} + +static struct symtab nulsym = { + NULL, 0, 0, 0, 0, "null", INT, 0, NULL, NULL +}; + +void +dclargs(void) +{ + union dimfun *df; + union arglist *al; + struct params *a; + struct symtab *p, **parr = NULL; /* XXX gcc */ + int i; + + /* + * Deal with fun(void) properly. + */ + if (nparams == 1 && lparam->sym && lparam->sym->stype == VOID) + goto done; + + /* + * Generate a list for bfcode(). + * Parameters were pushed in reverse order. + */ + if (nparams != 0) + parr = FUNALLO(sizeof(struct symtab *) * nparams); + + if (nparams) + for (a = lparam, i = 0; a != NULL; a = a->prev) { + p = a->sym; + parr[i++] = p; + if (p == NULL) { + uerror("parameter %d name missing", i); + p = &nulsym; /* empty symtab */ + } + if (p->stype == FARG) + p->stype = INT; + if (ISARY(p->stype)) { + p->stype += (PTR-ARY); + p->sdf++; + } else if (ISFTN(p->stype)) { + werror("function declared as argument"); + p->stype = INCREF(p->stype); + } +#ifdef STABS + if (gflag) + stabs_newsym(p); +#endif + } + if (oldstyle && (df = cftnsp->sdf) && (al = df->dfun)) { + /* + * Check against prototype of oldstyle function. + */ + union arglist *al2, *alb; + + alb = al2 = FUNALLO(sizeof(union arglist) * nparams * 3 + 1); + for (i = 0; i < nparams; i++) { + TWORD type = parr[i]->stype; + (al2++)->type = type; + if (ISSOU(BTYPE(type))) + (al2++)->sap = parr[i]->sap; + while (!ISFTN(type) && !ISARY(type) && type > BTMASK) + type = DECREF(type); + if (type > BTMASK) + (al2++)->df = parr[i]->sdf; + } + al2->type = TNULL; + intcompare = 1; + if (chkftn(al, alb)) + uerror("function doesn't match prototype"); + FUNFREE(alb); + intcompare = 0; + + } + + if (oldstyle && nparams) { + /* Must recalculate offset for oldstyle args here */ + argoff = ARGINIT; + for (i = 0; i < nparams; i++) { + parr[i]->soffset = NOOFFSET; + oalloc(parr[i], &argoff); + } + } + +done: autooff = AUTOINIT; + + plabel(prolab); /* after prolog, used in optimization */ + retlab = getlab(); + bfcode(parr, nparams); + if (fun_inline && (xinline +#ifdef GCC_COMPAT + || attr_find(cftnsp->sap, GCC_ATYP_ALW_INL) +#endif + )) + inline_args(parr, nparams); + FUNFREE(parr); + plabel(getlab()); /* used when spilling */ + if (parlink) + ecomp(parlink); + parlink = NIL; + lparam = NULL; + nparams = 0; + symclear(1); /* In case of function pointer args */ +} + +/* + * basic attributes for structs and enums + */ +static struct attr * +seattr(void) +{ + return attr_add(attr_new(ATTR_ALIGNED, 4), attr_new(ATTR_STRUCT, 2)); +} + +/* + * Struct/union/enum symtab construction. + */ +static void +defstr(struct symtab *sp, int class) +{ + sp->sclass = (char)class; + if (class == STNAME) + sp->stype = STRTY; + else if (class == UNAME) + sp->stype = UNIONTY; + else if (class == ENAME) + sp->stype = ENUMTY; +} + +/* + * Declare a struct/union/enum tag. + * If not found, create a new tag with UNDEF type. + */ +static struct symtab * +deftag(char *name, int class) +{ + struct symtab *sp; + + if ((sp = lookup(name, STAGNAME))->sap == NULL) { + /* New tag */ + defstr(sp, class); + } else if (sp->sclass != class) + uerror("tag %s redeclared", name); + return sp; +} + +/* + * reference to a structure or union, with no definition + */ +NODE * +rstruct(char *tag, int soru) +{ + struct symtab *sp; + + sp = deftag(tag, soru); + if (sp->sap == NULL) + sp->sap = seattr(); + return mkty(sp->stype, 0, sp->sap); +} + +static int enumlow, enumhigh; +int enummer; + +/* + * Declare a member of enum. + */ +void +moedef(char *name) +{ + struct symtab *sp; + + sp = lookup(name, SNORMAL); + if (sp->stype == UNDEF || (sp->slevel < blevel)) { + if (sp->stype != UNDEF) + sp = hide(sp); + sp->stype = INT; /* always */ + sp->sclass = MOE; + sp->soffset = enummer; + } else + uerror("%s redeclared", name); + if (enummer < enumlow) + enumlow = enummer; + if (enummer > enumhigh) + enumhigh = enummer; + enummer++; +} + +/* + * Declare an enum tag. Complain if already defined. + */ +struct symtab * +enumhd(char *name) +{ + struct attr *ap; + struct symtab *sp; + + enummer = enumlow = enumhigh = 0; + if (name == NULL) + return NULL; + + sp = deftag(name, ENAME); + if (sp->stype != ENUMTY) { + if (sp->slevel == blevel) + uerror("%s redeclared", name); + sp = hide(sp); + defstr(sp, ENAME); + } + if (sp->sap == NULL) + ap = sp->sap = attr_new(ATTR_STRUCT, 4); + else + ap = attr_find(sp->sap, ATTR_STRUCT); + ap->amlist = sp; + return sp; +} + +/* + * finish declaration of an enum + */ +NODE * +enumdcl(struct symtab *sp) +{ + NODE *p; + TWORD t; + +#ifdef ENUMSIZE + t = ENUMSIZE(enumhigh, enumlow); +#else + t = ctype(enumlow < 0 ? INT : UNSIGNED); +#ifdef notdef + if (enumhigh <= MAX_CHAR && enumlow >= MIN_CHAR) + t = ctype(CHAR); + else if (enumhigh <= MAX_SHORT && enumlow >= MIN_SHORT) + t = ctype(SHORT); + else + t = ctype(INT); +#endif +#endif + + if (sp) + sp->stype = t; + p = mkty(t, 0, 0); + p->n_sp = sp; + return p; +} + +/* + * Handle reference to an enum + */ +NODE * +enumref(char *name) +{ + struct symtab *sp; + NODE *p; + + sp = lookup(name, STAGNAME); + +#ifdef notdef + /* + * 6.7.2.3 Clause 2: + * "A type specifier of the form 'enum identifier' without an + * enumerator list shall only appear after the type it specifies + * is complete." + */ + if (sp->sclass != ENAME) + uerror("enum %s undeclared", name); +#endif + if (sp->sclass == SNULL) { + /* declare existence of enum */ + sp = enumhd(name); + sp->stype = ENUMTY; + } + + p = mkty(sp->stype, 0, sp->sap); + p->n_sp = sp; + return p; +} + +/* + * begining of structure or union declaration + * It's an error if this routine is called twice with the same struct. + */ +struct rstack * +bstruct(char *name, int soru, NODE *gp) +{ + struct rstack *r; + struct symtab *sp; + struct attr *ap, *gap; + +#ifdef GCC_COMPAT + gap = gp ? gcc_attr_parse(gp) : NULL; +#else + gap = NULL; +#endif + + if (name != NULL) { + sp = deftag(name, soru); + if (sp->sap == NULL) + sp->sap = seattr(); + ap = attr_find(sp->sap, ATTR_ALIGNED); + if (ap->iarg(0) != 0) { + if (sp->slevel < blevel) { + sp = hide(sp); + defstr(sp, soru); + sp->sap = seattr(); + } else + uerror("%s redeclared", name); + } + gap = sp->sap = attr_add(sp->sap, gap); + } else { + gap = attr_add(seattr(), gap); + sp = NULL; + } + + r = tmpcalloc(sizeof(struct rstack)); + r->rsou = soru; + r->rsym = sp; + r->rb = NULL; + r->ap = gap; + r->rnext = rpole; + rpole = r; + + return r; +} + +/* + * Called after a struct is declared to restore the environment. + * - If ALSTRUCT is defined, this will be the struct alignment and the + * struct size will be a multiple of ALSTRUCT, otherwise it will use + * the alignment of the largest struct member. + */ +NODE * +dclstruct(struct rstack *r) +{ + NODE *n; + struct attr *aps, *apb; + struct symtab *sp; + int al, sa, sz; + + apb = attr_find(r->ap, ATTR_ALIGNED); + aps = attr_find(r->ap, ATTR_STRUCT); + aps->amlist = r->rb; + +#ifdef ALSTRUCT + al = ALSTRUCT; +#else + al = ALCHAR; +#endif + + /* + * extract size and alignment, calculate offsets + */ + for (sp = r->rb; sp; sp = sp->snext) { + sa = talign(sp->stype, sp->sap); + if (sp->sclass & FIELD) + sz = sp->sclass&FLDSIZ; + else + sz = (int)tsize(sp->stype, sp->sdf, sp->sap); + if (sz > rpole->rstr) + rpole->rstr = sz; /* for use with unions */ + /* + * set al, the alignment, to the lcm of the alignments + * of the members. + */ + SETOFF(al, sa); + } + + SETOFF(rpole->rstr, al); + + aps->amsize = rpole->rstr; + apb->iarg(0) = al; + +#ifdef PCC_DEBUG + if (ddebug) { + printf("dclstruct(%s): size=%d, align=%d\n", + r->rsym ? r->rsym->sname : "??", + aps->amsize, apb->iarg(0)); + } + if (ddebug>1) { + printf("\tsize %d align %d link %p\n", + aps->amsize, apb->iarg(0), aps->amlist); + for (sp = aps->amlist; sp != NULL; sp = sp->snext) { + printf("\tmember %s(%p)\n", sp->sname, sp); + } + } +#endif + +#ifdef STABS + if (gflag) + stabs_struct(r->rsym, r->ap); +#endif + + rpole = r->rnext; + n = mkty(r->rsou == STNAME ? STRTY : UNIONTY, 0, r->ap); + n->n_sp = r->rsym; + + n->n_qual |= 1; /* definition place XXX used by attributes */ + return n; +} + +/* + * Add a new member to the current struct or union being declared. + */ +void +soumemb(NODE *n, char *name, int class) +{ + struct symtab *sp, *lsp; + int incomp, tsz, al; + TWORD t; + + if (rpole == NULL) + cerror("soumemb"); + + /* check if tag name exists */ + lsp = NULL; + for (sp = rpole->rb; sp != NULL; lsp = sp, sp = sp->snext) + if (*name != '*' && sp->sname == name) + uerror("redeclaration of %s", name); + + sp = getsymtab(name, SMOSNAME); + if (rpole->rb == NULL) + rpole->rb = sp; + else + lsp->snext = sp; + + n->n_sp = sp; + sp->stype = n->n_type; + sp->squal = n->n_qual; + sp->slevel = blevel; + sp->sap = n->n_ap; + sp->sdf = n->n_df; + + if (class & FIELD) { + sp->sclass = (char)class; + if (rpole->rsou == UNAME) + rpole->rstr = 0; + falloc(sp, class&FLDSIZ, NIL); + } else if (rpole->rsou == STNAME || rpole->rsou == UNAME) { + sp->sclass = rpole->rsou == STNAME ? MOS : MOU; + if (sp->sclass == MOU) + rpole->rstr = 0; + al = talign(sp->stype, sp->sap); + tsz = (int)tsize(sp->stype, sp->sdf, sp->sap); + sp->soffset = upoff(tsz, al, &rpole->rstr); + } + + /* + * 6.7.2.1 clause 16: + * "...the last member of a structure with more than one + * named member may have incomplete array type;" + */ + if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET) + incomp = 1; + else + incomp = 0; + if ((rpole->flags & LASTELM) || (rpole->rb == sp && incomp == 1)) + uerror("incomplete array in struct"); + if (incomp == 1) + rpole->flags |= LASTELM; + + /* + * 6.7.2.1 clause 2: + * "...such a structure shall not be a member of a structure + * or an element of an array." + */ + t = sp->stype; + if (rpole->rsou != STNAME || BTYPE(t) != STRTY) + return; /* not for unions */ + while (ISARY(t)) + t = DECREF(t); + if (ISPTR(t)) + return; + + if ((lsp = strmemb(sp->sap)) != NULL) { + for (; lsp->snext; lsp = lsp->snext) + ; + if (ISARY(lsp->stype) && lsp->snext && + lsp->sdf->ddim == NOOFFSET) + uerror("incomplete struct in struct"); + } +} + +/* + * error printing routine in parser + */ +void +yyerror(char *s) +{ + uerror(s); +} + +void yyaccpt(void); +void +yyaccpt(void) +{ + ftnend(); +} + +/* + * p is top of type list given to tymerge later. + * Find correct CALL node and declare parameters from there. + */ +void +ftnarg(NODE *p) +{ + NODE *q; + +#ifdef PCC_DEBUG + if (ddebug > 2) + printf("ftnarg(%p)\n", p); +#endif + /* + * Push argument symtab entries onto param stack in reverse order, + * due to the nature of the stack it will be reclaimed correct. + */ + for (; p->n_op != NAME; p = p->n_left) { + if (p->n_op == UCALL && p->n_left->n_op == NAME) + return; /* Nothing to enter */ + if (p->n_op == CALL && p->n_left->n_op == NAME) + break; + } + + p = p->n_right; + while (p->n_op == CM) { + q = p->n_right; + if (q->n_op != ELLIPSIS) { + ssave(q->n_sp); + nparams++; +#ifdef PCC_DEBUG + if (ddebug > 2) + printf(" saving sym %s (%p) from (%p)\n", + q->n_sp->sname, q->n_sp, q); +#endif + } + p = p->n_left; + } + ssave(p->n_sp); + if (p->n_type != VOID) + nparams++; + +#ifdef PCC_DEBUG + if (ddebug > 2) + printf(" saving sym %s (%p) from (%p)\n", + nparams ? p->n_sp->sname : "", p->n_sp, p); +#endif +} + +/* + * compute the alignment of an object with type ty, sizeoff index s + */ +int +talign(unsigned int ty, struct attr *apl) +{ + struct attr *al; + int a; + + for (; ty > BTMASK; ty = DECREF(ty)) { + switch (ty & TMASK) { + case PTR: + return(ALPOINT); + case ARY: + continue; + case FTN: + cerror("compiler takes alignment of function"); + } + } + + /* check for alignment attribute */ + if ((al = attr_find(apl, ATTR_ALIGNED))) { + if ((a = al->iarg(0)) == 0) { + uerror("no alignment"); + a = ALINT; + } + return a; + } + +#ifndef NO_COMPLEX + if (ISITY(ty)) + ty -= (FIMAG-FLOAT); +#endif + ty = BTYPE(ty); + if (ty >= CHAR && ty <= ULONGLONG && ISUNSIGNED(ty)) + ty = DEUNSIGN(ty); + + switch (ty) { +#ifdef GCC_COMPAT + case VOID: a = ALCHAR; break; /* GCC */ +#endif + case BOOL: a = ALBOOL; break; + case CHAR: a = ALCHAR; break; + case SHORT: a = ALSHORT; break; + case INT: a = ALINT; break; + case LONG: a = ALLONG; break; + case LONGLONG: a = ALLONGLONG; break; + case FLOAT: a = ALFLOAT; break; + case DOUBLE: a = ALDOUBLE; break; + case LDOUBLE: a = ALLDOUBLE; break; + default: + uerror("no alignment"); + a = ALINT; + } + return a; +} + +short sztable[] = { 0, SZBOOL, SZCHAR, SZCHAR, SZSHORT, SZSHORT, SZINT, SZINT, + SZLONG, SZLONG, SZLONGLONG, SZLONGLONG, SZFLOAT, SZDOUBLE, SZLDOUBLE }; + +/* compute the size associated with type ty, + * dimoff d, and sizoff s */ +/* BETTER NOT BE CALLED WHEN t, d, and s REFER TO A BIT FIELD... */ +OFFSZ +tsize(TWORD ty, union dimfun *d, struct attr *apl) +{ + struct attr *ap, *ap2; + OFFSZ mult, sz; + + mult = 1; + + for (; ty > BTMASK; ty = DECREF(ty)) { + switch (ty & TMASK) { + + case FTN: + uerror( "cannot take size of function"); + case PTR: + return( SZPOINT(ty) * mult ); + case ARY: + if (d->ddim == NOOFFSET) + return 0; + if (d->ddim < 0) + cerror("tsize: dynarray"); + mult *= d->ddim; + d++; + } + } + +#ifndef NO_COMPLEX + if (ISITY(ty)) + ty -= (FIMAG-FLOAT); +#endif + + if (ty == VOID) + ty = CHAR; + if (ty <= LDOUBLE) + sz = sztable[ty]; + else if (ISSOU(ty)) { + if ((ap = strattr(apl)) == NULL || + (ap2 = attr_find(apl, ATTR_ALIGNED)) == NULL || + (ap2->iarg(0) == 0)) { + uerror("unknown structure/union/enum"); + sz = SZINT; + } else + sz = ap->amsize; + } else { + uerror("unknown type"); + sz = SZINT; + } + + return((unsigned int)sz * mult); +} + +#ifndef MYINSTRING +/* + * Print out a string of characters. + * Assume that the assembler understands C-style escape + * sequences. + */ +void +instring(struct symtab *sp) +{ + unsigned short sh[2]; + char *s, *str; + TWORD t; + NODE *p; + + locctr(STRNG, sp); + defloc(sp); + + t = BTYPE(sp->stype); + str = s = sp->sname; + if (t == ctype(USHORT)) { + /* convert to UTF-16 */ + p = xbcon(0, NULL, t); + while (*s) { + cp2u16(u82cp(&s), sh); + if ((glval(p) = sh[0])) + inval(0, SZSHORT, p); + if ((glval(p) = sh[1])) + inval(0, SZSHORT, p); + } + slval(p, 0); + inval(0, SZSHORT, p); + nfree(p); + } else if (t == ctype(SZINT < 32 ? ULONG : UNSIGNED) || + t == ctype(SZINT < 32 ? LONG : INT)) { + /* convert to UTF-32 */ + p = xbcon(0, NULL, t); + while (*s) { + slval(p, u82cp(&s)); + inval(0, SZINT < 32 ? SZLONG : SZINT, p); + } + slval(p, 0); + inval(0, SZINT < 32 ? SZLONG : SZINT, p); + nfree(p); + } else if (t == CHAR || t == UCHAR) { + printf(PRTPREF "\t.ascii \""); + while (*s) { + if (*s == '\\') + (void)esccon(&s); + else + s++; + + if (s - str > 60) { + fwrite(str, 1, s - str, stdout); + printf("\"\n" PRTPREF "\t.ascii \""); + str = s; + } + } + + fwrite(str, 1, s - str, stdout); + printf("\\0\"\n"); + } else + cerror("instring %ld", t); +} +#endif + +/* + * update the offset pointed to by poff; return the + * offset of a value of size `size', alignment `alignment', + * given that off is increasing + */ +int +upoff(int size, int alignment, int *poff) +{ + int off; + + off = *poff; + SETOFF(off, alignment); + if (off < 0) + cerror("structure or stack overgrown"); /* wrapped */ + *poff = off+size; + return (off); +} + +/* + * allocate p with offset *poff, and update *poff + */ +int +oalloc(struct symtab *p, int *poff ) +{ + int al, off, tsz; + int noff; + + /* + * Only generate tempnodes if we are optimizing, + * and only for integers, floats or pointers, + * and not if the type on this level is volatile. + */ + if (xtemps && ((p->sclass == AUTO) || (p->sclass == REGISTER)) && + (p->stype < STRTY || ISPTR(p->stype)) && + !(cqual(p->stype, p->squal) & VOL) && cisreg(p->stype)) { + NODE *tn = tempnode(0, p->stype, p->sdf, p->sap); + p->soffset = regno(tn); + p->sflags |= STNODE; + nfree(tn); + return 0; + } + + al = talign(p->stype, p->sap); + noff = off = *poff; + tsz = (int)tsize(p->stype, p->sdf, p->sap); +#ifdef BACKAUTO + if (p->sclass == AUTO) { + noff = off + tsz; + if (noff < 0) + cerror("stack overflow"); + SETOFF(noff, al); + off = -noff; + } else +#endif + if (p->sclass == PARAM && (p->stype == CHAR || p->stype == UCHAR || + p->stype == SHORT || p->stype == USHORT || p->stype == BOOL)) { + off = upoff(SZINT, ALINT, &noff); +#if TARGET_ENDIAN == TARGET_BE + off = noff - tsz; +#endif + } else { + off = upoff(tsz, al, &noff); + } + + if (p->sclass != REGISTER) { + /* in case we are allocating stack space for register arguments */ + if (p->soffset == NOOFFSET) + p->soffset = off; + else if(off != p->soffset) + return(1); + } + + *poff = noff; + return(0); +} + +/* + * Delay emission of code generated in argument headers. + */ +static void +edelay(NODE *p) +{ + if (blevel == 1) { + /* Delay until after declarations */ + if (parlink == NULL) + parlink = p; + else + parlink = block(COMOP, parlink, p, 0, 0, 0); + } else + ecomp(p); +} + +/* + * Traverse through the array args, evaluate them and put the + * resulting temp numbers in the dim fields. + */ +static void +evalidx(struct symtab *sp) +{ + union dimfun *df; + NODE *p; + TWORD t; + int astkp = 0; + + if (arrstk[0] == NIL) + astkp++; /* for parameter arrays */ + + if (isdyn(sp)) + sp->sflags |= SDYNARRAY; + + df = sp->sdf; + for (t = sp->stype; t > BTMASK; t = DECREF(t)) { + if (!ISARY(t)) + continue; + if (df->ddim == -1) { + p = tempnode(0, INT, 0, 0); + df->ddim = -regno(p); + edelay(buildtree(ASSIGN, p, arrstk[astkp++])); + } + df++; + } + arrstkp = 0; +} + +/* + * Return 1 if dynamic array, 0 otherwise. + */ +int +isdyn(struct symtab *sp) +{ + union dimfun *df = sp->sdf; + TWORD t; + + for (t = sp->stype; t > BTMASK; t = DECREF(t)) { + if (!ISARY(t)) + return 0; + if (df->ddim < 0 && df->ddim != NOOFFSET) + return 1; + df++; + } + return 0; +} + +/* + * Allocate space on the stack for dynamic arrays (or at least keep track + * of the index). + * Strategy is as follows: + * - first entry is a pointer to the dynamic datatype. + * - if it's a one-dimensional array this will be the only entry used. + * - if it's a multi-dimensional array the following (numdim-1) integers + * will contain the sizes to multiply the indexes with. + * - code to write the dimension sizes this will be generated here. + * - code to allocate space on the stack will be generated here. + */ +static void +dynalloc(struct symtab *p, int *poff) +{ + union dimfun *df; + NODE *n, *tn, *pol; + TWORD t; + + /* + * The pointer to the array is not necessarily stored in a + * TEMP node, but if it is, its number is in the soffset field; + */ + t = p->stype; + p->sflags |= STNODE; + p->stype = INCREF(p->stype); /* Make this an indirect pointer */ + tn = tempnode(0, p->stype, p->sdf, p->sap); + p->soffset = regno(tn); + + df = p->sdf; + + pol = bcon(1); + for (; t > BTMASK; t = DECREF(t)) { + if (!ISARY(t)) + break; + if (df->ddim < 0) + n = tempnode(-df->ddim, INT, 0, 0); + else + n = bcon(df->ddim); + + pol = buildtree(MUL, pol, n); + df++; + } + /* Create stack gap */ + spalloc(tn, pol, tsize(t, 0, p->sap)); +} + +/* + * allocate a field of width w + * new is 0 if new entry, 1 if redefinition, -1 if alignment + */ +int +falloc(struct symtab *p, int w, NODE *pty) +{ + TWORD otype, type; + int al,sz; + + otype = type = p ? p->stype : pty->n_type; + + if (type == BOOL) + type = BOOL_TYPE; + if (!ISINTEGER(type)) { + uerror("illegal field type"); + type = INT; + } + + al = talign(type, NULL); + sz = tsize(type, NULL, NULL); + + if (w > sz) { + uerror("field too big"); + w = sz; + } + + if (w == 0) { /* align only */ + SETOFF(rpole->rstr, al); + if (p != NULL) + uerror("zero size field"); + return(0); + } + + if (rpole->rstr%al + w > sz) + SETOFF(rpole->rstr, al); + if (p == NULL) { + rpole->rstr += w; /* we know it will fit */ + return(0); + } + + /* establish the field */ + + p->soffset = rpole->rstr; + rpole->rstr += w; + p->stype = otype; + fldty(p); + return(0); +} + +/* + * Check if this symbol should be a common or must be handled in data seg. + */ +static void +commchk(struct symtab *sp) +{ + if ((sp->sflags & STLS) +#ifdef GCC_COMPAT + || attr_find(sp->sap, GCC_ATYP_SECTION) +#endif + ) { + /* TLS handled in data segment */ + if (sp->sclass == EXTERN) + sp->sclass = EXTDEF; + beginit(sp); + endinit(1); + } else { + symdirec(sp); + defzero(sp); + } +} + +void +nidcl(NODE *p, int class) +{ + nidcl2(p, class, 0); +} + +/* + * handle unitialized declarations assumed to be not functions: + * int a; + * extern int a; + * static int a; + */ +void +nidcl2(NODE *p, int class, char *astr) +{ + struct symtab *sp; + int commflag = 0; + + /* compute class */ + if (class == SNULL) { + if (blevel > 1) + class = AUTO; + else if (blevel != 0 || rpole) + cerror( "nidcl error" ); + else /* blevel = 0 */ + commflag = 1, class = EXTERN; + } + + defid2(p, class, astr); + + sp = p->n_sp; + /* check if forward decl */ + if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET) + return; + + if (sp->sflags & SASG) + return; /* already initialized */ + + switch (class) { + case EXTDEF: + /* simulate initialization by 0 */ + simpleinit(p->n_sp, bcon(0)); + break; + case EXTERN: + if (commflag) + lcommadd(p->n_sp); + else + extdec(p->n_sp); + break; + case STATIC: + if (blevel == 0) + lcommadd(p->n_sp); + else + commchk(p->n_sp); + break; + } +} + +struct lcd { + SLIST_ENTRY(lcd) next; + struct symtab *sp; +}; + +static SLIST_HEAD(, lcd) lhead = { NULL, &lhead.q_forw}; + +/* + * Add a local common statement to the printout list. + */ +void +lcommadd(struct symtab *sp) +{ + struct lcd *lc, *lcp; + + lcp = NULL; + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp == sp) + return; /* already exists */ + if (lc->sp == NULL && lcp == NULL) + lcp = lc; + } + if (lcp == NULL) { + lc = permalloc(sizeof(struct lcd)); + lcommsz += sizeof(struct lcd); + lc->sp = sp; + SLIST_INSERT_LAST(&lhead, lc, next); + } else + lcp->sp = sp; +} + +/* + * Delete a local common statement. + */ +void +lcommdel(struct symtab *sp) +{ + struct lcd *lc; + + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp == sp) { + lc->sp = NULL; + return; + } + } +} + +/* + * Print out the remaining common statements. + */ +void +lcommprint(void) +{ + struct lcd *lc; + + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp != NULL) + commchk(lc->sp); + } +} + +/* + * Merge given types to a single node. + * Any type can end up here. + * p is the old node, q is the old (if any). + * CLASS is AUTO, EXTERN, REGISTER, STATIC or TYPEDEF. + * QUALIFIER is VOL or CON + * TYPE is CHAR, SHORT, INT, LONG, SIGNED, UNSIGNED, VOID, BOOL, FLOAT, + * DOUBLE, STRTY, UNIONTY. + */ +struct typctx { + int class, qual, sig, uns, cmplx, imag, err, align; + TWORD type; + NODE *saved; + struct attr *pre, *post; +}; + +static void +typwalk(NODE *p, void *arg) +{ + struct typctx *tc = arg; + +#define cmop(x,y) block(CM, x, y, INT, 0, 0) + switch (p->n_op) { + case ALIGN: + if (tc->align < glval(p)) + tc->align = glval(p); + break; + case ATTRIB: +#ifdef GCC_COMPAT + if (tc->saved && (tc->saved->n_qual & 1)) { + tc->post = attr_add(tc->post,gcc_attr_parse(p->n_left)); + } else { + tc->pre = attr_add(tc->pre, gcc_attr_parse(p->n_left)); + } + p->n_left = bcon(0); /* For tfree() */ +#else + uerror("gcc type attribute used"); +#endif + break; + case CLASS: + if (p->n_type == 0) + break; /* inline hack */ + if (tc->class) + tc->err = 1; /* max 1 class */ + tc->class = p->n_type; + break; + + case FUNSPEC: + if (p->n_type == INLINE) { + fun_inline = 1; + } else if (p->n_type == NORETURN) { + tc->pre = attr_add(tc->pre, attr_new(ATTR_NORETURN, 3)); + } else + tc->err = 1; + break; + + case QUALIFIER: + if (p->n_qual == 0 && + ((tc->saved && !ISPTR(tc->saved->n_type)) || + (tc->saved == 0))) + uerror("invalid use of 'restrict'"); + tc->qual |= p->n_qual >> TSHIFT; + break; + + case TYPE: + if (p->n_sp != NULL || ISSOU(p->n_type)) { + /* typedef, enum or struct/union */ + if (tc->saved || tc->type) + tc->err = 1; +#ifdef GCC_COMPAT + if (ISSOU(p->n_type) && p->n_left) { + if (tc->post) + cerror("typwalk"); + tc->post = gcc_attr_parse(p->n_left); + } +#endif + tc->saved = ccopy(p); + break; + } + + switch (p->n_type) { + case BOOL: + case CHAR: + case FLOAT: + case VOID: + if (tc->type) + tc->err = 1; + tc->type = p->n_type; + break; + case DOUBLE: + if (tc->type == 0) + tc->type = DOUBLE; + else if (tc->type == LONG) + tc->type = LDOUBLE; + else + tc->err = 1; + break; + case SHORT: + if (tc->type == 0 || tc->type == INT) + tc->type = SHORT; + else + tc->err = 1; + break; + case INT: + if (tc->type == SHORT || tc->type == LONG || + tc->type == LONGLONG) + break; + else if (tc->type == 0) + tc->type = INT; + else + tc->err = 1; + break; + case LONG: + if (tc->type == 0) + tc->type = LONG; + else if (tc->type == INT) + break; + else if (tc->type == LONG) + tc->type = LONGLONG; + else if (tc->type == DOUBLE) + tc->type = LDOUBLE; + else + tc->err = 1; + break; + case SIGNED: + if (tc->sig || tc->uns) + tc->err = 1; + tc->sig = 1; + break; + case UNSIGNED: + if (tc->sig || tc->uns) + tc->err = 1; + tc->uns = 1; + break; + case COMPLEX: + tc->cmplx = 1; + break; + case IMAG: + tc->imag = 1; + break; + default: + cerror("typwalk"); + } + } + +} + +NODE * +typenode(NODE *p) +{ + struct attr *ap; + struct symtab *sp; + struct typctx tc; + NODE *q; + char *c; + + memset(&tc, 0, sizeof(struct typctx)); + + flist(p, typwalk, &tc); + tfree(p); + + if (tc.err) + goto bad; + + if (tc.cmplx || tc.imag) { + if (tc.type == 0) + tc.type = DOUBLE; + if ((tc.cmplx && tc.imag) || tc.sig || tc.uns || + !ISFTY(tc.type)) + goto bad; + if (tc.cmplx) { + c = tc.type == DOUBLE ? "0d" : + tc.type == FLOAT ? "0f" : "0l"; + sp = lookup(addname(c), 0); + tc.type = STRTY; + tc.saved = mkty(tc.type, sp->sdf, sp->sap); + tc.saved->n_sp = sp; + tc.type = 0; + } else + tc.type += (FIMAG-FLOAT); + } + + if (tc.saved && tc.type) + goto bad; + if (tc.sig || tc.uns) { + if (tc.type == 0) + tc.type = tc.sig ? INT : UNSIGNED; + if (tc.type > ULONGLONG) + goto bad; + if (tc.uns) + tc.type = ENUNSIGN(tc.type); + } + + if (xuchar && tc.type == CHAR && tc.sig == 0) + tc.type = UCHAR; + +#ifdef GCC_COMPAT + if (pragma_packed) { + q = bdty(CALL, bdty(NAME, "packed"), bcon(pragma_packed)); + tc.post = attr_add(tc.post, gcc_attr_parse(q)); + } + if (pragma_aligned) { + /* Deal with relevant pragmas */ + if (tc.align < pragma_aligned) + tc.align = pragma_aligned; + } + pragma_aligned = pragma_packed = 0; +#endif + if ((q = tc.saved) == NULL) { + TWORD t; + if ((t = BTYPE(tc.type)) > LDOUBLE && t != VOID && + t != BOOL && !(t >= FIMAG && t <= LIMAG)) + cerror("typenode2 t %x", tc.type); + if (t == UNDEF) { + t = INT; + MODTYPE(tc.type, INT); + } + q = mkty(tc.type, 0, 0); + } + q->n_ap = attr_add(q->n_ap, tc.post); + q->n_qual = tc.qual; + slval(q, tc.class); +#ifdef GCC_COMPAT + if (tc.post) { + /* Can only occur for TYPEDEF, STRUCT or UNION */ + if (tc.saved == NULL) + cerror("typenode"); + if (tc.saved->n_sp) /* trailer attributes for structs */ + tc.saved->n_sp->sap = q->n_ap; + } + if (tc.pre) + q->n_ap = attr_add(q->n_ap, tc.pre); + gcc_tcattrfix(q); +#endif + + if (tc.align && (ap = attr_find(q->n_ap, ATTR_ALIGNED)) && + ap->iarg(0) && tc.align > talign(q->n_type, q->n_ap)/SZCHAR) { + q->n_ap = attr_add(q->n_ap, attr_new(ATTR_ALIGNED, 1)); + q->n_ap->aa[0].iarg = SZCHAR * tc.align; + } + + return q; + +bad: uerror("illegal type combination"); + return mkty(INT, 0, 0); +} + +struct tylnk { + struct tylnk *next; + union dimfun df; +}; + +/* + * Retrieve all CM-separated argument types, sizes and dimensions and + * put them in an array. + * XXX - can only check first type level, side effects? + */ +static union arglist * +arglist(NODE *n) +{ + union arglist *al; + NODE *w = n, **ap; + int num, cnt, i, j, k; + TWORD ty; + +#ifdef PCC_DEBUG + if (pdebug) { + printf("arglist %p\n", n); + fwalk(n, eprint, 0); + } +#endif + /* First: how much to allocate */ + for (num = cnt = 0, w = n; w->n_op == CM; w = w->n_left) { + cnt++; /* Number of levels */ + num++; /* At least one per step */ + if (w->n_right->n_op == ELLIPSIS) + continue; + ty = w->n_right->n_type; + if (ty == ENUMTY) { + uerror("arg %d enum undeclared", cnt); + ty = w->n_right->n_type = INT; + } + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) + num++; + while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + num++; + } + cnt++; + ty = w->n_type; + if (ty == ENUMTY) { + uerror("arg %d enum undeclared", cnt); + ty = w->n_type = INT; + } + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) + num++; + while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + num++; + num += 2; /* TEND + last arg type */ + + /* Second: Create list to work on */ + ap = FUNALLO(sizeof(NODE *) * cnt); + al = permalloc(sizeof(union arglist) * num); + arglistcnt += num; + + for (w = n, i = 0; w->n_op == CM; w = w->n_left) + ap[i++] = w->n_right; + ap[i] = w; + + /* Third: Create actual arg list */ + for (k = 0, j = i; j >= 0; j--) { + if (ap[j]->n_op == ELLIPSIS) { + al[k++].type = TELLIPSIS; + ap[j]->n_op = ICON; /* for tfree() */ + continue; + } + /* Convert arrays to pointers */ + if (ISARY(ap[j]->n_type)) { + ap[j]->n_type += (PTR-ARY); + ap[j]->n_df++; + } + /* Convert (silently) functions to pointers */ + if (ISFTN(ap[j]->n_type)) + ap[j]->n_type = INCREF(ap[j]->n_type); + ty = ap[j]->n_type; +#ifdef GCC_COMPAT + if (ty == UNIONTY && + attr_find(ap[j]->n_ap, GCC_ATYP_TRANSP_UNION)){ + /* transparent unions must have compatible types + * shortcut here: if pointers, set void *, + * otherwise btype. + */ + struct symtab *sp = strmemb(ap[j]->n_ap); + ty = ISPTR(sp->stype) ? PTR|VOID : sp->stype; + } +#endif + al[k++].type = ty; + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) + al[k++].sap = ap[j]->n_ap; + while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + al[k++].df = ap[j]->n_df; + } + al[k++].type = TNULL; + if (k > num) + cerror("arglist: k%d > num%d", k, num); + tfree(n); + FUNFREE(ap); +#ifdef PCC_DEBUG + if (pdebug) + alprint(al, 0); +#endif + return al; +} + +static void +tylkadd(union dimfun dim, struct tylnk **tylkp, int *ntdim) +{ + (*tylkp)->next = tmpalloc(sizeof(struct tylnk)); + *tylkp = (*tylkp)->next; + (*tylkp)->next = NULL; + (*tylkp)->df = dim; + (*ntdim)++; +} + +/* + * build a type, and stash away dimensions, + * from a parse tree of the declaration + * the type is build top down, the dimensions bottom up + */ +static void +tyreduce(NODE *p, struct tylnk **tylkp, int *ntdim) +{ + union dimfun dim; + NODE *r = NULL; + int o; + TWORD t, q; + + o = p->n_op; + if (o == NAME) { + p->n_qual = DECQAL(p->n_qual); + return; + } + + t = INCREF(p->n_type); + q = p->n_qual; + switch (o) { + case CALL: + t += (FTN-PTR); + dim.dfun = arglist(p->n_right); + break; + case UCALL: + t += (FTN-PTR); + dim.dfun = NULL; + break; + case LB: + t += (ARY-PTR); + if (p->n_right->n_op != ICON) { + r = p->n_right; + o = RB; + } else { + dim.ddim = (int)glval(p->n_right); + nfree(p->n_right); +#ifdef notdef + /* XXX - check dimensions at usage time */ + if (dim.ddim == NOOFFSET && p->n_left->n_op == LB) + uerror("null dimension"); +#endif + } + break; + } + + p->n_left->n_type = t; + p->n_left->n_qual = INCQAL(q) | p->n_left->n_qual; + tyreduce(p->n_left, tylkp, ntdim); + + if (o == LB || o == UCALL || o == CALL) + tylkadd(dim, tylkp, ntdim); + if (o == RB) { + dim.ddim = -1; + tylkadd(dim, tylkp, ntdim); + arrstk[arrstkp++] = r; + } + + p->n_sp = p->n_left->n_sp; + p->n_type = p->n_left->n_type; + p->n_qual = p->n_left->n_qual; +} + +/* + * merge type typ with identifier idp. + * idp is returned as a NAME node with correct types, + * typ is untouched since multiple declarations uses it. + * typ has type attributes, idp can never carry such attributes + * so on return just a pointer to the typ attributes is returned. + */ +NODE * +tymerge(NODE *typ, NODE *idp) +{ + TWORD t; + NODE *p; + union dimfun *j; + struct tylnk *base, tylnk, *tylkp; + struct attr *bap; + int ntdim, i; + +#ifdef PCC_DEBUG + if (ddebug > 2) { + printf("tymerge(%p,%p)\n", typ, idp); + fwalk(typ, eprint, 0); + fwalk(idp, eprint, 0); + } +#endif + + if (typ->n_op != TYPE) + cerror("tymerge: arg 1"); + + bap = typ->n_ap; + + idp->n_type = typ->n_type; + idp->n_qual |= typ->n_qual; + + tylkp = &tylnk; + tylkp->next = NULL; + ntdim = 0; + + tyreduce(idp, &tylkp, &ntdim); + + for (t = typ->n_type, j = typ->n_df; t&TMASK; t = DECREF(t)) + if (ISARY(t) || ISFTN(t)) + tylkadd(*j++, &tylkp, &ntdim); + + if (ntdim) { + union dimfun *a = permalloc(sizeof(union dimfun) * ntdim); + dimfuncnt += ntdim; + for (i = 0, base = tylnk.next; base; base = base->next, i++) + a[i] = base->df; + idp->n_df = a; + } else + idp->n_df = NULL; + + /* now idp is a single node: fix up type */ + if ((t = ctype(idp->n_type)) != idp->n_type) + idp->n_type = t; + + if (idp->n_op != NAME) { + for (p = idp->n_left; p->n_op != NAME; p = nfree(p)) + ; + nfree(p); + idp->n_op = NAME; + } + /* carefully not destroy any type attributes */ + if (idp->n_ap != NULL) { + struct attr *ap = idp->n_ap; + while (ap->next) + ap = ap->next; + ap->next = bap; + } else + idp->n_ap = bap; + + return(idp); +} + +static NODE * +argcast(NODE *p, TWORD t, union dimfun *d, struct attr *ap) +{ + NODE *u, *r = p1alloc(); + + r->n_op = NAME; + r->n_type = t; + r->n_qual = 0; /* XXX */ + r->n_df = d; + r->n_ap = ap; + + u = buildtree(CAST, r, p); + nfree(u->n_left); + r = u->n_right; + nfree(u); + return r; +} + +#ifdef PCC_DEBUG +/* + * Print a prototype. + */ +static void +alprint(union arglist *al, int in) +{ + TWORD t; + int i = 0, j; + + for (; al->type != TNULL; al++) { + for (j = in; j > 0; j--) + printf(" "); + printf("arg %d: ", i++); + t = al->type; + tprint(t, 0); + while (t > BTMASK) { + if (ISARY(t)) { + al++; + printf(" dim %d ", al->df->ddim); + } else if (ISFTN(t)) { + al++; + if (al->df->dfun) { + printf("\n"); + alprint(al->df->dfun, in+1); + } + } + t = DECREF(t); + } + if (ISSOU(t)) { + al++; + printf(" (size %d align %d)", (int)tsize(t, 0, al->sap), + (int)talign(t, al->sap)); + } + printf("\n"); + } + if (in == 0) + printf("end arglist\n"); +} +#endif + +int +suemeq(struct attr *s1, struct attr *s2) +{ + + return (strmemb(s1) == strmemb(s2)); +} + +/* + * Sanity-check old-style args. + */ +static NODE * +oldarg(NODE *p) +{ + if (p->n_op == TYPE) + uerror("type is not an argument"); + if (p->n_type == FLOAT) + return cast(p, DOUBLE, p->n_qual); + return p; +} + +/* + * Do prototype checking and add conversions before calling a function. + * Argument f is function and a is a CM-separated list of arguments. + * Returns a merged node (via buildtree() of function and arguments. + */ +NODE * +doacall(struct symtab *sp, NODE *f, NODE *a) +{ + NODE *w, *r; + union arglist *al; + struct ap { + struct ap *next; + NODE *node; + } *at, *apole = NULL, *apary = NULL; + int i, argidx/* , hasarray = 0*/; + TWORD type, arrt; + +#ifdef PCC_DEBUG + if (ddebug) { + printf("doacall.\n"); + fwalk(f, eprint, 0); + if (a) + fwalk(a, eprint, 0); + } +#endif + + /* First let MD code do something */ + calldec(f, a); +/* XXX XXX hack */ + if ((f->n_op == CALL) && + f->n_left->n_op == ADDROF && + f->n_left->n_left->n_op == NAME && + (f->n_left->n_left->n_type & 0x7e0) == 0x4c0) + goto build; +/* XXX XXX hack */ + + /* Check for undefined or late defined enums */ + if (BTYPE(f->n_type) == ENUMTY) { + /* not-yet check if declared enum */ + struct symtab *sq = strmemb(f->n_ap); + if (sq->stype != ENUMTY) + MODTYPE(f->n_type, sq->stype); + if (BTYPE(f->n_type) == ENUMTY) + uerror("enum %s not declared", sq->sname); + } + + /* + * Do some basic checks. + */ + if (f->n_df == NULL || (al = f->n_df[0].dfun) == NULL) { + /* + * Handle non-prototype declarations. + */ + if (f->n_op == NAME && f->n_sp != NULL) { + if (strncmp(f->n_sp->sname, "__builtin", 9) != 0 && + (f->n_sp->sflags & SINSYS) == 0) + warner(Wmissing_prototypes, f->n_sp->sname); + } else + warner(Wmissing_prototypes, ""); + + /* floats must be cast to double */ + if (a == NULL) + goto build; + if (a->n_op != CM) { + a = oldarg(a); + } else { + for (w = a; w->n_left->n_op == CM; w = w->n_left) + w->n_right = oldarg(w->n_right); + w->n_left = oldarg(w->n_left); + w->n_right = oldarg(w->n_right); + } + goto build; + } + if (al->type == VOID) { + if (a != NULL) + uerror("function takes no arguments"); + goto build; /* void function */ + } else { + if (a == NULL) { + uerror("function needs arguments"); + goto build; + } + } +#ifdef PCC_DEBUG + if (pdebug) { + printf("arglist for %s\n", + f->n_sp != NULL ? f->n_sp->sname : "function pointer"); + alprint(al, 0); + } +#endif + + /* + * Create a list of pointers to the nodes given as arg. + */ + for (w = a, i = 1; w->n_op == CM; w = w->n_left) + i++; + apary = FUNALLO(sizeof(struct ap) * i); + + for (w = a, i = 0; w->n_op == CM; w = w->n_left) { + at = &apary[i++]; + at->node = w->n_right; + at->next = apole; + apole = at; + } + at = &apary[i]; + at->node = w; + at->next = apole; + apole = at; + + /* + * Do the typechecking by walking up the list. + */ + argidx = 1; + while (al->type != TNULL) { + if (al->type == TELLIPSIS) { + /* convert the rest of float to double */ + for (; apole; apole = apole->next) { + if (apole->node->n_type != FLOAT) + continue; + MKTY(apole->node, DOUBLE, 0, 0); + } + goto build; + } + if (apole == NULL) { + uerror("too few arguments to function"); + goto build; + } +/* al = prototyp, apole = argument till ftn */ +/* type = argumentets typ, arrt = prototypens typ */ + type = apole->node->n_type; + arrt = al->type; +#if 0 + if ((hasarray = ISARY(arrt))) + arrt += (PTR-ARY); +#endif + /* Taking addresses of arrays are meaningless in expressions */ + /* but people tend to do that and also use in prototypes */ + /* this is mostly a problem with typedefs */ + if (ISARY(type)) { + if (ISPTR(arrt) && ISARY(DECREF(arrt))) + type = INCREF(type); + else + type += (PTR-ARY); + } else if (ISPTR(type) && !ISARY(DECREF(type)) && + ISPTR(arrt) && ISARY(DECREF(arrt))) { + type += (ARY-PTR); + type = INCREF(type); + } + + /* Check structs */ + if (type <= BTMASK && arrt <= BTMASK) { +#ifndef NO_COMPLEX + if ((type != arrt) && (ANYCX(apole->node) || + (arrt == STRTY && + attr_find(al[1].sap, ATTR_COMPLEX)))) { + cxargfixup(apole->node, arrt, al[1].sap); + } else +#endif + if (type != arrt) { + if (ISSOU(BTYPE(type)) || ISSOU(BTYPE(arrt))) { +incomp: uerror("incompatible types for arg %d", + argidx); + } else { + MKTY(apole->node, arrt, 0, 0) + } +#ifndef NO_COMPLEX + } else if (type == STRTY && + attr_find(apole->node->n_ap, ATTR_COMPLEX) && + attr_find(al[1].sap, ATTR_COMPLEX)) { + /* Both are complex */ + if (strmemb(apole->node->n_ap)->stype != + strmemb(al[1].sap)->stype) { + /* must convert to correct type */ + w = p1alloc(); + *w = *apole->node; + w = mkcmplx(w, + strmemb(al[1].sap)->stype); + *apole->node = *w; + nfree(w); + } + goto out; +#endif + } else if (ISSOU(BTYPE(type))) { + if (!suemeq(apole->node->n_ap, al[1].sap)) + goto incomp; + } + goto out; + } + + /* XXX should (recusively) check return type and arg list of + func ptr arg XXX */ + if (ISFTN(DECREF(arrt)) && ISFTN(type)) + type = INCREF(type); + + /* Hereafter its only pointers (or arrays) left */ + /* Check for struct/union intermixing with other types */ + if (((type <= BTMASK) && ISSOU(BTYPE(type))) || + ((arrt <= BTMASK) && ISSOU(BTYPE(arrt)))) + goto incomp; + + /* Check for struct/union compatibility */ + if (type == arrt) { + if (ISSOU(BTYPE(type))) { + if (suemeq(apole->node->n_ap, al[1].sap)) + goto out; + } else + goto out; + } + if (BTYPE(arrt) == VOID && type > BTMASK) + goto skip; /* void *f = some pointer */ + if (arrt > BTMASK && BTYPE(type) == VOID) + goto skip; /* some *f = void pointer */ + if (apole->node->n_op == ICON && glval(apole->node) == 0) + goto skip; /* Anything assigned a zero */ + + if ((type & ~BTMASK) == (arrt & ~BTMASK)) { + /* do not complain for pointers with signedness */ + if ((DEUNSIGN(BTYPE(type)) == DEUNSIGN(BTYPE(arrt))) && + (BTYPE(type) != BTYPE(arrt))) { + warner(Wpointer_sign); + goto skip; + } + } + + werror("implicit conversion of argument %d due to prototype", + argidx); + +skip: if (ISSOU(BTYPE(arrt))) { + MKTY(apole->node, arrt, 0, al[1].sap) + } else { + MKTY(apole->node, arrt, 0, 0) + } + +out: al++; + if (ISSOU(BTYPE(arrt))) + al++; +#if 0 + while (arrt > BTMASK && !ISFTN(arrt)) + arrt = DECREF(arrt); + if (ISFTN(arrt) || hasarray) + al++; +#else + while (arrt > BTMASK) { + if (ISARY(arrt) || ISFTN(arrt)) { + al++; + break; + } + arrt = DECREF(arrt); + } +#endif + apole = apole->next; + argidx++; + } + if (apole != NULL) + uerror("too many arguments to function"); + +build: if (apary) + FUNFREE(apary); + if (sp != NULL && (sp->sflags & SINLINE) && (w = inlinetree(sp, f, a))) + return w; + return buildtree(a == NIL ? UCALL : CALL, f, a); +} + +static int +chk2(TWORD type, union dimfun *dsym, union dimfun *ddef) +{ + while (type > BTMASK) { + switch (type & TMASK) { + case ARY: + /* may be declared without dimension */ + if (dsym->ddim == NOOFFSET) + dsym->ddim = ddef->ddim; + if (dsym->ddim < 0 && ddef->ddim < 0) + ; /* dynamic arrays as arguments */ + else if (ddef->ddim > 0 && dsym->ddim != ddef->ddim) + return 1; + dsym++, ddef++; + break; + case FTN: + /* old-style function headers with function pointers + * will most likely not have a prototype. + * This is not considered an error. */ + if (ddef->dfun == NULL) { +#ifdef notyet + werror("declaration not a prototype"); +#endif + } else if (chkftn(dsym->dfun, ddef->dfun)) + return 1; + dsym++, ddef++; + break; + } + type = DECREF(type); + } + return 0; +} + +/* + * Compare two function argument lists to see if they match. + */ +int +chkftn(union arglist *usym, union arglist *udef) +{ + TWORD t2; + int ty, tyn; + + if (usym == NULL) + return 0; + if (cftnsp != NULL && udef == NULL && usym->type == VOID) + return 0; /* foo() { function with foo(void); prototype */ + if (udef == NULL && usym->type != TNULL) + return 1; + while (usym->type != TNULL) { + if (usym->type == udef->type) + goto done; + /* + * If an old-style declaration, then all types smaller than + * int are given as int parameters. + */ + if (intcompare) { + ty = BTYPE(usym->type); + tyn = BTYPE(udef->type); + if (ty == tyn || ty != INT) + return 1; + if (tyn == CHAR || tyn == UCHAR || + tyn == SHORT || tyn == USHORT) + goto done; + return 1; + } else + return 1; + +done: ty = BTYPE(usym->type); + t2 = usym->type; + if (ISSOU(ty)) { + usym++, udef++; + if (suemeq(usym->sap, udef->sap) == 0) + return 1; + } + + while (!ISFTN(t2) && !ISARY(t2) && t2 > BTMASK) + t2 = DECREF(t2); + if (t2 > BTMASK) { + usym++, udef++; + if (chk2(t2, usym->df, udef->df)) + return 1; + } + usym++, udef++; + } + if (usym->type != udef->type) + return 1; + return 0; +} + +void +fixtype(NODE *p, int class) +{ + unsigned int t, type; + int mod1, mod2; + /* fix up the types, and check for legality */ + + /* forward declared enums */ + if (BTYPE(p->n_sp->stype) == ENUMTY) { + MODTYPE(p->n_sp->stype, strmemb(p->n_sp->sap)->stype); + } + + if( (type = p->n_type) == UNDEF ) return; + if ((mod2 = (type&TMASK))) { + t = DECREF(type); + while( mod1=mod2, mod2 = (t&TMASK) ){ + if( mod1 == ARY && mod2 == FTN ){ + uerror( "array of functions is illegal" ); + type = 0; + } + else if( mod1 == FTN && ( mod2 == ARY || mod2 == FTN ) ){ + uerror( "function returns illegal type" ); + type = 0; + } + t = DECREF(t); + } + } + + /* detect function arguments, watching out for structure declarations */ + if (rpole && ISFTN(type)) { + uerror("function illegal in structure or union"); + type = INCREF(type); + } + p->n_type = type; +} + +/* + * give undefined version of class + */ +int +uclass(int class) +{ + if (class == SNULL) + return(EXTERN); + else if (class == STATIC) + return(USTATIC); + else + return(class); +} + +int +fixclass(int class, TWORD type) +{ + extern int fun_inline; + + /* first, fix null class */ + if (class == SNULL) { + if (fun_inline && ISFTN(type)) + return SNULL; + if (rpole) + cerror("field8"); + else if (blevel == 0) + class = EXTDEF; + else + class = AUTO; + } + + /* now, do general checking */ + + if( ISFTN( type ) ){ + switch( class ) { + default: + uerror( "function has illegal storage class" ); + case AUTO: + class = EXTERN; + case EXTERN: + case EXTDEF: + case TYPEDEF: + case STATIC: + case USTATIC: + ; + } + } + + if (class & FIELD) { + cerror("field3"); + } + + switch (class) { + + case MOS: + case MOU: + cerror("field4"); + + case REGISTER: + if (blevel == 0) + uerror("illegal register declaration"); + if (blevel == 1) + return(PARAM); + else + return(REGISTER); + + case AUTO: + if( blevel < 2 ) uerror( "illegal ULABEL class" ); + return( class ); + + case EXTERN: + case STATIC: + case EXTDEF: + case TYPEDEF: + case USTATIC: + case PARAM: + return( class ); + + default: + cerror( "illegal class: %d", class ); + /* NOTREACHED */ + + } + return 0; /* XXX */ +} + +/* + * Generates a goto statement; sets up label number etc. + */ +void +gotolabel(char *name) +{ + struct symtab *s = lookup(name, SLBLNAME|STEMP); + + if (s->soffset == 0) { + s->soffset = -getlab(); + s->sclass = STATIC; + } + branch(s->soffset < 0 ? -s->soffset : s->soffset); +} + +/* + * Sets a label for gotos. + */ +void +deflabel(char *name, NODE *p) +{ + struct symtab *s = lookup(name, SLBLNAME|STEMP); + +#ifdef GCC_COMPAT + s->sap = gcc_attr_parse(p); +#endif + if (s->soffset > 0) + uerror("label '%s' redefined", name); + if (s->soffset == 0) { + s->soffset = getlab(); + s->sclass = STATIC; + } + if (s->soffset < 0) + s->soffset = -s->soffset; + plabel( s->soffset); +} + +struct symtab * +getsymtab(char *name, int flags) +{ + struct symtab *s; + + if (flags & SSTMT) { + s = stmtalloc(sizeof(struct symtab)); + } else if (flags & SBLK) { + s = blkalloc(sizeof(struct symtab)); + } else if (flags & STEMP) { + s = tmpalloc(sizeof(struct symtab)); + } else { + s = permalloc(sizeof(struct symtab)); + symtabcnt++; + } + s->sname = name; + s->snext = NULL; + s->stype = UNDEF; + s->squal = 0; + s->sclass = SNULL; + s->sflags = (short)(flags & SMASK); + s->soffset = 0; + s->slevel = (char)blevel; + s->sdf = NULL; + s->sap = NULL; + return s; +} + +int +fldchk(int sz) +{ + if (rpole->rsou != STNAME && rpole->rsou != UNAME) + uerror("field outside of structure"); + if (sz < 0 || sz >= FIELD) { + uerror("illegal field size"); + return 1; + } + return 0; +} + +#ifdef PCC_DEBUG +static char * +ccnames[] = { /* names of storage classes */ + "SNULL", + "AUTO", + "EXTERN", + "STATIC", + "REGISTER", + "EXTDEF", + "LABEL", + "ULABEL", + "MOS", + "PARAM", + "STNAME", + "MOU", + "UNAME", + "TYPEDEF", + "FORTRAN", + "ENAME", + "MOE", + "UFORTRAN", + "USTATIC", + }; + +char * +scnames(int c) +{ + /* return the name for storage class c */ + static char buf[12]; + if( c&FIELD ){ + snprintf( buf, sizeof(buf), "FIELD[%d]", c&FLDSIZ ); + return( buf ); + } + return( ccnames[c] ); + } +#endif + +#if 0 +static char *stack_chk_fail = "__stack_smash_handler"; +static char *stack_chk_guard = "__guard"; +#else +static char *stack_chk_fail = "__stack_chk_fail"; +static char *stack_chk_guard = "__stack_chk_guard"; +#endif +static char *stack_chk_canary = "__stack_chk_canary"; + +void +sspinit(void) +{ + NODE *p; + + p = block(NAME, NIL, NIL, FTN+VOID, 0, 0); + p->n_sp = lookup(stack_chk_fail, SNORMAL); + defid(p, EXTERN); + nfree(p); + + p = block(NAME, NIL, NIL, INT, 0, 0); + p->n_sp = lookup(stack_chk_guard, SNORMAL); + defid(p, EXTERN); + nfree(p); +} + +void +sspstart(void) +{ + NODE *p, *q; + + q = block(NAME, NIL, NIL, INT, 0, 0); + q->n_sp = lookup(stack_chk_guard, SNORMAL); + q = clocal(q); + + p = block(REG, NIL, NIL, INCREF(INT), 0, 0); + slval(p, 0); + p->n_rval = FPREG; + p = cast(p, INT, 0); + q = buildtree(ER, p, q); + + p = block(NAME, NIL, NIL, INT, 0, 0); + p->n_qual = VOL >> TSHIFT; + p->n_sp = lookup(stack_chk_canary, SNORMAL); + defid(p, AUTO); + p = clocal(p); + ecomp(buildtree(ASSIGN, p, q)); +} + +void +sspend(void) +{ + NODE *p, *q; + TWORD t; + int lab; + + if (retlab != NOLAB) { + plabel(retlab); + retlab = getlab(); + } + + t = DECREF(cftnsp->stype); + if (t == BOOL) + t = BOOL_TYPE; + + p = block(NAME, NIL, NIL, INT, 0, 0); + p->n_sp = lookup(stack_chk_canary, SNORMAL); + p = clocal(p); + + q = block(REG, NIL, NIL, INCREF(INT), 0, 0); + slval(q, 0); + q->n_rval = FPREG; + q = cast(q, INT, 0); + q = buildtree(ER, p, q); + + p = block(NAME, NIL, NIL, INT, 0, 0); + p->n_sp = lookup(stack_chk_guard, SNORMAL); + p = clocal(p); + + lab = getlab(); + cbranch(buildtree(EQ, p, q), bcon(lab)); + + p = block(NAME, NIL, NIL, FTN+VOID, 0, 0); + p->n_sp = lookup(stack_chk_fail, SNORMAL); + p = clocal(p); + + q = eve(bdty(STRING, cftnsp->sname, PTR|CHAR)); + ecomp(buildtree(CALL, p, q)); + + plabel(lab); +} + +/* + * Fetch pointer to first member in a struct list. + */ +struct symtab * +strmemb(struct attr *ap) +{ + + if ((ap = attr_find(ap, ATTR_STRUCT)) == NULL) + cerror("strmemb"); + return ap->amlist; +} + +#ifndef NO_COMPLEX + +static char *real, *imag; +static struct symtab *cxsp[3], *cxmul[3], *cxdiv[3]; +static char *cxnmul[] = { "__mulsc3", "__muldc3", "__mulxc3" }; +static char *cxndiv[] = { "__divsc3", "__divdc3", "__divxc3" }; +/* + * As complex numbers internally are handled as structs, create + * these by hand-crafting them. + */ +void +complinit(void) +{ + struct attr *ap; + struct rstack *rp; + NODE *p, *q; + char *n[] = { "0f", "0d", "0l" }; + int i, d_debug; + + d_debug = ddebug; + ddebug = 0; + real = addname("__real"); + imag = addname("__imag"); + p = block(NAME, NIL, NIL, FLOAT, 0, 0); + for (i = 0; i < 3; i++) { + p->n_type = FLOAT+i; + rpole = rp = bstruct(NULL, STNAME, NULL); + soumemb(p, real, 0); + soumemb(p, imag, 0); + q = dclstruct(rp); + cxsp[i] = q->n_sp = lookup(addname(n[i]), 0); + defid(q, TYPEDEF); + ap = attr_new(ATTR_COMPLEX, 0); + q->n_sp->sap = attr_add(q->n_sp->sap, ap); + nfree(q); + } + /* create function declarations for external ops */ + for (i = 0; i < 3; i++) { + cxnmul[i] = addname(cxnmul[i]); + p->n_sp = cxmul[i] = lookup(cxnmul[i], 0); + p->n_type = FTN|STRTY; + p->n_ap = cxsp[i]->sap; + p->n_df = cxsp[i]->sdf; + defid2(p, EXTERN, 0); + cxmul[i]->sdf = permalloc(sizeof(union dimfun)); + dimfuncnt++; + cxmul[i]->sdf->dfun = NULL; + cxndiv[i] = addname(cxndiv[i]); + p->n_sp = cxdiv[i] = lookup(cxndiv[i], 0); + p->n_type = FTN|STRTY; + p->n_ap = cxsp[i]->sap; + p->n_df = cxsp[i]->sdf; + defid2(p, EXTERN, 0); + cxdiv[i]->sdf = permalloc(sizeof(union dimfun)); + dimfuncnt++; + cxdiv[i]->sdf->dfun = NULL; + } + nfree(p); + ddebug = d_debug; +} + +static TWORD +maxtt(NODE *p) +{ + TWORD t; + + t = ANYCX(p) ? strmemb(p->n_ap)->stype : p->n_type; + t = BTYPE(t); + if (t == VOID) + t = CHAR; /* pointers */ + if (ISITY(t)) + t -= (FIMAG - FLOAT); + return t; +} + +/* + * Return the highest real floating point type. + * Known that at least one type is complex or imaginary. + */ +static TWORD +maxtyp(NODE *l, NODE *r) +{ + TWORD tl, tr, t; + + tl = maxtt(l); + tr = maxtt(r); + t = tl > tr ? tl : tr; + if (!ISFTY(t)) + cerror("maxtyp"); + return t; +} + +/* + * Fetch space on stack for complex struct. + */ +static NODE * +cxstore(TWORD t) +{ + struct symtab s; + + s = *cxsp[t - FLOAT]; + s.sclass = AUTO; + s.soffset = NOOFFSET; + oalloc(&s, &autooff); + return nametree(&s); +} + +#define comop(x,y) buildtree(COMOP, x, y) + +/* + * Convert node p to complex type dt. + */ +static NODE * +mkcmplx(NODE *p, TWORD dt) +{ + NODE *q, *r, *i, *t; + + if (!ANYCX(p)) { + /* Not complex, convert to complex on stack */ + q = cxstore(dt); + if (ISITY(p->n_type)) { + p->n_type = p->n_type - FIMAG + FLOAT; + r = bcon(0); + i = p; + } else { + if (ISPTR(p->n_type)) + p = cast(p, INTPTR, 0); + r = p; + i = bcon(0); + } + p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), r); + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), i)); + p = comop(p, q); + } else { + if (strmemb(p->n_ap)->stype != dt) { + q = cxstore(dt); + p = buildtree(ADDROF, p, NIL); + t = tempnode(0, p->n_type, p->n_df, p->n_ap); + p = buildtree(ASSIGN, ccopy(t), p); + p = comop(p, buildtree(ASSIGN, + structref(ccopy(q), DOT, real), + structref(ccopy(t), STREF, real))); + p = comop(p, buildtree(ASSIGN, + structref(ccopy(q), DOT, imag), + structref(t, STREF, imag))); + p = comop(p, q); + } + } + return p; +} + +static NODE * +cxasg(NODE *l, NODE *r) +{ + TWORD tl, tr; + + tl = strattr(l->n_ap) ? strmemb(l->n_ap)->stype : 0; + tr = strattr(r->n_ap) ? strmemb(r->n_ap)->stype : 0; + + if (ANYCX(l) && ANYCX(r) && tl != tr) { + /* different types in structs */ + r = mkcmplx(r, tl); + } else if (!ANYCX(l)) + r = structref(r, DOT, ISITY(l->n_type) ? imag : real); + else if (!ANYCX(r)) + r = mkcmplx(r, tl); + return buildtree(ASSIGN, l, r); +} + +/* + * Fixup complex operations. + * At least one operand is complex. + */ +NODE * +cxop(int op, NODE *l, NODE *r) +{ + TWORD mxtyp; + NODE *p, *q; + NODE *ltemp, *rtemp; + NODE *real_l, *imag_l; + NODE *real_r, *imag_r; + real_r = imag_r = NULL; /* bad uninit var warning */ + + if (op == ASSIGN) + return cxasg(l, r); + + mxtyp = maxtyp(l, r); + l = mkcmplx(l, mxtyp); + if (op != UMINUS) + r = mkcmplx(r, mxtyp); + + if (op == COLON) + return buildtree(COLON, l, r); + + /* put a pointer to left and right elements in a TEMP */ + l = buildtree(ADDROF, l, NIL); + ltemp = tempnode(0, l->n_type, l->n_df, l->n_ap); + l = buildtree(ASSIGN, ccopy(ltemp), l); + + if (op != UMINUS) { + r = buildtree(ADDROF, r, NIL); + rtemp = tempnode(0, r->n_type, r->n_df, r->n_ap); + r = buildtree(ASSIGN, ccopy(rtemp), r); + + p = comop(l, r); + } else + p = l; + + /* create the four trees needed for calculation */ + real_l = structref(ccopy(ltemp), STREF, real); + imag_l = structref(ltemp, STREF, imag); + if (op != UMINUS) { + real_r = structref(ccopy(rtemp), STREF, real); + imag_r = structref(rtemp, STREF, imag); + } + + /* get storage on stack for the result */ + q = cxstore(mxtyp); + + switch (op) { + case NE: + case EQ: + tfree(q); + p = buildtree(op, comop(p, real_l), real_r); + q = buildtree(op, imag_l, imag_r); + p = buildtree(op == EQ ? ANDAND : OROR, p, q); + return p; + + case ANDAND: + case OROR: /* go via EQ to get INT of it */ + tfree(q); + p = buildtree(NE, comop(p, real_l), bcon(0)); /* gets INT */ + q = buildtree(NE, imag_l, bcon(0)); + p = buildtree(OR, p, q); + + q = buildtree(NE, real_r, bcon(0)); + q = buildtree(OR, q, buildtree(NE, imag_r, bcon(0))); + + p = buildtree(op, p, q); + return p; + + case UMINUS: + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), + buildtree(op, real_l, NIL))); + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), + buildtree(op, imag_l, NIL))); + break; + + case PLUS: + case MINUS: + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), + buildtree(op, real_l, real_r))); + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), + buildtree(op, imag_l, imag_r))); + break; + + case MUL: + case DIV: + /* Complex mul is "complex" */ + /* (u+iv)*(x+iy)=((u*x)-(v*y))+i(v*x+y*u) */ + /* Complex div is even more "complex" */ + /* (u+iv)/(x+iy)=(u*x+v*y)/(x*x+y*y)+i((v*x-u*y)/(x*x+y*y)) */ + /* but we need to do it via a subroutine */ + tfree(q); + p = buildtree(CM, comop(p, real_l), imag_l); + p = buildtree(CM, p, real_r); + p = buildtree(CM, p, imag_r); + q = nametree(op == DIV ? + cxdiv[mxtyp-FLOAT] : cxmul[mxtyp-FLOAT]); + return buildtree(CALL, q, p); + break; + default: + uerror("illegal operator %s", copst(op)); + } + return comop(p, q); +} + +/* + * Fixup imaginary operations. + * At least one operand is imaginary, none is complex. + */ +NODE * +imop(int op, NODE *l, NODE *r) +{ + NODE *p, *q; + TWORD mxtyp; + int li, ri; + + li = ri = 0; + if (ISITY(l->n_type)) + li = 1, l->n_type = l->n_type - (FIMAG-FLOAT); + if (ISITY(r->n_type)) + ri = 1, r->n_type = r->n_type - (FIMAG-FLOAT); + + mxtyp = maxtyp(l, r); + switch (op) { + case ASSIGN: + /* if both are imag, store value, otherwise store 0.0 */ + if (!(li && ri)) { + tfree(r); + r = bcon(0); + } + p = buildtree(ASSIGN, l, r); + p->n_type += (FIMAG-FLOAT); + break; + + case PLUS: + if (li && ri) { + p = buildtree(PLUS, l, r); + p->n_type += (FIMAG-FLOAT); + } else { + /* If one is imaginary and one is real, make complex */ + if (li) + q = l, l = r, r = q; /* switch */ + q = cxstore(mxtyp); + p = buildtree(ASSIGN, + structref(ccopy(q), DOT, real), l); + p = comop(p, buildtree(ASSIGN, + structref(ccopy(q), DOT, imag), r)); + p = comop(p, q); + } + break; + + case MINUS: + if (li && ri) { + p = buildtree(MINUS, l, r); + p->n_type += (FIMAG-FLOAT); + } else if (li) { + q = cxstore(mxtyp); + p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), + buildtree(UMINUS, r, NIL)); + p = comop(p, buildtree(ASSIGN, + structref(ccopy(q), DOT, imag), l)); + p = comop(p, q); + } else /* if (ri) */ { + q = cxstore(mxtyp); + p = buildtree(ASSIGN, + structref(ccopy(q), DOT, real), l); + p = comop(p, buildtree(ASSIGN, + structref(ccopy(q), DOT, imag), + buildtree(UMINUS, r, NIL))); + p = comop(p, q); + } + break; + + case MUL: + p = buildtree(MUL, l, r); + if (li && ri) + p = buildtree(UMINUS, p, NIL); + if (li ^ ri) + p->n_type += (FIMAG-FLOAT); + break; + + case DIV: + p = buildtree(DIV, l, r); + if (ri && !li) + p = buildtree(UMINUS, p, NIL); + if (li ^ ri) + p->n_type += (FIMAG-FLOAT); + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + if (li ^ ri) { /* always 0 */ + tfree(l); + tfree(r); + p = bcon(0); + } else + p = buildtree(op, l, r); + break; + + default: + cerror("imop"); + p = NULL; + } + return p; +} + +NODE * +cxelem(int op, NODE *p) +{ + + if (ANYCX(p)) { + p = structref(p, DOT, op == XREAL ? real : imag); + } else if (op == XIMAG) { + /* XXX sanitycheck? */ + tfree(p); + p = bcon(0); + } + return p; +} + +NODE * +cxconj(NODE *p) +{ + NODE *q, *r; + + /* XXX side effects? */ + q = cxstore(strmemb(p->n_ap)->stype); + r = buildtree(ASSIGN, structref(ccopy(q), DOT, real), + structref(ccopy(p), DOT, real)); + r = comop(r, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), + buildtree(UMINUS, structref(p, DOT, imag), NIL))); + return comop(r, q); +} + +/* + * Prepare for return. + * There may be implicit casts to other types. + */ +NODE * +imret(NODE *p, NODE *q) +{ + if (ISITY(q->n_type) && ISITY(p->n_type)) { + if (p->n_type != q->n_type) { + p->n_type -= (FIMAG-FLOAT); + p = cast(p, q->n_type - (FIMAG-FLOAT), 0); + p->n_type += (FIMAG-FLOAT); + } + } else { + p1tfree(p); + if (ISITY(q->n_type)) { + p = block(FCON, 0, 0, q->n_type, 0, 0); + p->n_dcon = fltallo(); + *p->n_dcon = *FLOAT_ZERO; + } else + p = bcon(0); + } + + return p; +} + +/* + * Prepare for return. + * There may be implicit casts to other types. + */ +NODE * +cxret(NODE *p, NODE *q) +{ + if (ANYCX(q)) { /* Return complex type */ + p = mkcmplx(p, strmemb(q->n_ap)->stype); + } else if (q->n_type < STRTY || ISITY(q->n_type)) { /* real or imag */ + p = structref(p, DOT, ISITY(q->n_type) ? imag : real); + if (p->n_type != q->n_type) + p = cast(p, q->n_type, 0); + } else + cerror("cxred failing type"); + return p; +} + +/* + * either p1 or p2 is complex, so fixup the remaining type accordingly. + */ +NODE * +cxcast(NODE *p1, NODE *p2) +{ + if (ANYCX(p1) && ANYCX(p2)) { + if (p1->n_type != p2->n_type) + p2 = mkcmplx(p2, p1->n_type); + } else if (ANYCX(p1)) { + p2 = mkcmplx(p2, strmemb(p1->n_ap)->stype); + } else /* if (ANYCX(p2)) */ { + p2 = cast(structref(p2, DOT, real), p1->n_type, 0); + } + nfree(p1); + return p2; +} + +static void +cxargfixup(NODE *a, TWORD dt, struct attr *ap) +{ + NODE *p; + TWORD t; + + p = p1alloc(); + *p = *a; + if (dt == STRTY) { + /* dest complex */ + t = strmemb(ap)->stype; + p = mkcmplx(p, t); + } else { + /* src complex, not dest */ + p = structref(p, DOT, ISFTY(dt) ? real : imag); + } + *a = *p; + nfree(p); +} +#endif + +/* + * Allocations: + * permalloc() Never freed. in pass2. + * tmpalloc() during a function lifetime, then freed. in pass2. + * blkalloc() during a block lifetime. Variables etc. In pass1. + * stmtalloc() during a statement lifetime. Expression trees. In pass1. + */ + +/* + * Short-time allocations during statements. + */ +#define MEMCHUNKSZ 8192 /* 8k per allocation */ +struct balloc { + char a1; + union { + long long l; + long double d; + } a2; +}; +#define ALIGNMENT offsetof(struct balloc, a2) +#define ROUNDUP(x) (((x) + ((ALIGNMENT)-1)) & ~((ALIGNMENT)-1)) + +#define MAXSZ MEMCHUNKSZ-sizeof(struct xalloc *) +struct xalloc { + struct xalloc *next; + union { + long long b; /* for initial alignment */ + long double d; + char elm[MAXSZ]; + }; +} *sapole, *bkpole; +int cstp, cbkp; + +void * +stmtalloc(size_t size) +{ + struct xalloc *xp; + void *rv; + + size = ROUNDUP(size); + if (size > MAXSZ) + cerror("stmtalloc"); + if (sapole == 0 || (size + cstp) > MAXSZ) { + xp = xmalloc(sizeof(struct xalloc)); + xp->next = sapole; + sapole = xp; + cstp = 0; + } + rv = &sapole->elm[cstp]; + cstp += size; + return rv; +} + +void +stmtfree(void) +{ + extern P1ND *frelink; + extern int usdnodes; + struct xalloc *x1; + + if (usdnodes != 0) + cerror("stmtfree: usdnodes %d", usdnodes); + frelink = NULL; + + while (sapole) { + x1 = sapole->next; + free(sapole); + sapole = x1; + } + cstp = 0; +} + +void * +blkalloc(size_t size) +{ + struct xalloc *xp; + void *rv; + + if (blevel < 2) + return permalloc(size); + + size = ROUNDUP(size); + if (size > MAXSZ) + cerror("blkalloc"); + if (bkpole == 0 || (size + cbkp) > MAXSZ) { + xp = xmalloc(sizeof(struct xalloc)); + xp->next = bkpole; + bkpole = xp; + cbkp = 0; + } + rv = &bkpole->elm[cbkp]; + cbkp += size; + return rv; +} + +void +blkfree(void) +{ + struct xalloc *x1; + + while (bkpole) { + x1 = bkpole->next; + free(bkpole); + bkpole = x1; + } + cbkp = 0; +} + diff --git a/lang/pcc/pcc/cc/ccom/scan.l b/lang/pcc/pcc/cc/ccom/scan.l new file mode 100644 index 000000000..31a896135 --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/scan.l @@ -0,0 +1,958 @@ +%{ +/* $Id: scan.l,v 1.147 2016/03/08 18:17:45 ragge Exp $ */ + +/* + * Copyright (c) 2002 Anders Magnusson. All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ +%} + + +B [0-1] +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +P [Pp][+-]?{D}+ +FS ((f|F|l|L)?i|i?(f|F|l|L)) +IS (u|U|l|L|i)* +UL ({L}|[\x80-\xFF]) +UC (L|u|U) +US (L|u|U|u8) + +%{ +#include +#include +#include +#include +#include + +#include "pass1.h" +#include "cgram.h" +#include "unicode.h" + +#define bdebug flexbdebug + +static P1ND *cvtdig(int radix); +static P1ND *charcon(void); +static P1ND *wcharcon(void); +static void control(int); +static void pragma(void); +int notype, parbal, inattr, parlvl, nodinit, inoso; +int kwdecode(struct symtab *s); + +#define CPP_IDENT 2 +#define CPP_LINE 3 +#define CPP_HASH 4 + +#ifdef STABS +#define STABS_LINE(x) if (gflag && cftnsp) stabs_line(x) +#else +#define STABS_LINE(x) +#endif +#if defined(FLEX_SCANNER) && YY_FLEX_SUBMINOR_VERSION == 31 +/* Hack to avoid unnecessary warnings */ +FILE *yyget_in (void); +FILE *yyget_out (void); +int yyget_leng (void); +char *yyget_text (void); +void yyset_in (FILE *); +void yyset_out (FILE *); +int yyget_debug (void); +void yyset_debug (int); +int yylex_destroy (void); +extern int yyget_lineno (void); +extern void yyset_lineno (int); +#endif + +%} + +%% + +{UL}({UL}|{D})* { struct symtab *s; + int i = 0; + + yylval.strp = addname(yytext); + if ((s = lookup(yylval.strp, SNOCREAT)) != NULL && + s->sclass == KEYWORD) + return kwdecode(s); + +#ifdef GCC_COMPAT + if (doing_init && nodinit == 0) { + /* check for name: for old gcc compat */ + while ((i = input()) == ' ' || i == '\t') + ; + if (i == ':') + return(GCC_DESIG); + unput(i); + } + if ((i = gcc_keyword(yylval.strp)) > 0) { + if (i == PCC_OFFSETOF) + inoso = 1; + return i; + } +#endif + if (i == 0) { + if (notype) + return(C_NAME); + return s && s->sclass == TYPEDEF ? + notype=1, C_TYPENAME : C_NAME; + } + } + +0[xX]{H}+{IS}? { yylval.nodep = cvtdig(16); return(C_ICON); } +0{D}+{IS}? { yylval.nodep = cvtdig(8); return(C_ICON); } +0[bB]{B}+{IS}? { yylval.nodep = cvtdig(2); return(C_ICON); } +{D}+{IS}? { yylval.nodep = cvtdig(10); return(C_ICON); } +{UC}'(\\.|[^\\'])*' { yylval.nodep = wcharcon(); return(C_ICON); } +'(\\.|[^\\'])*' { yylval.nodep = charcon(); return(C_ICON); } + +{D}+{E}{FS}? { yylval.flt = floatcon(yytext); return(C_FCON); } +{D}*"."{D}+({E})?{FS}? { yylval.flt = floatcon(yytext); return(C_FCON); } +{D}+"."{D}*({E})?{FS}? { yylval.flt = floatcon(yytext); return(C_FCON); } +0[xX]{H}*"."{H}+{P}{FS}? { yylval.flt = fhexcon(yytext); return(C_FCON); } +0[xX]{H}+"."{P}{FS}? { yylval.flt = fhexcon(yytext); return(C_FCON); } +0[xX]{H}+{P}{FS}? { yylval.flt = fhexcon(yytext); return(C_FCON); } + +{US}?\"(\\.|[^\\"])*\" { yylval.strp = yytext; return C_STRING; } + +"..." { return(C_ELLIPSIS); } +">>=" { yylval.intval = RSEQ; return(C_ASOP); } +"<<=" { yylval.intval = LSEQ; return(C_ASOP); } +"+=" { yylval.intval = PLUSEQ; return(C_ASOP); } +"-=" { yylval.intval = MINUSEQ; return(C_ASOP); } +"*=" { yylval.intval = MULEQ; return(C_ASOP); } +"/=" { yylval.intval = DIVEQ; return(C_ASOP); } +"%=" { yylval.intval = MODEQ; return(C_ASOP); } +"&=" { yylval.intval = ANDEQ; return(C_ASOP); } +"^=" { yylval.intval = EREQ; return(C_ASOP); } +"|=" { yylval.intval = OREQ; return(C_ASOP); } +">>" { yylval.intval = RS; return(C_SHIFTOP); } +"<<" { yylval.intval = LS; return(C_SHIFTOP); } +"++" { yylval.intval = INCR; return(C_INCOP); } +"--" { yylval.intval = DECR; return(C_INCOP); } +"->" { yylval.intval = STREF; return(C_STROP); } +"&&" { yylval.intval = ANDAND; return(C_ANDAND); } +"||" { yylval.intval = OROR; return(C_OROR); } +"<=" { yylval.intval = LE; return(C_RELOP); } +">=" { yylval.intval = GE; return(C_RELOP); } +"==" { yylval.intval = EQ; return(C_EQUOP); } +"!=" { yylval.intval = NE; return(C_EQUOP); } +";" { notype = 0; return(';'); } +("{"|"<%") { notype = 0; return('{'); } +("}"|"%>") { if (rpole) notype = 1; return('}'); } +"," { if (parbal && !inoso) notype = 0; + if (parbal == 0) notype = 1; return(','); } +":" { if (doing_init) nodinit--; return(':'); } +"=" { return('='); } +"(" { parbal++; notype = 0; return('('); } +")" { parbal--; + inoso = 0; + if (parbal==0) { notype = 0; } + if (inattr && parlvl == parbal) + inattr = 0; + return(')'); } +("["|"<:") { return('['); } +("]"|":>") { return(']'); } +"." { yylval.intval = DOT; return(C_STROP); } +"&" { return('&'); } +"!" { yylval.intval = NOT; return(C_UNOP); } +"~" { yylval.intval = COMPL; return(C_UNOP); } +"-" { return('-'); } +"+" { return('+'); } +"*" { if (parbal && notype == 0) notype = 1; return('*'); } +"/" { yylval.intval = DIV; return(C_DIVOP); } +"%" { yylval.intval = MOD; return(C_DIVOP); } +"<" { yylval.intval = LT; return(C_RELOP); } +">" { yylval.intval = GT; return(C_RELOP); } +"^" { return('^'); } +"|" { return('|'); } +"?" { if (doing_init) nodinit++; return('?'); } +^#pragma[ \t].* { pragma(); } +^#ident[ \t].* { control(CPP_IDENT); } +^#line[ \t].* { control(CPP_LINE); } +^#.* { control(CPP_HASH); } + +[ \t\v\f] { } +"\n" { ++lineno; STABS_LINE(lineno); } +. { /* ignore bad characters */ } + +%% + +int lineno, issyshdr; + +int +yywrap(void) +{ + if (0) unput(0); /* quiet gcc */ + return(1); +} + +#define DEFKW 500 +#define KWFUNC 501 +#define KWNOT 502 + +struct keywords { + char *name; + int cword, wclass; +} keywords[] = { + { "__func__", 0, KWFUNC }, + { "_Alignas", C_ALIGNAS, DEFKW }, + { "_Alignof", C_ALIGNOF, DEFKW }, + { "_Atomic", C_ATOMIC, DEFKW }, + { "asm", C_ASM, DEFKW }, + { "auto", AUTO, C_CLASS }, + { "_Bool", BOOL, C_TYPE }, + { "break", C_BREAK, DEFKW }, + { "case", C_CASE, DEFKW }, + { "char", CHAR, C_TYPE }, + { "continue", C_CONTINUE, DEFKW }, + { "_Complex", COMPLEX, C_TYPE }, + { "const", CON, C_QUALIFIER }, + { "default", C_DEFAULT, DEFKW }, + { "do", C_DO, DEFKW }, + { "double", DOUBLE, C_TYPE }, + { "else", C_ELSE, DEFKW }, + { "enum", C_ENUM, KWNOT }, + { "extern", EXTERN, C_CLASS }, + { "float", FLOAT, C_TYPE }, + { "for", C_FOR, DEFKW }, + { "_Generic", C_GENERIC, DEFKW }, + { "goto", C_GOTO, KWNOT }, + { "if", C_IF, DEFKW }, + { "_Imaginary", IMAG, C_TYPE }, + { "inline", INLINE, C_FUNSPEC }, + { "int", INT, C_TYPE }, + { "long", LONG, C_TYPE }, + { "_Noreturn", NORETURN, C_FUNSPEC }, + { "register", REGISTER, C_CLASS }, + { "restrict", 0, C_QUALIFIER }, + { "return", C_RETURN, DEFKW }, + { "short", SHORT, C_TYPE }, + { "signed", SIGNED, C_TYPE }, + { "sizeof", C_SIZEOF, DEFKW }, + { "static", STATIC, C_CLASS }, + { "_Static_assert", C_STATICASSERT, DEFKW }, + { "struct", STNAME, C_STRUCT }, + { "switch", C_SWITCH, DEFKW }, + { "_Thread_local", THLOCAL, C_CLASS }, + { "typedef", TYPEDEF, C_CLASS }, + { "union", UNAME, C_STRUCT }, + { "unsigned", UNSIGNED, C_TYPE }, + { "void", VOID, C_TYPE }, + { "volatile", VOL, C_QUALIFIER }, + { "while", C_WHILE, DEFKW }, +}; + + +void +kwinit(void) +{ + struct symtab *s; + int i, n = sizeof(keywords) / sizeof(keywords[0]); + + for (i = 0; i < n; i++) { + s = lookup(addname(keywords[i].name), 0); + s->sclass = KEYWORD; + s->soffset = i; + } +} + +int +kwdecode(struct symtab *s) +{ + struct keywords *kw = &keywords[s->soffset]; + + if (inattr && kw->cword != C_SIZEOF) + return C_NAME; + + switch (kw->wclass) { + case C_TYPE: + yylval.type = kw->cword; + notype=1; + break; + + case C_CLASS: + if (kw->cword == THLOCAL) + uerror("_Thread_local not supported"); + yylval.type = kw->cword; + break; + + case C_QUALIFIER: + yylval.type = kw->cword; + break; + + case C_FUNSPEC: + yylval.type = kw->cword; + break; + + case DEFKW: + return kw->cword; + + case KWFUNC: + if (cftnsp == NULL) + uerror("__func__ outside function"); + yylval.strp = cftnsp->sname; + return(C_STRING); + + case KWNOT: + notype = 1; + return kw->cword; + + case C_STRUCT: + notype = 1; + yylval.intval = kw->cword; + break; + + default: + cerror("keyword %s not found", kw->name); + } + return kw->wclass; +} + +static long double +typround(long double dc, char *e, TWORD *tw) +{ + int im = 0; + + *tw = DOUBLE; + for (; *e; e++) { + switch (*e) { + case 'f': + case 'F': + *tw = FLOAT; + dc = (float)dc; + break; + case 'l': + case 'L': + *tw = ctype(LDOUBLE); + break; + case 'i': + case 'I': + im = 1; + break; + } + } + if (*tw == DOUBLE) + dc = (double)dc; +#ifndef NO_COMPLEX + if (im) + *tw += (FIMAG-FLOAT); +#endif + return dc; +} + +/* + * Return which type current fp string has. + */ +static TWORD +endtyp(char *s) +{ + TWORD tw = DOUBLE; + + for (; *s; s++) + ; + s--; + if (*s == 'i' || *s == 'I') + tw += (FIMAG-FLOAT), s--; + if (*s == 'f' || *s == 'F') + tw--, s--; + else if (*s == 'l' || *s == 'L') + tw++, s--; + if ((*s == 'i' || *s == 'I') && ISFTY(tw)) + tw += (FIMAG-FLOAT), s--; +/* XXX complain */ + return tw; +} + +FLT * +floatcon(char *s) +{ + FLT *flt; + TWORD tw; + + flt = stmtalloc(sizeof(FLT)); +#ifdef NATIVE_FLOATING_POINT +#ifdef HAVE_STRTOLD + flt->fp = strtold(s, NULL); +#else + flt->fp = strtod(s, NULL); +#endif +#else + flt->sf = strtosf(s); /* parse number */ +#endif + flt->t = tw = endtyp(s); + if (ISITY(tw)) + tw -= (FIMAG-FLOAT); + return flt; +} + +static int +h2n(int ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + return ch - 'A' + 10; + +} + +/* + * Get exponent. Max size is 16 bits. + */ +static int +fdecl(char *c, char **ep) +{ + int minus = 0; + int val = 0; + + if (*c == '+') + c++; + else if (*c == '-') + minus = 1, c++; + + while (isdigit((int)*c)) { + val *= 10; + val += *c++ - '0'; + if (val > 32769) + val = 32769; + } + if (minus) + val = -val; + *ep = c; + return val; +} + +FLT * +fhexcon(char *c) +{ + FLT *flt; + TWORD tw; + char *ep; + long double d; + int i, ed; + + d = 0.0; + ed = 0; + c+= 2; /* skip 0x */ +#define FSET(n) { d *= 2; if (i & n) d += 1.0; } + for (; *c != '.' && *c != 'p' && *c != 'P'; c++) { + i = h2n(*c); + FSET(8); FSET(4); FSET(2); FSET(1); + } + if (*c != '.' && *c != 'p' && *c != 'P') + cerror("fhexcon"); + if (*c == '.') { + c++; + for (; *c != 'p' && *c != 'P'; c++) { + i = h2n(*c); + FSET(8); FSET(4); FSET(2); FSET(1); + ed -= 4; + } + } + if (*c != 'P' && *c != 'p') + cerror("fhexcon2"); + c++; + ed += fdecl(c, &ep); + + /* avoid looping in vain. Idea from Fred J. Tydeman */ + if (ed > 32769) ed = 32769; + if (ed < -32769) ed = -32769; + + while (ed > 0) + d *= 2, ed--; + while (ed < 0) + d /= 2, ed++; + d = typround(d, ep, &tw); + flt = stmtalloc(sizeof(FLT)); + flt->fp = d; + flt->t = tw; + return flt; +} + +P1ND * +cvtdig(int radix) +{ + P1ND *p; + TWORD ntype; + unsigned long long v; + char *ch = yytext; + int n, numl, numu; + + if (radix == 16 || radix == 2) + ch += 2; /* Skip 0x or 0b */ + + v = 0; + while ((*ch >= '0' && *ch <= '9') || (*ch >= 'a' && *ch <= 'f') || + (*ch >= 'A' && *ch <= 'F')) { + v *= radix; + n = *ch; + n = (n <= '9' ? n - '0' : (n > 'F' ? n - 'a' : n - 'A') + 10); + ch++; + v += n; + } + /* Parse trailing chars */ + ntype = INT; + numl = numu = 0; + for (n = 0; n < 3; n++) { + if (*ch == 0) + break; + if ((*ch == 'l' || *ch == 'L') && numl < 2) + ntype+=2, numl++; + else if ((*ch == 'u' || *ch == 'U') && numu < 1) + ntype = ENUNSIGN(ntype), numu++; + else if (*ch == 'i') + ntype = DOUBLE; + else + break; + ch++; + } + if (*ch) + uerror("constant has too many '%c'", *ch); + + switch (ntype) { + case DOUBLE: /* special case */ + p = block(FCON, NULL, NULL, IMAG, 0, 0); + p->n_dcon = stmtalloc(sizeof(FLT)); + FLOAT_INT2FP(p->n_dcon, v, ULONGLONG); + FLOAT_FP2FP(p->n_dcon, DOUBLE); + return p; + + case INT: + case LONG: + case LONGLONG: + if (radix == 10) { + if (ntype == LONGLONG) + break; + if (v > MAX_LONG) + ntype = LONGLONG; + else if (v > MAX_INT) + ntype = LONG; + } else { + if (v > MAX_LONGLONG) { + ntype = ULONGLONG; + } else if (v > MAX_ULONG) { + if (ntype < LONGLONG) + ntype = LONGLONG; + } else if (v > MAX_LONG) { + if (ntype < ULONG) + ntype = ULONG; + } else if (v > MAX_UNSIGNED) { + if (ntype < LONG) + ntype = LONG; + } else if (v > MAX_INT) { + if (ntype < UNSIGNED) + ntype = UNSIGNED; + } + } + break; + case UNSIGNED: + case ULONG: + if (v > MAX_ULONG) { + ntype = ULONGLONG; + } else if (v > MAX_UNSIGNED) + ntype = ULONG; + break; + } + + ntype = ctype(ntype); + p = xbcon(v, NULL, ntype); + ASGLVAL(p->n_slval, v); + + return p; +} + +/* + * return value of escaped character constant + */ +unsigned int +esccon(char **sptr) +{ + unsigned int val; + char *wr = *sptr; + char c; + + wr++; /* skip \ */ + switch (c = *wr++) { + case 'a': val = '\a'; break; + case 'b': val = '\b'; break; +#ifdef GCC_COMPAT + case 'e': val = '\033'; break; +#endif + case 'f': val = '\f'; break; + case 'n': val = '\n'; break; + case 'r': val = '\r'; break; + case 't': val = '\t'; break; + case 'v': val = '\v'; break; + + case '\"': val = '\"'; break; + case '\'': val = '\''; break; + case '\?': val = '\?'; break; + case '\\': val = '\\'; break; + + case 'x': + val = 0; + for (;;) { + c = *wr; + if (c >= '0' && c <= '9') + c = c - '0'; + else if (c >= 'a' && c <= 'f') + c = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + c = c - 'A' + 10; + else + break; + + val = (val << 4) + c; + wr++; + } + break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + val = (c - '0'); + c = *wr; + if (c >= '0' && c <= '7') { + wr++; + val = (val << 3) + (c - '0'); + c = *wr; + if (c >= '0' && c <= '7') { + wr++; + val = (val << 3) + (c - '0'); + } + } + break; + + default: + werror("unknown escape sequence \\%c", c); + val = c; + break; + } + + *sptr = wr; + return val; +} + +/* + * Convert (one) character constant to an int. + * Handle as unsigned except if only one character and char is signed. + */ +P1ND * +charcon(void) +{ + unsigned int val = 0, i = 0; + char *pp = yytext; + + pp++; /* skip ' */ + while (*pp != '\'') { + val <<= SZCHAR; /* XXX big endian? */ + if (*pp == '\\') + val |= esccon(&pp); + else + val |= (*pp++ & ((1 << SZCHAR)-1)); + i++; + } + + if (i == 0) + uerror("empty character constant"); + else if (i == 1 && xuchar == 0) + val = (signed char)val; /* XXX other sizes of char? */ + else if (i > 1) + werror("too many characters in character constant"); + + return bcon(val); +} + +/* + * Convert a wide-character constant to an unsigned int + */ +P1ND * +wcharcon(void) +{ + unsigned int val = 0, i = 0; + char *pp = yytext; + + pp++; /* skip L */ + pp++; /* skip ' */ + while (*pp != '\'') { + /* + * although u82cp() does handle escaped values, we deal + * with them directly since otherwise you can't process + * values which might be valid utf8 prefix + */ + if (*pp == '\\') + val = esccon(&pp); + else + val = u82cp(&pp); + + i++; + } + + if (i == 0) + uerror("empty wide-character constant"); + else if (i > 1) + werror("too many characters in wide-character constant"); + + return xbcon(val, NULL, ctype(UNSIGNED)); +} + +void +control(int t) +{ + char *wr = yytext; + char *eptr; + int val; + + wr++; /* Skip initial '#' */ + switch (t) { + case CPP_IDENT: + return; /* Just skip these for now. */ + + case CPP_LINE: + wr += 4; + /* FALLTHROUGH */ + case CPP_HASH: + val = strtol(wr, &eptr, 10); + if (wr == eptr) /* Illegal string */ + goto bad; + wr = eptr; + lineno = val - 1; + while (*wr && *wr != '\"') + wr++; + if (*wr == 0) + return; + if (*wr++ != '\"') + goto bad; + eptr = wr; + while (*wr && *wr != '\"') + wr++; + if (*wr != '\"') + goto bad; + *wr++ = 0; + free(ftitle); + ftitle = xstrdup(eptr); + while (*wr == ' ') + wr++; + issyshdr = 0; + if (*wr == '3') + issyshdr = 1; +#ifdef DWARF + if (gflag) + dwarf_file(ftitle); +#endif +#ifdef STABS + if (gflag) + stabs_file(ftitle); +#endif + } + return; +bad: + werror("%s: illegal control", yytext); +} + +int pragma_allpacked; +int pragma_packed, pragma_aligned; + +static int +pragmas_weak(char *str) +{ + struct symtab *sp; + char *s1, *s2; + + if ((s1 = pragtok(NULL)) == NULL) + return 1; + if ((s2 = pragtok(NULL)) == NULL) { + sp = lookup(addname(s1), SNORMAL); +#ifdef GCC_COMPAT + sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(NAME, "weak"))); +#else + sp->sap = NULL; +#endif + } else if (*s2 == '=') { + if ((s2 = pragtok(NULL)) == NULL) + return 1; + sp = lookup(addname(s2), SNORMAL); +#ifdef GCC_COMPAT + sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(CALL, + bdty(NAME, "aliasweak"), bdty(STRING, s1, 0)))); +#else + sp->sap = NULL; +#endif + } else + return 1; + return 0; +} + +char *pragstore; + +/* trivial tokenizer for pragmas */ +#define ps pragstore +char * +pragtok(char *sin) +{ + static char ss[2]; + char *rv; + + if (sin) + ps = sin; + + for (; isspace((int)*ps); ps++) + ; + if (*ps == 0) + return NULL; + for (rv = ps; isalpha((int)*ps) || isdigit((int)*ps) || *ps == '_'; ps++) + ; + ss[0] = *ps; + if (rv == ps) { + rv = ss, ps++; + } else { + *ps = 0; + rv = tmpstrdup(rv); + *ps = ss[0]; + } + return rv; +} + +/* return 1 on error */ +int +eat(int ch) +{ + char *s = pragtok(0); + return (s == 0 || *s != ch); +} + +static int +pragmas_alpack(char *t) +{ + char *s; + int ap; + + ap = (s = pragtok(0)) ? atoi(s) : 1; + if (strcmp(t, "packed") == 0) + pragma_packed = ap; + else + pragma_aligned = ap; + return 0; +} + + +/* + * Packing control. + */ +static int +pragmas_pack(char *t) +{ +#define PACKSTKSZ 10 + static int packstk[PACKSTKSZ], packptr; + char *s; + + if (eat('(')) + return 1; + s = pragtok(0); + if (*s == ')') + return pragma_allpacked = 0; + if (strcmp(s, "push") == 0) { + if (packptr == PACKSTKSZ) + uerror("too many push"); + packstk[packptr++] = pragma_allpacked; + s = pragtok(0); + if (*s == ')') + return 0; + if (*s != ',') + return 1; + s = pragtok(0); + } else if (strcmp(s, "pop") == 0) { + if (packptr == 0) + uerror("stack empty"); + pragma_allpacked = packstk[--packptr]; + return eat(')'); + } + + if (*s < '0' || *s > '9') /* no number */ + return 1; + pragma_allpacked = atoi(s); + return eat(')'); +} + +static int +pragmas_unsupp(char *t) +{ + werror("#pragma %s unsupported", t); + return 0; /* Just ignore */ +} + +static int +pragmas_stdc(char *t) +{ + return 0; /* Just ignore */ +} + +struct pragmas { + char *name; + int (*fun)(char *); +} pragmas[] = { + { "pack", pragmas_pack }, + { "packed", pragmas_alpack }, + { "aligned", pragmas_alpack }, + { "rename", pragmas_unsupp }, +#ifdef GCC_COMPAT + { "GCC", pragmas_gcc }, +#endif + { "STDC", pragmas_stdc }, + { "weak", pragmas_weak }, + { "ident", NULL }, + { 0 }, +}; + +/* + * got a full pragma line. Split it up here. + */ +static void +pragma(void) +{ + struct pragmas *p; + char *t, *pt; + + if ((t = pragtok(&yytext[7])) != NULL) { + pt = ps; + for (p = pragmas; p->name; p++) { + if (strcmp(t, p->name) == 0) { + if (p->fun && (*p->fun)(t)) + uerror("bad argument to #pragma"); + return; + } + } + ps = pt; + if (mypragma(t)) + return; + } + warner(Wunknown_pragmas, t, ps); +} + +void +cunput(char c) +{ + unput(c); +} diff --git a/lang/pcc/pcc/cc/ccom/softfloat.c b/lang/pcc/pcc/cc/ccom/softfloat.c new file mode 100644 index 000000000..12f175858 --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/softfloat.c @@ -0,0 +1,359 @@ +/* $Id: softfloat.c,v 1.4 2009/07/29 12:32:34 ragge Exp $ */ + +/* + * Copyright (c) 2008 Anders Magnusson. All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +#ifdef SOFTFLOAT + +#include "pass1.h" + + +/* + * Floating point emulation to be used when cross-compiling. + * Currently only supports F- and D-float, used in DEC machines. + * Should be trivial to add other emulations. + * + * XXX - assumes that: + * - long long is (at least) 64 bits + * - int is at least 32 bits. + * - short is 16 bits. + */ + +#ifdef FDFLOAT + +/* + * Useful macros to manipulate the float. + */ +#define DSIGN(w) (((w).fd1 >> 15) & 1) +#define DSIGNSET(w,s) ((w).fd1 = (s << 15) | ((w).fd1 & 077777)) +#define DEXP(w) (((w).fd1 >> 7) & 0377) +#define DEXPSET(w,e) ((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177)) +#define DMANTH(w) ((w).fd1 & 0177) +#define DMANTHSET(w,m) ((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600)) + +typedef unsigned int lword; +typedef unsigned long long dword; + +#define MAXMANT 0x100000000000000LL + +/* + * Returns a zero dfloat. + */ +static SF +nulldf(void) +{ + SF rv; + + rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0; + return rv; +} + +/* + * Convert a (u)longlong to dfloat. + * XXX - fails on too large (> 55 bits) numbers. + */ +SF +soft_cast(CONSZ ll, TWORD t) +{ + int i; + SF rv; + + rv = nulldf(); + if (ll == 0) + return rv; /* fp is zero */ + if (ll < 0) + DSIGNSET(rv,1), ll = -ll; + for (i = 0; ll > 0; i++, ll <<= 1) + ; + DEXPSET(rv, 192-i); + DMANTHSET(rv, ll >> 56); + rv.fd2 = ll >> 40; + rv.fd3 = ll >> 24; + rv.fd4 = ll >> 8; + return rv; +} + +/* + * multiply two dfloat. Use chop, not round. + */ +SF +soft_mul(SF p1, SF p2) +{ + SF rv; + lword a1[2], a2[2], res[4]; + dword sum; + + res[0] = res[1] = res[2] = res[3] = 0; + + /* move mantissa into lwords */ + a1[0] = p1.fd4 | (p1.fd3 << 16); + a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000; + + a2[0] = p2.fd4 | (p2.fd3 << 16); + a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000; + +#define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \ + res[r] = sum; sum >>= 32; + + sum = 0; + MULONE(0, 0, 0); + MULONE(1, 0, 1); + res[2] = sum; + sum = 0; + MULONE(0, 1, 1); + MULONE(1, 1, 2); + res[3] = sum; + + rv.fd1 = 0; + DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2)); + DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128); + if (res[3] & 0x8000) { + res[3] = (res[3] << 8) | (res[2] >> 24); + res[2] = (res[2] << 8) | (res[1] >> 24); + } else { + DEXPSET(rv, DEXP(rv) - 1); + res[3] = (res[3] << 9) | (res[2] >> 23); + res[2] = (res[2] << 9) | (res[1] >> 23); + } + DMANTHSET(rv, res[3] >> 16); + rv.fd2 = res[3]; + rv.fd3 = res[2] >> 16; + rv.fd4 = res[2]; + return rv; +} + +SF +soft_div(SF t, SF n) +{ + SF rv; + dword T, N, K; + int c; + +#define SHL(x,b) ((dword)(x) << b) + T = SHL(1,55) | SHL(DMANTH(t), 48) | + SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4; + N = SHL(1,55) | SHL(DMANTH(n), 48) | + SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4; + + c = T > N; + for (K = 0; (K & 0x80000000000000ULL) == 0; ) { + if (T >= N) { + T -= N; + K |= 1; + } + T <<= 1; + K <<= 1; + } + rv.fd1 = 0; + DSIGNSET(rv, DSIGN(t) ^ DSIGN(n)); + DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c); + DMANTHSET(rv, K >> 48); + rv.fd2 = K >> 32; + rv.fd3 = K >> 16; + rv.fd4 = K; + return rv; +} + +/* + * Negate a float number. Easy. + */ +SF +soft_neg(SF sf) +{ + int sign = DSIGN(sf) == 0; + DSIGNSET(sf, sign); + return sf; +} + +/* + * Return true if fp number is zero. + */ +int +soft_isz(SF sf) +{ + return (DEXP(sf) == 0); +} + +int +soft_cmp_eq(SF x1, SF x2) +{ + cerror("soft_cmp_eq"); + return 0; +} + +int +soft_cmp_ne(SF x1, SF x2) +{ + cerror("soft_cmp_ne"); + return 0; +} + +int +soft_cmp_le(SF x1, SF x2) +{ + cerror("soft_cmp_le"); + return 0; +} + +int +soft_cmp_lt(SF x1, SF x2) +{ + cerror("soft_cmp_lt"); + return 0; +} + +int +soft_cmp_ge(SF x1, SF x2) +{ + cerror("soft_cmp_ge"); + return 0; +} + +int +soft_cmp_gt(SF x1, SF x2) +{ + cerror("soft_cmp_gt"); + return 0; +} + +/* + * Convert a fp number to a CONSZ. + */ +CONSZ +soft_val(SF sf) +{ + CONSZ mant; + int exp = DEXP(sf) - 128; + + mant = SHL(1,55) | SHL(DMANTH(sf), 48) | + SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4; + + while (exp < 0) + mant >>= 1, exp++; + while (exp > 0) + mant <<= 1, exp--; + return mant; +} + +SF +soft_plus(SF x1, SF x2) +{ + cerror("soft_plus"); + return x1; +} + +SF +soft_minus(SF x1, SF x2) +{ + cerror("soft_minus"); + return x1; +} + +/* + * Convert a hex constant to floating point number. + */ +NODE * +fhexcon(char *s) +{ + cerror("fhexcon"); + return NULL; +} + +/* + * Convert a floating-point constant to D-float and store it in a NODE. + */ +NODE * +floatcon(char *s) +{ + NODE *p; + dword mant; + SF fl, flexp, exp5; + int exp, negexp, bexp; + + exp = 0; + mant = 0; +#define ADDTO(sum, val) sum = sum * 10 + val - '0' + for (; *s >= '0' && *s <= '9'; s++) { + if (mant= '0' && *s <= '9'; s++) { + if (mant= '0' && *s <= '9'; s++) + ADDTO(eexp, *s); + if (sign) + eexp = -eexp; + exp = exp + eexp; + } + + negexp = 1; + if (exp<0) { + negexp = -1; + exp = -exp; + } + + + flexp = soft_cast(1, INT); + exp5 = soft_cast(5, INT); + bexp = exp; + fl = soft_cast(mant, INT); + + for (; exp; exp >>= 1) { + if (exp&01) + flexp = soft_mul(flexp, exp5); + exp5 = soft_mul(exp5, exp5); + } + if (negexp<0) + fl = soft_div(fl, flexp); + else + fl = soft_mul(fl, flexp); + + DEXPSET(fl, DEXP(fl) + negexp*bexp); + p = block(FCON, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); /* XXX type */ + p->n_dcon = fl; + return p; +} +#else +#error missing softfloat definition +#endif +#endif diff --git a/lang/pcc/pcc/cc/ccom/stabs.c b/lang/pcc/pcc/cc/ccom/stabs.c new file mode 100644 index 000000000..51c745c1b --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/stabs.c @@ -0,0 +1,458 @@ +/* $Id: stabs.c,v 1.35 2015/09/15 20:01:10 ragge Exp $ */ + +/* + * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Simple implementation of the "stabs" debugging format. + * Not complete but at least makes it possible to set breakpoints, + * examine simple variables and do stack traces. + * Based on the stabs documentation that follows gdb. + */ + +#include "pass1.h" + +#ifdef STABS + +#include +#include +#include + +#define STABHASH 256 +#define INTNUM 1 /* internal number of type "int" */ +#undef BIT2BYTE /* from external.h */ +#define BIT2BYTE(x) ((x)/SZCHAR) + +#ifndef STABLBL +#error macdefs.h must define STABLBL +#endif + +/* defines taken from BSD */ +#define N_GSYM 0x20 /* global symbol */ +#define N_FUN 0x24 /* procedure name */ +#define N_LCSYM 0x28 /* bss segment variable */ +#define N_RSYM 0x40 /* register variable */ +#define N_SLINE 0x44 /* text segment line number */ +#define N_SO 0x64 /* main source file name */ +#define N_LSYM 0x80 /* stack variable */ +#define N_SOL 0x84 /* included source file name */ +#define N_PSYM 0xa0 /* parameter variable */ +#define N_LBRAC 0xc0 /* left bracket */ +#define N_RBRAC 0xe0 /* right bracket */ + +/* + * Local type mapping + * Types are defined as a typeword, a dimension pointer (in the case + * of arrays) and struct/union/enum declarations. + * Function prototypes are ignored. + */ +static struct stabtype { + struct stabtype *next; /* linked list */ + TWORD type; /* pcc type number */ + union dimfun *df; /* dimension of arrays */ + struct attr *ap; /* struct/union/enum declarations */ + int num; /* local type number */ +} *stabhash[STABHASH]; +static int ntypes; +static char *curfun; +static int stablbl = 10; +extern int inftn; + +void ptype(char *name, int num, int inhnum, long long min, long long max); +struct stabtype *addtype(TWORD, union dimfun *, struct attr *); +struct stabtype *findtype(TWORD t, union dimfun *df, struct attr *sue); +void printtype(struct symtab *s, char *str, int len); +void cprint(int p2, char *fmt, ...); + +#define MAXPSTR 100 + +extern int isinlining; + +/* + * Output type definitions for the stab debugging format. + * Note that "int" is always internal number 1. + */ +void +stabs_init(void) +{ + struct stabtype *st; + +#define ADDTYPE(y) addtype(y, NULL, 0) + + ptype("int", ADDTYPE(INT)->num, INTNUM, MIN_INT, MAX_INT); + + st = ADDTYPE(CHAR); + ptype("char", st->num, st->num, 0, MAX_CHAR); + ptype("short", ADDTYPE(SHORT)->num, INTNUM, MIN_SHORT, MAX_SHORT); + ptype("long", ADDTYPE(LONG)->num, INTNUM, MIN_LONG, MAX_LONG); + ptype("long long", ADDTYPE(LONGLONG)->num, INTNUM, + MIN_LONGLONG, MAX_LONGLONG); + ptype("unsigned char", ADDTYPE(UCHAR)->num, INTNUM, 0, MAX_UCHAR); + ptype("unsigned short", ADDTYPE(USHORT)->num, INTNUM, 0, MAX_USHORT); + ptype("unsigned int", ADDTYPE(UNSIGNED)->num, INTNUM, 0, MAX_UNSIGNED); + ptype("unsigned long", ADDTYPE(ULONG)->num, INTNUM, 0, MAX_ULONG); + ptype("unsigned long long", ADDTYPE(ULONGLONG)->num, INTNUM, + 0, MAX_ULONGLONG); + + ptype("float", ADDTYPE(FLOAT)->num, INTNUM, 4, 0); + ptype("double", ADDTYPE(DOUBLE)->num, INTNUM, 8, 0); + ptype("long double", ADDTYPE(LDOUBLE)->num, INTNUM, 12, 0); + st = ADDTYPE(VOID); + cprint(0, "\t.stabs \"void:t%d=r%d\",%d,0,0,0\n", + st->num, st->num, N_LSYM); + +} + +/* + * Print a type in stabs format + */ +void +ptype(char *name, int num, int inhnum, long long min, long long max) +{ + cprint(0, "\t.stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0\n", + name, num, inhnum, min, max, N_LSYM); +} + +/* + * Add a new local type to the hash table. + * The search key is the (type, df, sue) triple. + */ +struct stabtype * +addtype(TWORD t, union dimfun *df, struct attr *ap) +{ + struct stabtype *st; + + st = permalloc(sizeof(struct stabtype)); + st->type = t; + st->df = df; + st->ap = ap; + st->num = ++ntypes; + st->next = stabhash[t & (STABHASH-1)]; + stabhash[t & (STABHASH-1)] = st; + return st; +} + +/* + * Search for a given type and return a type pointer (or NULL). + */ +struct stabtype * +findtype(TWORD t, union dimfun *df, struct attr *ap) +{ + struct stabtype *st; + union dimfun *dw, *dx; + TWORD tw; + + st = stabhash[t & (STABHASH-1)]; + for (; st; st = st->next) { + if (t != st->type || ap != st->ap) + continue; + /* Ok, type and sue matches, check dimensions */ + if (st->df == NULL) + return st; /* no arrays, got match */ + dw = st->df; + dx = df; + tw = t; + for (; tw > BTMASK; tw = DECREF(tw)) { + if (ISARY(tw)) { + if (dw->ddim == dx->ddim) + dw++, dx++; + else + break; + } + } + if (tw <= BTMASK) + return st; + } + return NULL; +} + +/* + * Print current line number. + */ +void +stabs_line(int line) +{ + if (inftn == 0) + return; /* ignore */ +#ifdef STAB_LINE_ABSOLUTE + cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", + N_SLINE, line, stablbl, stablbl); +#else + cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", + N_SLINE, line, stablbl, curfun, stablbl); +#endif + stablbl++; +} + +/* + * Start of block. + */ +void +stabs_lbrac(int blklvl) +{ +#ifdef STAB_LINE_ABSOLUTE + cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", + N_LBRAC, blklvl, stablbl, stablbl); +#else + cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", + N_LBRAC, blklvl, stablbl, curfun, stablbl); +#endif + stablbl++; +} + +/* + * End of block. + */ +void +stabs_rbrac(int blklvl) +{ +#ifdef STAB_LINE_ABSOLUTE + cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", + N_RBRAC, blklvl, stablbl, stablbl); +#else + cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", + N_RBRAC, blklvl, stablbl, curfun, stablbl); +#endif + stablbl++; +} + +static char *mainfile; + +/* + * Print current file and set mark. + */ +void +stabs_file(char *fname) +{ + if (mainfile == NULL) + mainfile = fname; /* first call */ + cprint(inftn, "\t.stabs \"%s\",%d,0,0," STABLBL "\n" STABLBL ":\n", + fname, fname == mainfile ? N_SO : N_SOL, stablbl, stablbl); + stablbl++; +} + +/* + * Print end mark + */ +void +stabs_efile(char *fname) +{ + cprint(inftn, "\t.stabs \"\",%d,0,0," STABLBL "\n" STABLBL ":\n", + fname == mainfile ? N_SO : N_SOL, stablbl, stablbl); + stablbl++; +} + +/* + * Print beginning of function. + */ +void +stabs_func(struct symtab *s) +{ + char str[MAXPSTR]; + + curfun = getexname(s); + printtype(s, str, sizeof(str)); + cprint(1, "\t.stabs \"%s:%c%s\",%d,0,%d,%s\n", + curfun, s->sclass == STATIC ? 'f' : 'F', str, + N_FUN, 0, curfun); +} + +/* + * Print a (complex) type. + * Will also create subtypes. + * Printed string is like "20=*21=*1". + */ +void +printtype(struct symtab *s, char *ostr, int len) +{ + struct stabtype *st; + union dimfun *df = s->sdf; + struct attr *ap = s->sap; + TWORD t = s->stype; + int op = 0; + + /* Print out not-yet-found types */ + if (ISFTN(t)) + t = DECREF(t); + st = findtype(t, df, ap); + while (st == NULL && t > BTMASK) { + st = addtype(t, df, ap); + op+=snprintf(ostr+op, len - op, "%d=", st->num); + if (ISFTN(t)) + ostr[op++] = 'f'; + else if (ISPTR(t)) + ostr[op++] = '*'; + else if (ISARY(t)) { + op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1); + } else + cerror("printtype: notype"); + if (ISARY(t)) + df++; + t = DECREF(t); + st = findtype(t, df, ap); + if (op > MAXPSTR-10) + cerror("printtype: too difficult expression"); + } + /* print out basic type. may have to be entered in case of sue */ + snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num); + /* snprintf here null-terminated the string */ +} + +void +stabs_newsym(struct symtab *s) +{ + extern int fun_inline; + char *sname; + char ostr[MAXPSTR]; + OFFSZ suesize, sz; + + if (ISFTN(s->stype)) + return; /* functions are handled separate */ + + if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS || + s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE || + s->sclass == TYPEDEF || (s->sclass & FIELD) || ISSOU(s->stype)) + return; /* XXX - fix structs */ + + sname = getexname(s); + sz = tsize(s->stype, s->sdf, s->sap); + suesize = BIT2BYTE(sz); + if (suesize > 32767) + suesize = 32767; + else if (suesize < -32768) + suesize = -32768; + + printtype(s, ostr, sizeof(ostr)); + switch (s->sclass) { + case PARAM: + cprint(0, "\t.stabs \"%s:p%s\",%d,0," CONFMT ",%d\n", + sname, ostr, N_PSYM, (CONSZ)suesize, BIT2BYTE(s->soffset)); + break; + + case AUTO: + cprint(0, "\t.stabs \"%s:%s\",%d,0," CONFMT ",%d\n", + sname, ostr, N_LSYM, (CONSZ)suesize, BIT2BYTE(s->soffset)); + break; + + case STATIC: + if (blevel) + cprint(0, "\t.stabs \"%s:V%s\",%d,0," CONFMT "," LABFMT "\n", + sname, ostr, N_LCSYM, (CONSZ)suesize, s->soffset); + else + cprint(0, "\t.stabs \"%s:S%s\",%d,0," CONFMT ",%s\n", + sname, ostr, N_LCSYM, (CONSZ)suesize, sname); + break; + + case EXTERN: + case EXTDEF: + cprint(0, "\t.stabs \"%s:G%s\",%d,0," CONFMT ",0\n", + sname, ostr, N_GSYM, (CONSZ)suesize); + break; + + case REGISTER: + cprint(0, "\t.stabs \"%s:r%s\",%d,0,%d,%d\n", + sname, ostr, N_RSYM, 1, s->soffset); + break; + + case SNULL: + if (fun_inline) + break; + /* FALLTHROUGH */ + default: + cerror("fix stab_newsym; class %d", s->sclass); + } +} + +void +stabs_chgsym(struct symtab *s) +{ +} + +/* + * define a struct. + */ +void +stabs_struct(struct symtab *p, struct attr *ap) +{ +} + +struct stabsv { + SLIST_ENTRY(stabsv) next; + char *str; +} ; +static SLIST_HEAD(, stabsv) stpole = { NULL, &stpole.q_forw }; + +/* + * Global variable debug info is printed out directly. + * For functions and their declarations, both the labels and + * the debug info is put into ASM nodes and follows their statements + * into pass2. + * Due to the possible unsync between pass1 and 2 and where the + * stabs info for text is sent over the following syncing is used: + * curfun == 0 + * print out everything; only data will be. + * curfun != 0 && inftn == 0 + * save in linked list + * curfun != 0 && inftn != 0 + * print linked list first, empty it, then arg. + */ +void +cprint(int p2, char *fmt, ...) +{ +#define CPBSZ 200 + char buf[CPBSZ]; + struct stabsv *w; + va_list ap; + char *str; + + if (isinlining) + return; /* XXX do not save any inline functions currently */ + + va_start(ap, fmt); + if (p2) { + if (vsnprintf(buf, CPBSZ, fmt, ap) >= CPBSZ) + werror("stab symbol line too long, truncating"); + str = tmpstrdup(buf); + if (inftn == 0) { + w = tmpalloc(sizeof(struct stabsv)); + w->str = str; + SLIST_INSERT_LAST(&stpole, w, next); + } else { + if (stpole.q_last != &stpole.q_forw) { + SLIST_FOREACH(w, &stpole, next) { + send_passt(IP_ASM, w->str); + } + SLIST_INIT(&stpole); + } + send_passt(IP_ASM, str); + } + } else + vprintf(fmt, ap); + va_end(ap); +} + +#endif diff --git a/lang/pcc/pcc/cc/ccom/symtabs.c b/lang/pcc/pcc/cc/ccom/symtabs.c new file mode 100644 index 000000000..d3a5e9154 --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/symtabs.c @@ -0,0 +1,660 @@ +/* $Id: symtabs.c,v 1.38 2015/09/15 20:01:10 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" +#include "unicode.h" +#include + +#define NODE P1ND +#define fwalk p1fwalk + +/* + * These definitions are used in the patricia tree that stores + * the strings. + */ +#define LEFT_IS_LEAF 0x80000000 +#define RIGHT_IS_LEAF 0x40000000 +#define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0) +#define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0) +#define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF)) +#define CHECKBITS 8 + +struct tree { + int bitno; + struct tree *lr[2]; +}; + +extern int dimfuncnt; +static struct tree *firstname; +int nametabs, namestrlen; +static struct tree *firststr; +int strtabs, strstrlen, symtreecnt; +static char *symtab_add(char *key, struct tree **, int *, int *); +int lastloc = NOSEG; +int treestrsz = sizeof(struct tree); + +#define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1 +#define getree() permalloc(sizeof(struct tree)) + +char * +addname(char *key) +{ + return symtab_add(key, &firstname, &nametabs, &namestrlen); +} + +char * +addstring(char *key) +{ + return symtab_add(key, &firststr, &strtabs, &strstrlen); +} + +/* + * Add a name to the name stack (if its non-existing), + * return its address. + * This is a simple patricia implementation. + */ +static char * +symtab_add(char *key, struct tree **first, int *tabs, int *stlen) +{ + struct tree *w, *new, *last; + int cix, bit, fbit, svbit, ix, bitno, len; + char *m, *k, *sm; + + /* Count full string length */ + for (k = key, len = 0; *k; k++, len++) + ; + + switch (*tabs) { + case 0: + *first = (struct tree *)newstring(key, len); + *stlen += (len + 1); + (*tabs)++; + return (char *)*first; + + case 1: + m = (char *)*first; + svbit = 0; /* XXX why? */ + break; + + default: + w = *first; + bitno = len * CHECKBITS; + for (;;) { + bit = BITNO(w->bitno); + fbit = bit > bitno ? 0 : P_BIT(key, bit); + svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : + IS_LEFT_LEAF(w->bitno); + w = w->lr[fbit]; + if (svbit) { + m = (char *)w; + break; + } + } + } + + sm = m; + k = key; + + /* Check for correct string and return */ + for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS) + ; + if (*m == 0 && *k == 0) + return sm; + + ix = *m ^ *k; + while ((ix & 1) == 0) + ix >>= 1, cix++; + + /* Create new node */ + new = getree(); + bit = P_BIT(key, cix); + new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + new->lr[bit] = (struct tree *)newstring(key, len); + *stlen += (len + 1); + + if ((*tabs)++ == 1) { + new->lr[!bit] = *first; + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + *first = new; + return (char *)new->lr[bit]; + } + + + w = *first; + last = NULL; + for (;;) { + fbit = w->bitno; + bitno = BITNO(w->bitno); + if (bitno == cix) + cerror("bitno == cix"); + if (bitno > cix) + break; + svbit = P_BIT(key, bitno); + last = w; + w = w->lr[svbit]; + if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) + break; + } + + new->lr[!bit] = w; + if (last == NULL) { + *first = new; + } else { + last->lr[svbit] = new; + last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + } + if (bitno < cix) + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + return (char *)new->lr[bit]; +} + +static struct tree *sympole[NSTYPES]; +static struct symtab *tmpsyms[NSTYPES]; +int numsyms[NSTYPES]; + +/* + * Inserts a symbol into the symbol tree. + * Returns a struct symtab. + */ +struct symtab * +lookup(char *key, int stype) +{ + struct symtab *sym; + struct tree *w, *new, *last; + int cix, bit, fbit, svbit, bitno; + int type, uselvl; + intptr_t ix, match, code = (intptr_t)key; + + type = stype & SMASK; + uselvl = (blevel > 0 && type != SSTRING); + + /* + * The local symbols are kept in a simple linked list. + * Check this list first. + */ + if (blevel > 0) + for (sym = tmpsyms[type]; sym; sym = sym->snext) + if (sym->sname == key) + return sym; + + switch (numsyms[type]) { + case 0: + if (stype & SNOCREAT) + return NULL; + if (uselvl) { + if (type == SNORMAL) + stype |= SBLK; + sym = getsymtab(key, stype); + sym->snext = tmpsyms[type]; + tmpsyms[type] = sym; + return sym; + } + sympole[type] = (struct tree *)getsymtab(key, stype); + numsyms[type]++; + return (struct symtab *)sympole[type]; + + case 1: + w = (struct tree *)sympole[type]; + svbit = 0; /* XXX why? */ + break; + + default: + w = sympole[type]; + for (;;) { + bit = BITNO(w->bitno); + fbit = (code >> bit) & 1; + svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : + IS_LEFT_LEAF(w->bitno); + w = w->lr[fbit]; + if (svbit) + break; + } + } + + sym = (struct symtab *)w; + match = (intptr_t)sym->sname; + + ix = code ^ match; + if (ix == 0) + return sym; + else if (stype & SNOCREAT) + return NULL; + +#ifdef PCC_DEBUG + if (ddebug) + printf(" adding %s as %s at level %d\n", + key, uselvl ? "temp" : "perm", blevel); +#endif + + /* + * Insert into the linked list, if feasible. + */ + if (uselvl) { + sym = getsymtab(key, stype|STEMP); + sym->snext = tmpsyms[type]; + tmpsyms[type] = sym; + return sym; + } + + /* + * Need a new node. If type is SNORMAL and inside a function + * the node must be allocated as permanent anyway. + * This could be optimized by adding a remove routine, but it + * may be more trouble than it is worth. + */ + if (stype == (STEMP|SNORMAL)) + stype = SNORMAL; + + for (cix = 0; (ix & 1) == 0; ix >>= 1, cix++) + ; + + new = (symtreecnt++, permalloc(sizeof(struct tree))); + bit = (code >> cix) & 1; + new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + new->lr[bit] = (struct tree *)getsymtab(key, stype); + if (numsyms[type]++ == 1) { + new->lr[!bit] = sympole[type]; + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + sympole[type] = new; + return (struct symtab *)new->lr[bit]; + } + + + w = sympole[type]; + last = NULL; + for (;;) { + fbit = w->bitno; + bitno = BITNO(w->bitno); + if (bitno == cix) + cerror("bitno == cix"); + if (bitno > cix) + break; + svbit = (code >> bitno) & 1; + last = w; + w = w->lr[svbit]; + if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) + break; + } + + new->lr[!bit] = w; + if (last == NULL) { + sympole[type] = new; + } else { + last->lr[svbit] = new; + last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + } + if (bitno < cix) + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + return (struct symtab *)new->lr[bit]; +} + +void +symclear(int level) +{ + struct symtab *s; + int i; + +#ifdef PCC_DEBUG + if (ddebug) + printf("symclear(%d)\n", level); +#endif + if (level < 1) { + for (i = 0; i < NSTYPES; i++) { + s = tmpsyms[i]; + tmpsyms[i] = 0; + if (i != SLBLNAME) + continue; + while (s != NULL) { + if (s->soffset < 0) + uerror("label '%s' undefined",s->sname); + s = s->snext; + } + } + } else { + for (i = 0; i < NSTYPES; i++) { + if (i == SLBLNAME) + continue; /* function scope */ + while (tmpsyms[i] != NULL && + tmpsyms[i]->slevel > level) { + tmpsyms[i] = tmpsyms[i]->snext; + } + } + } +} + +struct symtab * +hide(struct symtab *sym) +{ + struct symtab *new; + int typ = sym->sflags & SMASK; + + new = getsymtab(sym->sname, typ|STEMP); + new->snext = tmpsyms[typ]; + tmpsyms[typ] = new; + +#ifdef PCC_DEBUG + if (ddebug) + printf("\t%s hidden at level %d (%p -> %p)\n", + sym->sname, blevel, sym, new); +#endif + return new; +} + +/* + * Extract correct segment for the specified symbol and call + * target routines to print it out. + * If symtab entry is specified, output alignment as well. + */ +void +locctr(int seg, struct symtab *sp) +{ +#ifdef GCC_COMPAT + struct attr *ga; +#endif + + if (seg == NOSEG) { + ; + } else if (sp == NULL) { + if (lastloc != seg) + setseg(seg, NULL); +#ifdef GCC_COMPAT + } else if ((ga = attr_find(sp->sap, GCC_ATYP_SECTION)) != NULL) { + setseg(NMSEG, ga->sarg(0)); + seg = NOSEG; +#endif + } else { + if (seg == DATA) { + if (ISCON(cqual(sp->stype, sp->squal))) + seg = RDATA; + else if (sp->sclass == STATIC) + seg = LDATA; + } + if (sp->sflags & STLS) { + if (seg == DATA || seg == LDATA) + seg = TLSDATA; + if (seg == UDATA) seg = TLSUDATA; + } else if (kflag) { + if (seg == DATA) seg = PICDATA; + if (seg == RDATA) seg = PICRDATA; + if (seg == LDATA) seg = PICLDATA; + } + if (lastloc != seg) + setseg(seg, NULL); + } + lastloc = seg; + + /* setup alignment */ +#ifndef ALFTN +#define ALFTN ALINT +#endif + if (sp) { + int al; + + if (ISFTN(sp->stype)) { + al = ALFTN; + } else + al = talign(sp->stype, sp->sap); + defalign(al); + symdirec(sp); + } +} + +#ifndef MYALIGN +void +defalign(int al) +{ +#ifdef HASP2ALIGN +#define P2ALIGN(x) ispow2(x) +#else +#define P2ALIGN(x) (x) +#endif + if (al != ALCHAR) + printf(PRTPREF "\t.align %d\n", P2ALIGN(al/ALCHAR)); +} +#endif + +#ifndef MYDIREC +/* + * Directives given as attributes to symbols. + */ +void +symdirec(struct symtab *sp) +{ +#ifdef GCC_COMPAT + struct attr *ga; + char *name; + + name = getexname(sp); + if ((ga = attr_find(sp->sap, GCC_ATYP_WEAK)) != NULL) + printf(PRTPREF "\t.weak %s\n", name); + if ((ga = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) && + strcmp(ga->sarg(0), "default")) + printf(PRTPREF "\t.%s %s\n", ga->sarg(0), name); + if ((ga = attr_find(sp->sap, GCC_ATYP_ALIASWEAK))) { + printf(PRTPREF "\t.weak %s\n", ga->sarg(0)); + printf(PRTPREF "\t.set %s,%s\n", ga->sarg(0), name); + } +#endif +} +#endif + +char * +getexname(struct symtab *sp) +{ + struct attr *ap = attr_find(sp->sap, ATTR_SONAME); + + return (ap ? ap->sarg(0) : addname(exname(sp->sname))); +} + +static char *csbuf; +static int csbufp, cssz, strtype; +#ifndef NO_STRING_SAVE +static struct symtab *strpole; +#endif +#define STCHNK 128 + +static void +savch(int ch) +{ + if (csbufp == cssz) { + cssz += STCHNK; + csbuf = realloc(csbuf, cssz); + } + csbuf[csbufp++] = ch; +} + +/* + * save value as 3-digit octal escape sequence + */ +static void +voct(unsigned int v) +{ + savch('\\'); + savch(((v & 0700) >> 6) + '0'); + savch(((v & 0070) >> 3) + '0'); + savch((v & 0007) + '0'); +} + + +/* + * Add string new to string old. + * String new must come directly after old. + * new is expected to be utf-8. Will be cleaned slightly here. + */ +char * +stradd(char *old, char *new) +{ + if (old == NULL) { + strtype = 0; + csbufp = 0; + } else if (old != csbuf) + cerror("string synk error"); + + /* special hack for function names */ + for (old = new; *old; old++) + ; + if (old[-1] != '\"') { + do { + savch(*new); + } while (*new++); + return csbuf; + } + + if (*new != '\"') { + int ny = *new++; + if (ny == 'u' && *new == '8') + ny = '8', new++; + if (strtype && ny != strtype) + uerror("clash in string types"); + strtype = ny; + } + if (*new++ != '\"') + cerror("snuff synk error"); + + while (*new != '\"') { + if (*new == '\\') { + voct(esccon(&new)); + } else if (*new < ' ' || *new > '~') { + voct(*(unsigned char *)new++); + } else { + savch(*new++); + } + } + savch(0); + csbufp--; + return csbuf; +} + +TWORD +styp(void) +{ + TWORD t; + + if (strtype == 0 || strtype == '8') + t = xuchar ? UCHAR+ARY : CHAR+ARY; + else if (strtype == 'u') + t = ctype(USHORT)+ARY; + else if (strtype == 'L') + t = WCHAR_TYPE+ARY; + else + t = ctype(SZINT < 32 ? ULONG : UNSIGNED)+ARY; + return t; +} + +/* + * Create a string struct. + */ +static void +strst(struct symtab *sp, TWORD t) +{ + char *wr; + int i; + + sp->sclass = STATIC; + sp->slevel = 1; + sp->soffset = getlab(); + sp->squal = (CON >> TSHIFT); +#ifndef NO_STRING_SAVE + sp->sdf = permalloc(sizeof(union dimfun)); +#else + sp->sdf = stmtalloc(sizeof(union dimfun)); +#endif + dimfuncnt++; + sp->stype = t; + + for (wr = sp->sname, i = 1; *wr; i++) { + if (strtype == 'L' || strtype == 'U' || strtype == 'u') + (void)u82cp(&wr); + else if (*wr == '\\') + (void)esccon(&wr); + else + wr++; + } + sp->sdf->ddim = i; +#ifndef NO_STRING_SAVE + sp->snext = strpole; + strpole = sp; +#endif +} + +/* + * Save string (if needed) and return NODE for it. + * String is already in utf-8 format. + */ +NODE * +strend(char *s, TWORD t) +{ + struct symtab *sp, *sp2; + NODE *p; + +#ifdef NO_STRING_SAVE + sp = getsymtab(s, SSTRING|SSTMT); +#else + s = addstring(s); + sp = lookup(s, SSTRING); +#endif + + if (sp->soffset && sp->stype != t) { + /* same string stored but different type */ + /* This is uncommon, create a new symtab struct for it */ + sp2 = permalloc(sizeof(*sp)); + *sp2 = *sp; + strst(sp2, t); + sp = sp2; + } else if (sp->soffset == 0) { /* No string */ + strst(sp, t); + } + if (cssz > STCHNK) { + cssz = STCHNK; + csbuf = realloc(csbuf, cssz); + } +#ifdef NO_STRING_SAVE + instring(sp); +#endif + p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap); + p->n_sp = sp; + return(clocal(p)); +} + +#ifndef NO_STRING_SAVE +/* + * Print out strings that have been referenced. + */ +void +strprint(void) +{ + struct symtab *sp; + + for (sp = strpole; sp; sp = sp->snext) { + if ((sp->sflags & SASG) == 0) + continue; /* not referenced */ + instring(sp); + } +} +#endif diff --git a/lang/pcc/pcc/cc/ccom/trees.c b/lang/pcc/pcc/cc/ccom/trees.c new file mode 100644 index 000000000..e7edeba3c --- /dev/null +++ b/lang/pcc/pcc/cc/ccom/trees.c @@ -0,0 +1,3568 @@ +/* $Id: trees.c,v 1.373 2016/03/05 15:49:36 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ +/* + * Some of the changes from 32V include: + * - Understand "void" as type. + * - Handle enums as ints everywhere. + * - Convert some C-specific ops into branches. + */ + +# include "pass1.h" +# include "pass2.h" + +# include +# include +# include + +static void chkpun(P1ND *p); +static int opact(P1ND *p); +static int moditype(TWORD); +static P1ND *strargs(P1ND *); +static void rmcops(P1ND *p); +static P1ND *tymatch(P1ND *p); +static P1ND *rewincop(P1ND *p1, P1ND *p2, int op); +static int has_se(P1ND *p); +static struct symtab *findmember(struct symtab *, char *); +int inftn; /* currently between epilog/prolog */ +P1ND *cstknode(TWORD t, union dimfun *df, struct attr *ap); + +static char *tnames[] = { + "undef", + "farg", + "char", + "unsigned char", + "short", + "unsigned short", + "int", + "unsigned int", + "long", + "unsigned long", + "long long", + "unsigned long long", + "float", + "double", + "long double", + "strty", + "unionty", + "enumty", + "moety", + "void", + "signed", /* pass1 */ + "bool", /* pass1 */ + "fimag", /* pass1 */ + "dimag", /* pass1 */ + "limag", /* pass1 */ + "fcomplex", /* pass1 */ + "dcomplex", /* pass1 */ + "lcomplex", /* pass1 */ + "enumty", /* pass1 */ + "?", "?" +}; + +/* some special actions, used in finding the type of nodes */ +# define NCVT 01 +# define PUN 02 +# define TYPL 04 +# define TYPR 010 +# define TYMATCH 040 +# define LVAL 0100 +# define CVTO 0200 +# define CVTL 0400 +# define CVTR 01000 +# define PTMATCH 02000 +# define OTHER 04000 +# define NCVTR 010000 +# define PROML 020000 /* promote left operand */ + +/* node conventions: + + NAME: rval>0 is stab index for external + rval<0 is -inlabel number + lval is offset in bits + ICON: lval has the value + rval has the STAB index, or - label number, + if a name whose address is in the constant + rval = NONAME means no name + REG: rval is reg. identification cookie + + */ + +/* negatives of relationals */ +int p1negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE }; + +/* Have some defaults for most common targets */ +#ifndef WORD_ADDRESSED +#define offcon(o,t,d,ap) xbcon((o/SZCHAR), NULL, INTPTR) +#define VBLOCK(p,b,t,d,a) buildtree(DIV, p, b) +#define MBLOCK(p,b,t,d,a) buildtree(MUL, p, b) +#else +#define VBLOCK(p,b,t,d,a) block(PVCONV, p, b, t, d, a) +#define MBLOCK(p,b,t,d,a) block(PMCONV, p, b, t, d, a) +#endif + +P1ND * +buildtree(int o, P1ND *l, P1ND *r) +{ + P1ND *p, *q; + int actions; + int opty, n; + struct symtab *sp = NULL; /* XXX gcc */ + P1ND *lr, *ll; + +#ifdef PCC_DEBUG + if (bdebug) { + printf("buildtree(%s, %p, %p)\n", copst(o), l, r); + if (l) p1fwalk(l, eprint, 0); + if (r) p1fwalk(r, eprint, 0); + } +#endif + opty = coptype(o); + + /* check for constants */ + + if (o == ANDAND || o == OROR || o == NOT) { + if (l->n_op == FCON) { + p = bcon(!FLOAT_ISZERO(l->n_dcon)); + p1nfree(l); + l = p; + } + if (o != NOT && r->n_op == FCON) { + p = bcon(!FLOAT_ISZERO(r->n_dcon)); + p1nfree(r); + r = p; + } + } + + if( opty == UTYPE && l->n_op == ICON ){ + + switch( o ){ + + case NOT: + case UMINUS: + case COMPL: + if( conval( l, o, l ) ) return(l); + break; + } + } else if (o == NOT && l->n_op == FCON) { + l = clocal(block(SCONV, l, NULL, INT, 0, 0)); + } else if( o == UMINUS && l->n_op == FCON ){ + FLOAT_NEG(l->n_dcon); + return(l); + + } else if( o==QUEST && + (l->n_op==ICON || (l->n_op==NAME && ISARY(l->n_type)))) { + CONSZ c = glval(l); + if (l->n_op==NAME) + c = 1; /* will become constant later */ + p1nfree(l); + if (c) { + p1walkf(r->n_right, putjops, 0); + p1tfree(r->n_right); + l = r->n_left; + } else { + p1walkf(r->n_left, putjops, 0); + p1tfree(r->n_left); + l = r->n_right; + } + p1nfree(r); + return(l); + } else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){ + + switch( o ){ + + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + /* + * Do type propagation for simple types here. + * The constant value is correct anyway. + * Maybe this op shortcut should be removed? + */ + if (l->n_sp == NULL && r->n_sp == NULL && + l->n_type < BTMASK && r->n_type < BTMASK) { + if (l->n_type > r->n_type) + r->n_type = l->n_type; + else + l->n_type = r->n_type; + } + /* FALLTHROUGH */ + case ULT: + case UGT: + case ULE: + case UGE: + case LT: + case GT: + case LE: + case GE: + case EQ: + case NE: + case ANDAND: + case OROR: + case AND: + case OR: + case ER: + case LS: + case RS: + if (!ISPTR(l->n_type) && !ISPTR(r->n_type)) { + if( conval( l, o, r ) ) { + p1nfree(r); + return(l); + } + } + break; + } + } else if (opty == BITYPE && (l->n_op == FCON || l->n_op == ICON) && + (r->n_op == FCON || r->n_op == ICON) && (o == PLUS || o == MINUS || + o == MUL || o == DIV || (o >= EQ && o <= GT) )) { + /* at least one side is FCON */ + +#ifndef CC_DIV_0 + if (o == DIV && + ((r->n_op == ICON && glval(r) == 0) || + (r->n_op == FCON && FLOAT_EQ(r->n_dcon, FLOAT_ZERO)))) + goto runtime; /* HW dependent */ +#endif + if (l->n_op == ICON) { + if (!concast(l, r->n_type)) + cerror("fail cast const"); + } else if (r->n_op == ICON) { + if (!concast(r, l->n_type)) + cerror("fail cast const"); + } + + switch(o){ + case PLUS: + case MINUS: + case MUL: + case DIV: + switch (o) { + case PLUS: + FLOAT_PLUS(l, r); + break; + case MINUS: + FLOAT_MINUS(l, r); + break; + case MUL: + FLOAT_MUL(l, r); + break; + case DIV: + FLOAT_DIV(l, r); + break; + } + p1nfree(r); + return(l); + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: + switch (o) { + case EQ: + n = FLOAT_EQ(l->n_dcon, r->n_dcon); + break; + case NE: + n = FLOAT_NE(l->n_dcon, r->n_dcon); + break; + case LE: + n = FLOAT_LE(l->n_dcon, r->n_dcon); + break; + case LT: + n = FLOAT_LT(l->n_dcon, r->n_dcon); + break; + case GE: + n = FLOAT_GE(l->n_dcon, r->n_dcon); + break; + case GT: + n = FLOAT_GT(l->n_dcon, r->n_dcon); + break; + default: + n = 0; /* XXX flow analysis */ + } + p1nfree(r); + p1nfree(l); + return bcon(n); + } + } else if ((cdope(o)&ASGOPFLG) && o != RETURN && o != CAST) { + if (l->n_op == SCONV && l->n_left->n_op == FLD) + l = p1nfree(l); + /* + * Handle side effects by storing address in temporary q. + * Side effect nodes always have an UMUL. + */ + if (has_se(l)) { + ll = l->n_left; + + q = cstknode(ll->n_type, ll->n_df, ll->n_ap); + l->n_left = p1tcopy(q); + q = buildtree(ASSIGN, q, ll); + } else + q = bcon(0); /* No side effects */ + + /* + * Modify the trees so that the compound op is rewritten. + */ + /* avoid casting of LHS */ + if ((cdope(o) & SIMPFLG) && ISINTEGER(l->n_type) && + l->n_type != BOOL) + r = ccast(r, l->n_type, l->n_qual, l->n_df, l->n_ap); + + r = buildtree(UNASG o, p1tcopy(l), r); + r = buildtree(ASSIGN, l, r); + l = q; + o = COMOP; + } else if (o == INCR || o == DECR) { + if (l->n_op == SCONV && l->n_left->n_op == FLD) + l = p1nfree(l); + /* + * Rewrite to (t=d,d=d+1,t) + */ + if (has_se(l)) { + ll = l->n_left; + + q = cstknode(ll->n_type, ll->n_df, ll->n_ap); + l->n_left = p1tcopy(q); + q = buildtree(ASSIGN, q, ll); + } else + q = bcon(0); /* No side effects */ + + /* Boolean has special syntax. */ + if (l->n_type == BOOL) { + r = rewincop(l, r, o == INCR ? ASSIGN : EREQ); + } else + r = rewincop(l, r, o == INCR ? PLUSEQ : MINUSEQ); + l = q; + o = COMOP; + } else if (o == ASSIGN && l->n_op == SCONV && l->n_left->n_op == FLD) { + l = p1nfree(l); + } + + +#ifndef CC_DIV_0 +runtime: +#endif + /* its real; we must make a new node */ + + p = block(o, l, r, INT, 0, 0); + + actions = opact(p); + + if (actions & PROML) + p->n_left = intprom(p->n_left); + + if (actions & LVAL) { /* check left descendent */ + if (notlval(p->n_left)) { + uerror("lvalue required"); + p1nfree(p); + return l; +#ifdef notyet + } else { + if ((l->n_type > BTMASK && ISCON(l->n_qual)) || + (l->n_type <= BTMASK && ISCON(l->n_qual << TSHIFT))) + if (blevel > 0) + uerror("lvalue is declared const"); +#endif + } + } + + if( actions & NCVTR ){ + p->n_left = pconvert( p->n_left ); + } + else if( !(actions & NCVT ) ){ + switch( opty ){ + + case BITYPE: + p->n_right = pconvert( p->n_right ); + /* FALLTHROUGH */ + case UTYPE: + p->n_left = pconvert( p->n_left ); + + } + } + + if ((actions&PUN) && (o!=CAST)) + chkpun(p); + + if( actions & (TYPL|TYPR) ){ + + q = (actions&TYPL) ? p->n_left : p->n_right; + + p->n_type = q->n_type; + p->n_qual = q->n_qual; + p->n_df = q->n_df; + p->n_ap = q->n_ap; + } + + if( actions & CVTL ) p = convert( p, CVTL ); + if( actions & CVTR ) p = convert( p, CVTR ); + if( actions & TYMATCH ) p = tymatch(p); + if( actions & PTMATCH ) p = ptmatch(p); + + if( actions & OTHER ){ + struct symtab *sp1; + + l = p->n_left; + r = p->n_right; + + switch(o){ + + case NAME: + cerror("buildtree NAME"); + + case STREF: + /* p->x turned into *(p+offset) */ + /* rhs must be a name; check correctness */ + + /* Find member symbol struct */ + if (l->n_type != PTR+STRTY && l->n_type != PTR+UNIONTY){ + uerror("struct or union required"); + break; + } + + if ((sp1 = strmemb(l->n_ap)) == NULL) { + uerror("undefined struct or union"); + break; + } + + if ((sp = findmember(sp1, r->n_name)) == NULL) { + uerror("member '%s' not declared", r->n_name); + break; + } + + r->n_sp = sp; + p = stref(p); + break; + + case UMUL: + if (l->n_op == ADDROF) { + p1nfree(p); + p = p1nfree(l); + } + if( !ISPTR(l->n_type))uerror("illegal indirection"); + p->n_type = DECREF(l->n_type); + p->n_qual = DECREF(l->n_qual); + p->n_df = l->n_df; + p->n_ap = l->n_ap; + break; + + case ADDROF: + switch( l->n_op ){ + + case UMUL: + p1nfree(p); + p = p1nfree(l); + /* FALLTHROUGH */ + case TEMP: + case NAME: + p->n_type = INCREF(l->n_type); + p->n_qual = INCQAL(l->n_qual); + p->n_df = l->n_df; + p->n_ap = l->n_ap; + break; + + case COMOP: + p1nfree(p); + lr = buildtree(ADDROF, l->n_right, NULL); + p = buildtree( COMOP, l->n_left, lr ); + p1nfree(l); + break; + + case QUEST: + lr = buildtree( ADDROF, l->n_right->n_right, NULL ); + ll = buildtree( ADDROF, l->n_right->n_left, NULL ); + p1nfree(p); p1nfree(l->n_right); + p = buildtree( QUEST, l->n_left, buildtree( COLON, ll, lr ) ); + p1nfree(l); + break; + + default: + uerror("unacceptable operand of &: %d", l->n_op ); + break; + } + break; + + case LS: + case RS: /* must make type size at least int... */ + if (p->n_type == CHAR || p->n_type == SHORT) { + p->n_left = makety(l, INT, 0, 0, 0); + } else if (p->n_type == UCHAR || p->n_type == USHORT) { + p->n_left = makety(l, UNSIGNED, 0, 0, 0); + } + l = p->n_left; + p->n_type = l->n_type; + p->n_qual = l->n_qual; + p->n_df = l->n_df; + p->n_ap = l->n_ap; + if(tsize(r->n_type, r->n_df, r->n_ap) > SZINT) + p->n_right = makety(r, INT, 0, 0, 0); + break; + + case RETURN: + case ASSIGN: + case CAST: + /* structure assignment */ + /* take the addresses of the two sides; then make an + * operator using STASG and + * the addresses of left and right */ + + if (strmemb(l->n_ap) != strmemb(r->n_ap)) + uerror("assignment of different structures"); + + r = buildtree(ADDROF, r, NULL); + + l = block(STASG, l, r, r->n_type, r->n_df, r->n_ap); + l = clocal(l); + + if( o == RETURN ){ + p1nfree(p); + p = l; + break; + } + + p->n_op = UMUL; + p->n_left = l; + p->n_right = NULL; + break; + + case QUEST: /* fixup types of : */ + if (r->n_left->n_type != p->n_type) + r->n_left = makety(r->n_left, p->n_type, + p->n_qual, p->n_df, p->n_ap); + if (r->n_right->n_type != p->n_type) + r->n_right = makety(r->n_right, p->n_type, + p->n_qual, p->n_df, p->n_ap); + break; + + case COLON: + /* structure colon */ + + if (strmemb(l->n_ap) != strmemb(r->n_ap)) + uerror( "type clash in conditional" ); + break; + + case CALL: + p->n_right = r = strargs(p->n_right); + p = funcode(p); + /* FALLTHROUGH */ + case UCALL: + if (!ISPTR(l->n_type)) + uerror("illegal function"); + p->n_type = DECREF(l->n_type); + if (!ISFTN(p->n_type)) + uerror("illegal function"); + p->n_type = DECREF(p->n_type); + p->n_df = l->n_df+1; /* add one for prototypes */ + p->n_ap = l->n_ap; + if (p->n_type == STRTY || p->n_type == UNIONTY) { + /* function returning structure */ + /* make function really return ptr to str., with * */ + + p->n_op += STCALL-CALL; + p->n_type = INCREF(p->n_type); + p = clocal(p); /* before recursing */ + p = buildtree(UMUL, p, NULL); + + } + break; + + default: + cerror( "other code %d", o ); + } + } + + /* fixup type in bit-field assignment */ + if (p->n_op == ASSIGN && l->n_op == FLD && UPKFSZ(l->n_rval) < SZINT) + p = makety(p, INT, 0, 0, 0); + + /* + * Allow (void)0 casts. + * XXX - anything on the right side must be possible to cast. + * XXX - remove void types further on. + */ + if (p->n_op == CAST && p->n_type == VOID && + p->n_right->n_op == ICON) + p->n_right->n_type = VOID; + + if (actions & CVTO) + p = oconvert(p); + p = clocal(p); + +#ifdef PCC_DEBUG + if (bdebug) { + printf("End of buildtree:\n"); + p1fwalk(p, eprint, 0); + } +#endif + + return(p); + + } + +/* + * Rewrite ++/-- to (t=p, p++, t) ops on types that do not act act as usual. + */ +static P1ND * +rewincop(P1ND *p1, P1ND *p2, int op) +{ + P1ND *t, *r; + + t = cstknode(p1->n_type, p1->n_df, p1->n_ap); + r = buildtree(ASSIGN, p1tcopy(t), p1tcopy(p1)); + r = buildtree(COMOP, r, buildtree(op, p1, eve(p2))); + return buildtree(COMOP, r, t); +} + + +/* Find a member in a struct or union. May be an unnamed member */ +static struct symtab * +findmember(struct symtab *sp, char *s) +{ + struct symtab *sp2, *sp3; + + for (; sp != NULL; sp = sp->snext) { + if (sp->sname[0] == '*') { + /* unnamed member, recurse down */ + if ((sp2 = findmember(strmemb(sp->sap), s))) { + sp3 = tmpalloc(sizeof (struct symtab)); + *sp3 = *sp2; + sp3->soffset += sp->soffset; + return sp3; + } + } else if (sp->sname == s) + return sp; + } + return NULL; +} + + +/* + * Check if there will be a lost label destination inside of a ?: + * It cannot be reached so just print it out. + */ +void +putjops(P1ND *p, void *arg) +{ + if (p->n_op == COMOP && p->n_left->n_op == GOTO) + plabel((int)glval(p->n_left->n_left)+2); +} + +/* + * Build a name node based on a symtab entry. + * broken out from buildtree(). + */ +P1ND * +nametree(struct symtab *sp) +{ + P1ND *p; + + p = block(NAME, NULL, NULL, sp->stype, sp->sdf, sp->sap); + p->n_qual = sp->squal; + p->n_sp = sp; + +#ifndef NO_C_BUILTINS + if (sp->sname[0] == '_' && strncmp(sp->sname, "__builtin_", 10) == 0) + return p; /* do not touch builtins here */ + +#endif + + if (sp->sflags & STNODE) { + /* Generated for optimizer */ + p->n_op = TEMP; + p->n_rval = sp->soffset; + } + +#ifdef GCC_COMPAT + /* Get a label name */ + if (sp->sflags == SLBLNAME) + sp->stype = p->n_type = VOID; +#endif + if (sp->stype == UNDEF) { + uerror("%s undefined", sp->sname); + /* make p look reasonable */ + p->n_type = INT; + p->n_df = NULL; + defid(p, SNULL); + } + if (sp->sclass == MOE) { + p->n_op = ICON; + slval(p, sp->soffset); + p->n_df = NULL; + p->n_sp = NULL; + } + return clocal(p); +} + +/* + * Cast a node to another type by inserting a cast. + * Just a nicer interface to buildtree. + * Returns the new tree. + */ +P1ND * +cast(P1ND *p, TWORD t, TWORD u) +{ + P1ND *q; + + q = block(NAME, NULL, NULL, t, 0, 0); + q->n_qual = u; + q = buildtree(CAST, q, p); + p = q->n_right; + p1nfree(q->n_left); + p1nfree(q); + return p; +} + +/* + * Cast and complain if necessary by not inserining a cast. + */ +P1ND * +ccast(P1ND *p, TWORD t, TWORD u, union dimfun *df, struct attr *ap) +{ + P1ND *q; + + /* let buildtree do typechecking (and casting) */ + q = block(NAME, NULL, NULL, t, df, ap); + p = buildtree(ASSIGN, q, p); + p1nfree(p->n_left); + q = optim(p->n_right); + p1nfree(p); + return q; +} + +/* + * Do an actual cast of a constant (if possible). + * Routine assumes 2-complement. p is cast to type t. + * Returns 1 if handled, 0 otherwise. + */ +int +concast(P1ND *p, TWORD t) +{ + extern short sztable[]; + CONSZ val; + + if (p->n_op != ICON && p->n_op != FCON) /* only constants */ + return 0; + if (p->n_op == ICON && p->n_sp != NULL) { /* no addresses */ + if (t == BOOL) { + slval(p, 1), p->n_type = BOOL, p->n_sp = NULL; + return 1; + } + return 0; + } + if (((p->n_type & TMASK) && t != BOOL) || (t & TMASK)) /* no pointers */ + return 0; + +//printf("concast till %d\n", t); +//fwalk(p, eprint, 0); + +#define TYPMSK(y) ((((1LL << (y-1))-1) << 1) | 1) + if (p->n_op == ICON) { + val = glval(p); + + if (t == BOOL) { + if (val) + slval(p, 1); + } else if (t <= ULONGLONG) { + slval(p, val & TYPMSK(sztable[t])); + if (!ISUNSIGNED(t)) { + if (val & (1LL << (sztable[t]-1))) + slval(p, glval(p) | ~TYPMSK(sztable[t])); + } + } else if (t <= LDOUBLE) { + p->n_op = FCON; + p->n_dcon = fltallo(); + FLOAT_INT2FP(p->n_dcon, val, p->n_type); + } + } else { /* p->n_op == FCON */ + if (t == BOOL) { + p->n_op = ICON; + slval(p, FLOAT_NE(p->n_dcon, FLOAT_ZERO)); + p->n_sp = NULL; + } else if (t <= ULONGLONG) { + p->n_op = ICON; + FLOAT_FP2INT(glval(p), p->n_dcon, t); + p->n_sp = NULL; + } else { + FLOAT_FP2FP(p->n_dcon, t); + } + } + p->n_type = t; +//fwalk(p, eprint, 0); + return 1; +} + +/* + * Do a conditional branch. + */ +void +cbranch(P1ND *p, P1ND *q) +{ + p = buildtree(CBRANCH, p, q); + if (p->n_left->n_op == ICON) { + if (glval(p->n_left) != 0) { + branch((int)glval(q)); /* branch always */ + reached = 0; + } + p1tfree(p); + return; + } + ecomp(p); +} + +P1ND * +strargs(register P1ND *p) +{ + /* rewrite structure flavored arguments */ + + if( p->n_op == CM ){ + p->n_left = strargs( p->n_left ); + p->n_right = strargs( p->n_right ); + return( p ); + } + + if( p->n_type == STRTY || p->n_type == UNIONTY ){ + p = block(STARG, p, NULL, p->n_type, p->n_df, p->n_ap); + p->n_left = buildtree( ADDROF, p->n_left, NULL ); + p = clocal(p); + } + return( p ); +} + +/* + * apply the op o to the lval part of p; if binary, rhs is val + */ +int +conval(P1ND *p, int o, P1ND *q) +{ + TWORD tl = p->n_type, tr = q->n_type, td; + int i, u; + CONSZ val; + U_CONSZ v1, v2; + + val = glval(q); + + /* make both sides same type */ + if (tl < BTMASK && tr < BTMASK) { + td = tl > tr ? tl : tr; + if (td < INT) + td = INT; + u = ISUNSIGNED(td); + if (tl != td) + p = makety(p, td, 0, 0, 0); + if (tr != td) + q = makety(q, td, 0, 0, 0); + } else + u = ISUNSIGNED(tl) || ISUNSIGNED(tr); + if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE); + + if (p->n_sp != NULL && q->n_sp != NULL) + return(0); + if (q->n_sp != NULL && o != PLUS) + return(0); + if (p->n_sp != NULL && o != PLUS && o != MINUS) + return(0); + + v1 = glval(p); + v2 = glval(q); + if (v2 == 0 && (cdope(o) & DIVFLG)) + return 0; /* leave division by zero to runtime */ + switch( o ){ + + case PLUS: + slval(p, (glval(p) + val)); + if (p->n_sp == NULL) { + p->n_right = q->n_right; + p->n_type = q->n_type; + } + break; + case MINUS: + slval(p, (glval(p) - val)); + break; + case MUL: + slval(p, (glval(p) * val)); + break; + case DIV: + if (u) { + v1 /= v2; + slval(p, v1); + } else + slval(p, (glval(p) / val)); + break; + case MOD: + if (u) { + v1 %= v2; + slval(p, v1); + } else + slval(p, (glval(p) % val)); + break; + case AND: + slval(p, (glval(p) & val)); + break; + case OR: + slval(p, (glval(p) | val)); + break; + case ER: + slval(p, (glval(p) ^ val)); + break; + case LS: + i = (int)val; + slval(p, glval(p) << i); + break; + case RS: + i = (int)val; + if (u) { + v1 = v1 >> i; + slval(p, v1); + } else { + slval(p, glval(p) >> i); + } + break; + + case UMINUS: + slval(p, (-glval(p))); + break; + case COMPL: + slval(p, (~glval(p))); + break; + case NOT: + slval(p, (!glval(p))); + p->n_type = INT; + break; + case LT: + slval(p, (glval(p) < val)); + break; + case LE: + slval(p, (glval(p) <= val)); + break; + case GT: + slval(p, (glval(p) > val)); + break; + case GE: + slval(p, (glval(p) >= val)); + break; + case ULT: + slval(p, (v1 < v2)); + break; + case ULE: + slval(p, (v1 <= v2)); + break; + case UGT: + slval(p, (v1 > v2)); + break; + case UGE: + slval(p, (v1 >= v2)); + break; + case EQ: + slval(p, (glval(p) == val)); + break; + case NE: + slval(p, (glval(p) != val)); + break; + case ANDAND: + slval(p, (glval(p) && val)); + break; + case OROR: + slval(p, (glval(p) || val)); + break; + default: + return(0); + } + /* Do the best in making everything type correct after calc */ + if (clogop(o)) + p->n_type = INT; + if (p->n_sp == NULL && q->n_sp == NULL) { + slval(p, valcast(glval(p), p->n_type)); + } + return(1); + } + +/* + * Ensure that v matches the type t; sign- or zero-extended + * as suitable to CONSZ. + * Only to be used for integer types. + */ +CONSZ +valcast(CONSZ v, TWORD t) +{ + CONSZ r; + int sz; + + if (t < CHAR || t > ULONGLONG) + return v; /* cannot cast */ + + if (t >= LONGLONG) + return v; /* already largest */ + +#define M(x) ((((1ULL << ((x)-1)) - 1) << 1) + 1) +#define NOTM(x) (~M(x)) +#define SBIT(x) (1ULL << ((x)-1)) + + sz = (int)tsize(t, NULL, NULL); + r = v & M(sz); + if (!ISUNSIGNED(t) && (SBIT(sz) & r)) + r = r | NOTM(sz); + return r; +} + +/* + * Checks p for the existence of a pun. This is called when the op of p + * is ASSIGN, RETURN, CAST, COLON, or relational. + * One case is when enumerations are used: this applies only to lint. + * In the other case, one operand is a pointer, the other integer type + * we check that this integer is in fact a constant zero... + * in the case of ASSIGN, any assignment of pointer to integer is illegal + * this falls out, because the LHS is never 0. + * XXX - check for COMOPs in assignment RHS? + */ +void +chkpun(P1ND *p) +{ + union dimfun *d1, *d2; + P1ND *q; + int t1, t2; + + t1 = p->n_left->n_type; + t2 = p->n_right->n_type; + + switch (p->n_op) { + case RETURN: + /* return of void allowed but nothing else */ + if (t1 == VOID && t2 == VOID) + return; + if (t1 == VOID) { + werror("returning value from void function"); + return; + } + if (t2 == VOID) { + uerror("using void value"); + return; + } + break; + case COLON: + if (t1 == VOID && t2 == VOID) + return; + break; + default: + if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) { + uerror("value of void expression used"); + return; + } + break; + } + + /* allow void pointer assignments in any direction */ + if (BTYPE(t1) == VOID && (t2 & TMASK)) + return; + if (BTYPE(t2) == VOID && (t1 & TMASK)) + return; + + /* boolean have special syntax */ + if (t1 == BOOL) { + if (!ISARY(t2)) /* Anything scalar */ + return; + } + + if (ISPTR(t1) || ISARY(t1)) + q = p->n_right; + else + q = p->n_left; + + if (!ISPTR(q->n_type) && !ISARY(q->n_type)) { + if (q->n_op != ICON || glval(q) != 0) + werror("illegal combination of pointer and integer"); + } else { + if (t1 == t2) { + if (ISSOU(BTYPE(t1)) && + !suemeq(p->n_left->n_ap, p->n_right->n_ap)) + werror("illegal structure pointer combination"); + return; + } + d1 = p->n_left->n_df; + d2 = p->n_right->n_df; + for (;;) { + if (ISARY(t1) || ISPTR(t1)) { + if (!ISARY(t2) && !ISPTR(t2)) + break; + if (ISARY(t1) && ISARY(t2) && d1->ddim != d2->ddim) { + werror("illegal array size combination"); + return; + } + if (ISARY(t1)) + ++d1; + if (ISARY(t2)) + ++d2; + } else if (ISFTN(t1)) { + if (chkftn(d1->dfun, d2->dfun)) { + werror("illegal function " + "pointer combination"); + return; + } + ++d1; + ++d2; + } else + break; + t1 = DECREF(t1); + t2 = DECREF(t2); + } + if (DEUNSIGN(t1) != DEUNSIGN(t2)) + werror("illegal pointer combination"); + else if (t1 != t2) + warner(Wpointer_sign); + } +} + +static P1ND * +offplus(P1ND *p, int off, TWORD t, TWORD q, union dimfun *d, struct attr *ap) { + if (off != 0) { + p = block(PLUS, p, offcon(off, t, d, ap), t, d, ap); + p->n_qual = q; + p = optim(p); + } + + return buildtree(UMUL, p, NULL); +} + +P1ND * +stref(P1ND *p) +{ + P1ND *r; + struct attr *ap, *xap, *yap; + union dimfun *d; + TWORD t, q; + int dsc, fsz; + OFFSZ off; + struct symtab *s; + + /* make p->x */ + /* this is also used to reference automatic variables */ + + s = p->n_right->n_sp; + p1nfree(p->n_right); + r = p1nfree(p); +#ifdef GCC_COMPAT + xap = attr_find(r->n_ap, GCC_ATYP_PACKED); +#else + xap = NULL; +#endif + + p = pconvert(r); + + /* make p look like ptr to x */ + + if (!ISPTR(p->n_type)) + p->n_type = PTR+UNIONTY; + + t = INCREF(s->stype); + q = INCQAL(s->squal); + d = s->sdf; + ap = s->sap; +#ifdef GCC_COMPAT + if ((yap = attr_find(ap, GCC_ATYP_PACKED)) != NULL) + xap = yap; + else if (xap != NULL) + ap = attr_add(ap, attr_dup(xap)); + /* xap set if packed struct */ +#else + yap = NULL; +#endif + + p = makety(p, t, q, d, ap); + + /* compute the offset to be added */ + + off = s->soffset; + dsc = s->sclass; + + if (dsc & FIELD) { + TWORD ftyp = s->stype; + int fal = talign(ftyp, ap); + fsz = dsc&FLDSIZ; + off = (off/fal)*fal; + p = offplus(p, off, t, q, d, ap); + p = block(FLD, p, NULL, ftyp, 0, ap); + p->n_qual = q; + p->n_rval = PKFIELD(fsz, s->soffset%fal); + /* make type int or some other signed type */ + if (fsz < SZINT) + ftyp = INT; + else if (fsz > SZINT && fsz < SZLONG && ftyp < LONG) + ftyp = LONG; + else if (fsz > SZLONG && fsz < SZLONGLONG && ftyp < LONGLONG) + ftyp = LONGLONG; + if (ftyp != p->n_type) + p = makety(p, ftyp, 0, 0, 0); + } else { + p = offplus(p, off, t, q, d, ap); +#ifndef CAN_UNALIGN + /* if target cannot handle unaligned addresses, fix here */ +#endif + } + + p = clocal(p); + return p; +} + +int +notlval(register P1ND *p) +{ + /* return 0 if p an lvalue, 1 otherwise */ + + again: + + switch( p->n_op ){ + + case FLD: + p = p->n_left; + goto again; + + case NAME: + case OREG: + case UMUL: + if( ISARY(p->n_type) || ISFTN(p->n_type) ) return(1); + /* FALLTHROUGH */ + case TEMP: + case REG: + return(0); + + default: + return(1); + } +} + +/* make a constant node with value i */ +P1ND * +bcon(int i) +{ + return xbcon(i, NULL, INT); +} + +P1ND * +xbcon(CONSZ val, struct symtab *sp, TWORD type) +{ + P1ND *p; + + p = block(ICON, NULL, NULL, type, 0, 0); + slval(p, val); + p->n_sp = sp; + return clocal(p); +} + +P1ND * +bpsize(P1ND *p) +{ + int isdyn(struct symtab *sp); + struct symtab s; + P1ND *q, *r; + TWORD t; + int sz; + + s.stype = DECREF(p->n_type); + s.sdf = p->n_df; + if (isdyn(&s)) { + q = bcon(1); + for (t = s.stype; t > BTMASK; t = DECREF(t)) { + if (ISPTR(t)) + return buildtree(MUL, q, bcon(SZPOINT(t))); + if (ISARY(t)) { + if (s.sdf->ddim < 0) + r = tempnode(-s.sdf->ddim, INT, 0, 0); + else + r = bcon(s.sdf->ddim/SZCHAR); + q = buildtree(MUL, q, r); + s.sdf++; + } + } + sz = (int)tsize(t, s.sdf, p->n_ap); + p = buildtree(MUL, q, bcon(sz/SZCHAR)); + } else + p = (offcon(psize(p), p->n_type, p->n_df, p->n_ap)); + return p; +} + +/* + * p is a node of type pointer; psize returns the + * size of the thing pointed to + */ +OFFSZ +psize(P1ND *p) +{ + + if (!ISPTR(p->n_type)) { + uerror("pointer required"); + return(SZINT); + } + /* note: no pointers to fields */ + return(tsize(DECREF(p->n_type), p->n_df, p->n_ap)); +} + +/* + * convert an operand of p + * f is either CVTL or CVTR + * operand has type int, and is converted by the size of the other side + * convert is called when an integer is to be added to a pointer, for + * example in arrays or structures. + */ +P1ND * +convert(P1ND *p, int f) +{ + union dimfun *df; + TWORD ty, ty2; + P1ND *q, *r, *s, *rv; + + if (f == CVTL) { + q = p->n_left; + s = p->n_right; + } else { + q = p->n_right; + s = p->n_left; + } + ty2 = ty = DECREF(s->n_type); + while (ISARY(ty)) + ty = DECREF(ty); + + r = offcon(tsize(ty, s->n_df, s->n_ap), s->n_type, s->n_df, s->n_ap); + ty = ty2; + rv = bcon(1); + df = s->n_df; + while (ISARY(ty)) { + rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) : + tempnode(-df->ddim, INT, 0, 0)); + df++; + ty = DECREF(ty); + } + rv = clocal(MBLOCK(rv, r, INT, 0, 0)); + rv = optim(rv); + + r = MBLOCK(q, rv, INT, 0, 0); + r = clocal(r); + /* + * Indexing is only allowed with integer arguments, so insert + * SCONV here if arg is not an integer. + * XXX - complain? + */ + if (r->n_type != INTPTR) + r = clocal(makety(r, INTPTR, 0, 0, 0)); + if (f == CVTL) + p->n_left = r; + else + p->n_right = r; + return(p); +} + +P1ND * +pconvert(register P1ND *p) +{ + /* if p should be changed into a pointer, do so */ + + if( ISARY( p->n_type) ){ + p->n_type = DECREF( p->n_type ); + ++p->n_df; + return( buildtree( ADDROF, p, NULL ) ); + } + if( ISFTN( p->n_type) ) + return( buildtree( ADDROF, p, NULL ) ); + + return( p ); +} + +P1ND * +oconvert(register P1ND *p) +{ + /* convert the result itself: used for pointer and unsigned */ + + switch(p->n_op) { + + case LE: + case LT: + case GE: + case GT: + if(ISUNSIGNED(p->n_left->n_type) || + ISUNSIGNED(p->n_right->n_type) || + ISPTR(p->n_left->n_type) || + ISPTR(p->n_right->n_type)) + p->n_op += (ULE-LE); + /* FALLTHROUGH */ + case EQ: + case NE: + return( p ); + + case MINUS: + p->n_type = INTPTR; + p->n_ap = NULL; + return(clocal(VBLOCK(p, bpsize(p->n_left), INT, 0, 0))); + } + + cerror( "illegal oconvert: %d", p->n_op ); + + return(p); +} + +/* + * makes the operands of p agree; they are + * either pointers or integers, by this time + * with MINUS, the sizes must be the same + * with COLON, the types must be the same + */ +P1ND * +ptmatch(P1ND *p) +{ + struct attr *ap, *ap2; + union dimfun *d, *d2; + TWORD t1, t2, t, q1, q2, q; + int o; + + o = p->n_op; + t = t1 = p->n_left->n_type; + q = q1 = p->n_left->n_qual; + t2 = p->n_right->n_type; + q2 = p->n_right->n_qual; + d = p->n_left->n_df; + d2 = p->n_right->n_df; + ap = p->n_left->n_ap; + ap2 = p->n_right->n_ap; + + switch( o ){ + + case ASSIGN: + case RETURN: + { break; } + + case CAST: + if (t == VOID) { + /* just paint over */ + p->n_right = block(SCONV, p->n_right, NULL, VOID, 0, 0); + return p; + } + break; + + case MINUS: { + int isdyn(struct symtab *sp); + struct symtab s1, s2; + + s1.stype = DECREF(t); + s1.sdf = d; + s2.stype = DECREF(t2); + s2.sdf = d2; + if (isdyn(&s1) || isdyn(&s2)) + ; /* We don't know */ + else if (psize(p->n_left) != psize(p->n_right)) + uerror("illegal pointer subtraction"); + break; + } + + case COLON: + if (t1 != t2) { + /* + * Check for void pointer types. They are allowed + * to cast to/from any pointers; 6.5.15 #6. + * XXX qualified versions of void? + */ + if (ISPTR(t1) && ISPTR(t2)) { + if (BTYPE(t1) == VOID) { + t = t2; + d = d2; + ap = ap2; + break; + } + if (BTYPE(t2) == VOID) + break; + } + uerror("illegal types in :"); + } + break; + + default: /* must work harder: relationals or comparisons */ + + if( !ISPTR(t1) ){ + t = t2; + q = q2; + d = d2; + ap = ap2; + break; + } + if( !ISPTR(t2) ){ + break; + } + + /* both are pointers */ + if( talign(t2,ap2) < talign(t,ap) ){ + t = t2; + q = q2; + ap = ap2; + } + break; + } + + p->n_left = makety( p->n_left, t, q, d, ap ); + p->n_right = makety( p->n_right, t, q, d, ap ); + if( o!=MINUS && !clogop(o) ){ + + p->n_type = t; + p->n_qual = q; + p->n_df = d; + p->n_ap = ap; + } + + return(clocal(p)); +} + +/* + * Satisfy the types of various arithmetic binary ops. + * + * rules are: + * if assignment, type of LHS + * if any doubles, make double + * else if any float make float + * else if any longlongs, make long long + * else if any longs, make long + * else etcetc. + * + * If the op with the highest rank is unsigned, this is the resulting type. + * See: 6.3.1.1 rank order equal of signed and unsigned types + * 6.3.1.8 Usual arithmetic conversions + */ +static P1ND * +tymatch(P1ND *p) +{ + TWORD tl, tr, t; + P1ND *l, *r; + int o; + + o = p->n_op; + r = p->n_right; + l = p->n_left; + + tl = l->n_type; + tr = r->n_type; + + if (tl == BOOL) tl = BOOL_TYPE; + if (tr == BOOL) tr = BOOL_TYPE; + + if (casgop(o)) { + if (r->n_op != ICON && tl < FLOAT && tr < FLOAT && + DEUNSIGN(tl) < DEUNSIGN(tr) && o != CAST) + warner(Wtruncate, tnames[tr], tnames[tl]); + if (l->n_type == BOOL && r->n_type != BOOL) { + /* must create a ?: */ + p->n_right = buildtree(QUEST, p->n_right, + buildtree(COLON, bcon(1), bcon(0))); + } + p->n_right = makety(p->n_right, l->n_type, 0, 0, 0); + t = p->n_type = l->n_type; + p->n_ap = l->n_ap; + } else { + t = tl > tr ? tl : tr; /* MAX */ + /* This depends on ctype() called early */ + if (o != COLON && t < INT) + t = INT; + if (tl != t) p->n_left = makety(p->n_left, t, 0, 0, 0); + if (tr != t) p->n_right = makety(p->n_right, t, 0, 0, 0); + if (o == COLON && l->n_type == BOOL && r->n_type == BOOL) + t = p->n_type = BOOL; + else if (!clogop(o)) + p->n_type = t; + } +#ifdef PCC_DEBUG + if (tdebug) { + printf("tymatch(%p): ", p); + tprint(tl, 0); + printf(" %s ", copst(o)); + tprint(tr, 0); + printf(" => "); + tprint(t, 0); + printf("\n"); + p1fwalk(p, eprint, 0); + } +#endif + return p; +} + +/* + * make p into type t by inserting a conversion + */ +P1ND * +makety(P1ND *p, TWORD t, TWORD q, union dimfun *d, struct attr *ap) +{ + + if (t == p->n_type) { + p->n_df = d; + p->n_ap = ap; + p->n_qual = q; + return(p); + } + + if (ISITY(t) || ISCTY(t) || ISITY(p->n_type) || ISCTY(p->n_type)) + cerror("makety"); + + if (concast(p, t)) + return clocal(p); + + p = block(t & TMASK ? PCONV : SCONV, p, NULL, t, d, ap); + p->n_qual = q; + return clocal(p); +} + +P1ND * +block(int o, P1ND *l, P1ND *r, TWORD t, union dimfun *d, struct attr *ap) +{ + register P1ND *p; + + p = p1alloc(); + p->n_rval = 0; + p->n_op = o; + slval(p, 0); + p->n_left = l; + p->n_right = r; + p->n_type = t; + p->n_qual = 0; + p->n_df = d; + p->n_ap = ap; + return(p); +} + +/* + * Return the constant value from an ICON. + */ +CONSZ +icons(P1ND *p) +{ + /* if p is an integer constant, return its value */ + CONSZ val; + + if (p->n_op != ICON || p->n_sp != NULL) { + uerror( "constant expected"); + val = 1; + } else + val = glval(p); + p1tfree(p); + return(val); +} + +/* + * the intent of this table is to examine the + * operators, and to check them for + * correctness. + * + * The table is searched for the op and the + * modified type (where this is one of the + * types INT (includes char and short), LONG, + * DOUBLE (includes FLOAT), and POINTER + * + * The default action is to make the node type integer + * + * The actions taken include: + * PUN check for puns + * CVTL convert the left operand + * CVTR convert the right operand + * TYPL the type is determined by the left operand + * TYPR the type is determined by the right operand + * TYMATCH force type of left and right to match,by inserting conversions + * PTMATCH like TYMATCH, but for pointers + * LVAL left operand must be lval + * CVTO convert the op + * NCVT do not convert the operands + * OTHER handled by code + * NCVTR convert the left operand, not the right... + * + */ + +# define MINT 01 /* integer */ +# define MDBI 02 /* integer or double */ +# define MSTR 04 /* structure */ +# define MPTR 010 /* pointer */ +# define MPTI 020 /* pointer or integer */ + +int +opact(P1ND *p) +{ + int mt12, mt1, mt2, o; + + mt1 = mt2 = mt12 = 0; + + switch (coptype(o = p->n_op)) { + case BITYPE: + mt12=mt2 = moditype(p->n_right->n_type); + /* FALLTHROUGH */ + case UTYPE: + mt12 &= (mt1 = moditype(p->n_left->n_type)); + break; + } + + switch( o ){ + + case NAME : + case ICON : + case FCON : + case CALL : + case UCALL: + case UMUL: + { return( OTHER ); } + case UMINUS: + if( mt1 & MDBI ) return( TYPL+PROML ); + break; + + case COMPL: + if( mt1 & MINT ) return( TYPL+PROML ); + break; + + case ADDROF: + return( NCVT+OTHER ); + case NOT: + return( PROML ); + +/* case INIT: */ + case CM: + case CBRANCH: + case ANDAND: + case OROR: + return( 0 ); + + case MUL: + case DIV: + if( mt12 & MDBI ) return( TYMATCH ); + break; + + case MOD: + case AND: + case OR: + case ER: + if( mt12 & MINT ) return( TYMATCH ); + break; + + case LS: + case RS: + if( mt12 & MINT ) return( TYPL+OTHER+PROML ); + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + if( mt12 & MDBI ) return( TYMATCH+CVTO ); + else if( mt12 & MPTR ) return( PTMATCH+PUN+CVTO ); + else if( mt12 & MPTI ) return( PTMATCH+PUN ); + else break; + + case QUEST: + return( TYPR+OTHER ); + case COMOP: + return( TYPR ); + + case STREF: + return( NCVTR+OTHER ); + + case FORCE: + return( TYPL ); + + case COLON: + if( mt12 & MDBI ) return( TYMATCH ); + else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN ); + else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN ); + else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN ); + else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER ); + break; + + case ASSIGN: + case RETURN: + if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER ); + /* FALLTHROUGH */ + case CAST: + if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); + else if( mt1 & MPTR) return( LVAL+PTMATCH+PUN ); + else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); + break; + + case MINUS: + if (mt12 & MPTR) + return(CVTO+PTMATCH+PUN); + if (mt2 & MPTR) + break; + /* FALLTHROUGH */ + case PLUS: + if (mt12 & MDBI) + return(TYMATCH); + else if ((mt1&MPTR) && (mt2&MINT)) + return(TYPL+CVTR); + else if ((mt1&MINT) && (mt2&MPTR)) + return(TYPR+CVTL); + + } + uerror("operands of %s have incompatible types", copst(o)); + return(NCVT); +} + +int +moditype(TWORD ty) +{ + switch (ty) { + + case STRTY: + case UNIONTY: + return( MSTR ); + + case BOOL: + case CHAR: + case SHORT: + case UCHAR: + case USHORT: + case UNSIGNED: + case ULONG: + case ULONGLONG: + case INT: + case LONG: + case LONGLONG: + return( MINT|MDBI|MPTI ); + case FLOAT: + case DOUBLE: + case LDOUBLE: +#ifndef NO_COMPLEX + case FCOMPLEX: + case COMPLEX: + case LCOMPLEX: + case FIMAG: + case IMAG: + case LIMAG: +#endif + return( MDBI ); + default: + return( MPTR|MPTI ); + + } +} + +int tvaloff = MAXREGS+NPERMREG > 100 ? MAXREGS+NPERMREG + 100 : 100; + +/* + * Returns a TEMP node with temp number nr. + * If nr == 0, return a node with a new number. + */ +P1ND * +tempnode(int nr, TWORD type, union dimfun *df, struct attr *ap) +{ + P1ND *r; + + if (tvaloff == -NOOFFSET) + tvaloff++; /* Skip this for array indexing */ + r = block(TEMP, NULL, NULL, type, df, ap); + regno(r) = nr ? nr : tvaloff; + tvaloff += szty(type); + return r; +} + +/* + * Do sizeof on p. + */ +P1ND * +doszof(P1ND *p) +{ + extern P1ND *arrstk[10]; + extern int arrstkp; + union dimfun *df; + TWORD ty; + P1ND *rv, *q; + int astkp; + + if (p->n_op == FLD) + uerror("can't apply sizeof to bit-field"); + + /* + * Arrays may be dynamic, may need to make computations. + */ + + rv = bcon(1); + df = p->n_df; + ty = p->n_type; + astkp = 0; + while (ISARY(ty)) { + if (df->ddim == NOOFFSET) + uerror("sizeof of incomplete type"); + if (df->ddim < 0) { + if (arrstkp) + q = arrstk[astkp++]; + else + q = tempnode(-df->ddim, INT, 0, 0); + } else + q = bcon(df->ddim); + rv = buildtree(MUL, rv, q); + df++; + ty = DECREF(ty); + } + rv = buildtree(MUL, rv, + xbcon(tsize(ty, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR)); + p1tfree(p); + arrstkp = 0; /* XXX - may this fail? */ + return rv; +} + +#ifdef PCC_DEBUG +void +eprint(P1ND *p, int down, int *a, int *b) +{ + int ty; + + *a = *b = down+1; + while( down > 1 ){ + printf( "\t" ); + down -= 2; + } + if( down ) printf( " " ); + + ty = coptype( p->n_op ); + + printf("%p) %s, ", p, copst(p->n_op)); + if (p->n_op == XARG || p->n_op == XASM) + printf("id '%s', ", p->n_name); + if (ty == LTYPE) { + printf(CONFMT, glval(p)); + if (p->n_op == NAME || p->n_op == ICON) + printf(", %p, ", p->n_sp); + else if (p->n_op == FCON) + printf(", %Lf, ", p->n_dcon->fp); + else + printf(", %d, ", p->n_rval); + } + tprint(p->n_type, p->n_qual); + printf( ", %p, ", p->n_df); +#ifdef GCC_COMPAT + dump_attr(p->n_ap); +#endif +} +# endif + +/* + * Emit everything that should be emitted on the left side + * of a comma operator, and remove the operator. + * Do not traverse through QUEST, ANDAND and OROR. + * Enable this for all targets when stable enough. + */ +static void +comops(P1ND *p) +{ + int o; + P1ND *q; + + while (p->n_op == COMOP) { + /* XXX hack for GCC ({ }) ops */ + if (p->n_left->n_op == GOTO) { + int v = (int)glval(p->n_left->n_left); + ecomp(p->n_left); + plabel(v+2); + } else + ecomp(p->n_left); /* will recurse if more COMOPs */ + q = p->n_right; + *p = *q; + p1nfree(q); + } + o = coptype(p->n_op); + if (p->n_op == QUEST || p->n_op == ANDAND || p->n_op == OROR) + o = UTYPE; + if (o != LTYPE) + comops(p->n_left); + if (o == BITYPE) + comops(p->n_right); +} + +/* + * Walk up through the tree from the leaves, + * removing constant operators. + */ +static void +logwalk(P1ND *p) +{ + int o = coptype(p->n_op); + P1ND *l, *r; + + l = p->n_left; + r = p->n_right; + switch (o) { + case LTYPE: + return; + case BITYPE: + logwalk(r); + /* FALLTHROUGH */ + case UTYPE: + logwalk(l); + } + if (!clogop(p->n_op)) + return; + if (p->n_op == NOT && l->n_op == ICON) { + slval(p, (glval(l) == 0)); + p1nfree(l); + p->n_op = ICON; + } + if (l->n_op == ICON && r->n_op == ICON) { + if (conval(l, p->n_op, r) == 0) { + /* + * people sometimes tend to do really odd compares, + * like "if ("abc" == "def")" etc. + * do it runtime instead. + */ + } else { + slval(p, glval(l)); + p->n_op = ICON; + p1nfree(l); + p1nfree(r); + } + } +} + +/* + * Removes redundant logical operators for branch conditions. + */ +static void +fixbranch(P1ND *p, int label) +{ + + logwalk(p); + + if (p->n_op == ICON) { + if (glval(p) != 0) + branch(label); + p1nfree(p); + } else { + if (!clogop(p->n_op)) /* Always conditional */ + p = buildtree(NE, p, bcon(0)); + ecode(buildtree(CBRANCH, p, bcon(label))); + } +} + +/* + * Write out logical expressions as branches. + */ +static void +andorbr(P1ND *p, int true, int false) +{ + P1ND *q; + int o, lab; + + lab = -1; + switch (o = p->n_op) { + case EQ: + case NE: + /* + * Remove redundant EQ/NE nodes. + */ + while (((o = p->n_left->n_op) == EQ || o == NE) && + p->n_right->n_op == ICON) { + o = p->n_op; + q = p->n_left; + if (glval(p->n_right) == 0) { + p1nfree(p->n_right); + *p = *q; + p1nfree(q); + if (o == EQ) + p->n_op = p1negrel[p->n_op - EQ]; +#if 0 + p->n_op = NE; /* toggla */ +#endif + } else if (glval(p->n_right) == 1) { + p1nfree(p->n_right); + *p = *q; + p1nfree(q); + if (o == NE) + p->n_op = p1negrel[p->n_op - EQ]; +#if 0 + p->n_op = EQ; /* toggla */ +#endif + } else + break; /* XXX - should always be false */ + + } + /* FALLTHROUGH */ + case LE: + case LT: + case GE: + case GT: +calc: if (true < 0) { + p->n_op = p1negrel[p->n_op - EQ]; + true = false; + false = -1; + } + + rmcops(p->n_left); + rmcops(p->n_right); + fixbranch(p, true); + if (false >= 0) + branch(false); + break; + + case ULE: + case UGT: + /* Convert to friendlier ops */ + if (nncon(p->n_right) && glval(p->n_right) == 0) + p->n_op = o == ULE ? EQ : NE; + goto calc; + + case UGE: + case ULT: + /* Already true/false by definition */ + if (nncon(p->n_right) && glval(p->n_right) == 0) { + if (true < 0) { + o = o == ULT ? UGE : ULT; + true = false; + } + rmcops(p->n_left); + ecode(p->n_left); + rmcops(p->n_right); + ecode(p->n_right); + p1nfree(p); + if (o == UGE) /* true */ + branch(true); + break; + } + goto calc; + + case ANDAND: + lab = false<0 ? getlab() : false ; + andorbr(p->n_left, -1, lab); + comops(p->n_right); + andorbr(p->n_right, true, false); + if (false < 0) + plabel( lab); + p1nfree(p); + break; + + case OROR: + lab = true<0 ? getlab() : true; + andorbr(p->n_left, lab, -1); + comops(p->n_right); + andorbr(p->n_right, true, false); + if (true < 0) + plabel( lab); + p1nfree(p); + break; + + case NOT: + andorbr(p->n_left, false, true); + p1nfree(p); + break; + + default: + rmcops(p); + if (true >= 0) + fixbranch(p, true); + if (false >= 0) { + if (true >= 0) + branch(false); + else + fixbranch(buildtree(EQ, p, bcon(0)), false); + } + } +} + +/* + * Create a node for either TEMP or on-stack storage. + */ +P1ND * +cstknode(TWORD t, union dimfun *df, struct attr *ap) +{ + struct symtab *sp; + + /* create a symtab entry suitable for this type */ + sp = getsymtab("0hej", SSTMT); + sp->stype = t; + sp->sdf = df; + sp->sap = ap; + sp->sclass = AUTO; + sp->soffset = NOOFFSET; + oalloc(sp, &autooff); + return nametree(sp); + +} + +/* + * Massage the output trees to remove C-specific nodes: + * COMOPs are split into separate statements. + * QUEST/COLON are rewritten to branches. + * ANDAND/OROR/NOT are rewritten to branches for lazy-evaluation. + * CBRANCH conditions are rewritten for lazy-evaluation. + */ +static void +rmcops(P1ND *p) +{ + TWORD type; + P1ND *q, *r, *tval; + int o, ty, lbl, lbl2; + + tval = NULL; + o = p->n_op; + ty = coptype(o); + if (BTYPE(p->n_type) == ENUMTY) { /* fixup enum */ + struct symtab *sp = strmemb(p->n_ap); + MODTYPE(p->n_type, sp->stype); + /* + * XXX may fail if these are true: + * - variable-sized enums + * - non-byte-addressed targets. + */ + if (BTYPE(p->n_type) == ENUMTY && ISPTR(p->n_type)) + MODTYPE(p->n_type, INT); /* INT ok? */ + } + switch (o) { + case QUEST: + + /* + * Create a branch node from ?: + * || and && must be taken special care of. + */ + type = p->n_type; + andorbr(p->n_left, -1, lbl = getlab()); + + /* Make ASSIGN node */ + /* Only if type is not void */ + q = p->n_right->n_left; + comops(q); + if (type != VOID) { + tval = cstknode(q->n_type, q->n_df, q->n_ap); + q = buildtree(ASSIGN, p1tcopy(tval), q); + } + rmcops(q); + ecode(q); /* Done with assign */ + branch(lbl2 = getlab()); + plabel( lbl); + + q = p->n_right->n_right; + comops(q); + if (type != VOID) { + q = buildtree(ASSIGN, p1tcopy(tval), q); + } + rmcops(q); + ecode(q); /* Done with assign */ + + plabel( lbl2); + + p1nfree(p->n_right); + if (p->n_type != VOID) { + *p = *tval; + p1nfree(tval); + } else { + p->n_op = ICON; + slval(p, 0); + p->n_sp = NULL; + } + break; + + case ULE: + case ULT: + case UGE: + case UGT: + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: + case ANDAND: + case OROR: + case NOT: +#ifdef SPECIAL_CCODES +#error fix for private CCODES handling +#else + r = p1alloc(); + *r = *p; + andorbr(r, -1, lbl = getlab()); + + tval = cstknode(p->n_type, p->n_df, p->n_ap); + + ecode(buildtree(ASSIGN, p1tcopy(tval), bcon(1))); + branch(lbl2 = getlab()); + plabel( lbl); + ecode(buildtree(ASSIGN, p1tcopy(tval), bcon(0))); + plabel( lbl2); + + *p = *tval; + p1nfree(tval); + +#endif + break; + case CBRANCH: + andorbr(p->n_left, glval(p->n_right), -1); + p1nfree(p->n_right); + p->n_op = ICON; p->n_type = VOID; + break; + case COMOP: + cerror("COMOP error"); + + default: + if (ty == LTYPE) + return; + rmcops(p->n_left); + if (ty == BITYPE) + rmcops(p->n_right); + } +} + +/* + * Return 1 if an assignment is found. + */ +static int +has_se(P1ND *p) +{ + if (p->n_op == COMOP && p->n_left->n_op == GOTO) + return 1; + if (cdope(p->n_op) & ASGFLG) + return 1; + if (coptype(p->n_op) == LTYPE) + return 0; + if (has_se(p->n_left)) + return 1; + if (coptype(p->n_op) == BITYPE) + return has_se(p->n_right); + return 0; +} + +#ifndef FIELDOPS + +/* avoid promotion to int */ +#define TYPMOD(o, p, n, t) clocal(block(o, p, n, t, 0, 0)) +#define TYPLS(p, n, t) TYPMOD(LS, p, n, t) +#define TYPRS(p, n, t) TYPMOD(RS, p, n, t) +#define TYPOR(p, q, t) TYPMOD(OR, p, q, t) +#define TYPAND(p, q, t) TYPMOD(AND, p, q, t) + +/* + * Read an unaligned bitfield from position pointed to by p starting at + * off and size fsz and return a tree of type t with resulting data. + * ct is the type we must use to read data. + */ +static P1ND * +rdualfld(P1ND *p, TWORD t, TWORD ct, int off, int fsz) +{ + int t2f, inbits, tsz, ctsz; + P1ND *q, *r; + + ct = ENUNSIGN(ct); + ctsz = (int)tsize(ct, 0, 0); + + /* traverse until first data byte */ + for (t2f = 0; off >= ctsz; t2f++, off -= ctsz) + ; +#ifdef UNALIGNED_ACCESS + /* try to squeeze it into an int */ + if (off + fsz > ctsz && off + fsz <= SZINT) { + ct = UNSIGNED; + ctsz = SZINT; + } +#endif + p = makety(p, PTR|ct, 0, 0, 0); + if (off + fsz <= ctsz) { + /* only one operation needed */ + q = buildtree(UMUL, buildtree(PLUS, p, bcon(t2f)), 0); + if (!ISUNSIGNED(t)) { + ct = DEUNSIGN(ct); + q = makety(q, ct, 0, 0, 0); + } + q = TYPLS(q, bcon(ctsz-fsz-off), ct); + q = TYPRS(q, bcon(ctsz-fsz), ct); + q = makety(q, t, 0, 0, 0); + } else { + q = buildtree(UMUL, buildtree(PLUS, p1tcopy(p), bcon(t2f)), 0); + q = makety(TYPRS(q, bcon(off), ct), t, 0, 0, 0); + inbits = ctsz - off; + t2f++; + + while (fsz > inbits) { + r = buildtree(UMUL, + buildtree(PLUS, p1tcopy(p), bcon(t2f)), 0); + r = makety(r, t, 0, 0, 0); + r = TYPLS(r, bcon(inbits), t); + q = TYPOR(q, r, t); + inbits += ctsz; + t2f++; + } + /* sign/zero extend XXX - RS must sign extend */ + tsz = (int)tsize(t, 0, 0); + if (!ISUNSIGNED(t)) { + t = DEUNSIGN(t); + q = makety(q, t, 0, 0, 0); + } + q = TYPLS(q, bcon(tsz-fsz), t); + q = TYPRS(q, bcon(tsz-fsz), t); + p1tfree(p); + } + + return q; +} + +/* + * Write val to a (unaligned) bitfield with length fsz positioned off bits + * from d. Bitfield type is t, and type to use when writing is ct. + * neither f nor d should have any side effects if copied. + * Multiples of ct are supposed to be written without problems. + * Both val and d are free'd after use. + */ +static P1ND * +wrualfld(P1ND *val, P1ND *d, TWORD t, TWORD ct, int off, int fsz) +{ + P1ND *p, *q, *r, *rn, *s; + int ctsz, t2f, inbits; + + ctsz = (int)tsize(ct, 0, 0); + + ct = ENUNSIGN(ct); + d = makety(d, PTR|ct, 0, 0, 0); + + for (t2f = 0; off >= ctsz; t2f++, off -= ctsz) + ; + + if (off + fsz <= ctsz) { + r = tempnode(0, ct, 0, 0); + + /* only one operation needed */ + d = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0); + p = p1tcopy(d); + p = TYPAND(p, xbcon(~(SZMASK(fsz) << off), 0, ct), ct); + + val = makety(val, ct, 0, 0, 0); + q = TYPAND(val, xbcon(SZMASK(fsz), 0, ct), ct); + q = buildtree(ASSIGN, p1tcopy(r), q); + + q = TYPLS(q, bcon(off), ct); + p = TYPOR(p, q, ct); + p = makety(p, t, 0, 0, 0); + rn = buildtree(ASSIGN, d, p); + rn = buildtree(COMOP, rn, makety(r, t, 0, 0, 0)); + } else { + s = makety(p1tcopy(val), t, 0, 0, 0); + s = TYPAND(s, xbcon(SZMASK(fsz), 0, t), t); + + r = buildtree(UMUL, buildtree(PLUS, p1tcopy(d), bcon(t2f)), 0); + p = p1tcopy(r); + p = TYPAND(p, xbcon(SZMASK(off), 0, ct), ct); + q = p1tcopy(val); + q = TYPLS(q, bcon(off), t); + q = makety(q, ct, 0, 0, 0); + p = TYPOR(p, q, ct); + rn = buildtree(ASSIGN, r, p); + inbits = ctsz - off; + t2f++; + + while (fsz > inbits+ctsz) { + r = buildtree(UMUL, + buildtree(PLUS, p1tcopy(d), bcon(t2f)), 0); + q = p1tcopy(val); + q = TYPRS(q, bcon(inbits), t); + q = makety(q, ct, 0, 0, 0); + rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, q)); + t2f++; + inbits += ctsz; + } + + r = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0); + p = p1tcopy(r); + p = TYPAND(p, makety(xbcon(~SZMASK(fsz-inbits), 0, ct), + ct, 0, 0, 0), ct); + q = TYPRS(val, bcon(inbits), t); + q = TYPAND(q, xbcon(SZMASK(fsz-inbits), 0, t), t); + q = makety(q, ct, 0, 0, 0); + p = TYPOR(p, q, ct); + rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, p)); + rn = buildtree(COMOP, rn, s); + } + return rn; +} + +/* + * Rewrite bitfield operations to shifts. + */ +static P1ND * +rmfldops(P1ND *p) +{ + TWORD t, ct; + P1ND *q, *r, *t1, *t2, *bt; + int fsz, foff; + + if (p->n_op == FLD) { + /* Rewrite a field read operation */ + fsz = UPKFSZ(p->n_rval); + foff = UPKFOFF(p->n_rval); + q = buildtree(ADDROF, p->n_left, NULL); + + ct = t = p->n_type; +#ifdef GCC_COMPAT + if (attr_find(p->n_ap, GCC_ATYP_PACKED) && + coptype(q->n_op) != LTYPE) { + t1 = tempnode(0, q->n_type, 0, 0); + bt = buildtree(ASSIGN, p1tcopy(t1), q); + q = t1; +#ifndef UNALIGNED_ACCESS + ct = UCHAR; +#endif + } else +#endif + bt = bcon(0); +#if TARGET_ENDIAN == TARGET_BE + foff = (int)tsize(t, 0, 0) - fsz - foff; +#endif + q = rdualfld(q, t, ct, foff, fsz); + if (fsz < SZINT) + q = makety(q, INT, 0, 0, 0); + if (p->n_type != INT) + q = makety(q, p->n_type, 0, 0, 0); + p->n_left = bt; + p->n_right = q; + p->n_op = COMOP; + } else if (((cdope(p->n_op)&ASGOPFLG) || p->n_op == ASSIGN || + p->n_op == INCR || p->n_op == DECR) && p->n_left->n_op == FLD) { + /* + * Rewrite a field write operation + * More difficult than a read op since we must care + * about side effects. + */ + q = p->n_left; + fsz = UPKFSZ(q->n_rval); + foff = UPKFOFF(q->n_rval); + t = q->n_left->n_type; +#if TARGET_ENDIAN == TARGET_BE + foff = (int)tsize(t, 0, 0) - fsz - foff; +#endif + bt = NULL; + if (p->n_right->n_op != ICON && p->n_right->n_op != NAME) { + t2 = tempnode(0, p->n_right->n_type, 0, 0); + bt = buildtree(ASSIGN, p1tcopy(t2), p->n_right); + } else + t2 = p->n_right; + + ct = t; +#ifdef GCC_COMPAT +#ifndef UNALIGNED_ACCESS + if (attr_find(q->n_ap, GCC_ATYP_PACKED)) + ct = UCHAR; +#endif +#endif + /* t2 is what we have to write (RHS of ASSIGN) */ + /* bt is (eventually) something that must be written */ + + if (q->n_left->n_op == UMUL) { + /* LHS of assignment may have side effects */ + q = q->n_left; + t1 = tempnode(0, q->n_left->n_type, 0, 0); + r = buildtree(ASSIGN, p1tcopy(t1), q->n_left); + + bt = bt ? block(COMOP, bt, r, INT, 0, 0) : r; + q->n_left = t1; + } + t1 = buildtree(ADDROF, p->n_left->n_left, 0); + + /* t1 is lval where to write (and read) */ + + if (p->n_op == ASSIGN) { + q = wrualfld(t2, t1, t, ct, foff, fsz); + if (bt) + q = block(COMOP, bt, q, t, 0, 0); + p1nfree(p->n_left); + p->n_left = bcon(0); + p->n_right = q; + p->n_op = COMOP; + } else + cerror("NOTASSIGN!"); + + t = p->n_type; + if (ISUNSIGNED(p->n_type)) { + /* mask away unwanted bits */ + if ((t == LONGLONG && fsz == SZLONGLONG-1) || + (t == LONG && fsz == SZLONG-1) || + (t == INT && fsz == SZINT-1)) + p = buildtree(AND, p, + xbcon((1LL << fsz)-1, 0, t)); + } else { + /* Correct value in case of signed bitfield. */ + if (t == LONGLONG) + fsz = SZLONGLONG - fsz; + else if (t == LONG) + fsz = SZLONG - fsz; + else + fsz = SZINT - fsz; + p = buildtree(LS, p, bcon(fsz)); +#ifdef RS_DIVIDES + p = buildtree(RS, p, bcon(fsz)); +#else + { + p = buildtree(DIV, p, xbcon(1LL << fsz, 0, t)); + /* avoid wrong sign if divisor gets negative */ + if ((t == LONGLONG && fsz == SZLONGLONG-1) || + (t == LONG && fsz == SZLONG-1) || + (t == INT && fsz == SZINT-1)) + p = buildtree(UMINUS, p, NULL); + } +#endif + } + } + if (coptype(p->n_op) != LTYPE) + p->n_left = rmfldops(p->n_left); + if (coptype(p->n_op) == BITYPE) + p->n_right = rmfldops(p->n_right); + return p; +} +#endif + +void +ecomp(P1ND *p) +{ + +#ifdef PCC_DEBUG + if (edebug) { + printf("ecomp\n"); + p1fwalk(p, eprint, 0); + } +#endif + if (!reached) { + warner(Wunreachable_code); + reached = 1; + } + p = optim(p); +#ifndef FIELDOPS + p = rmfldops(p); +#endif + comops(p); + rmcops(p); + if (p->n_op == ICON && p->n_type == VOID) + p1tfree(p); + else + ecode(p); +} + + +#ifdef PASS1 +/* + * Print out full tree. + * Nodes are already converted to pass2 style. + */ +static void +p2print(NODE *p) +{ + struct attr *ap; + int ty, i; + + ty = optype(p->n_op); + + printf("\" %d ", p->n_op); + + printf("%d %d ", p->n_type, p->n_qual); + if (ty == LTYPE) + printf(CONFMT " ", p->n_lval); + if (ty != BITYPE) { + if (p->n_op != NAME && p->n_op != ICON) + printf("%d ", p->n_rval); + } + + /* handle special cases */ + if (p->n_op == NAME || p->n_op == ICON || + p->n_op == XASM || p->n_op == XARG) + printf("%s", p->n_name); + + if (p->n_ap) { + printf(" + "); + for (ap = p->n_ap; ap; ap = ap->next) { + printf("%d %d ", ap->atype, ap->sz); + for (i = 0; i < ap->sz; i++) + printf("%d ", ap->iarg(i)); + } + } + printf("\n"); + + if (ty != LTYPE) + p2print(p->n_left); + if (ty == BITYPE) + p2print(p->n_right); +} + +/* + * Print out the code trees for pass2. + * First on line is always a sync char, second is space: + * ! - Prologue. + * " - Node + * ^ - Label + * $ - Assembler statement + * % - Epilog. + * # - Line number + * & - File name + * * - Passthrough line. + */ +void +pass2_compile(struct interpass *ip) +{ + struct interpass_prolog *ipp; + static int oldlineno; + int i; + + if (oldlineno != ip->lineno) + printf("# %d\n", oldlineno = ip->lineno); + + switch (ip->type) { + case IP_PROLOG: + ipp = (struct interpass_prolog *)ip; + printf("! %d %d %d %d %d %s\n", + ipp->ipp_type, ipp->ipp_vis, ip->ip_lbl, ipp->ip_tmpnum, + ipp->ip_lblnum, ipp->ipp_name); +#ifdef TARGET_IPP_MEMBERS + printf("( "); + target_members_print_prolog(ipp); + printf("\n"); +#endif + break; + case IP_NODE: + p2print(ip->ip_node); + tfree(ip->ip_node); + break; + case IP_DEFLAB: + printf("^ %d\n", ip->ip_lbl); + break; + case IP_ASM: + printf("$ %s\n", ip->ip_asm); + break; + case IP_EPILOG: + ipp = (struct interpass_prolog *)ip; + printf("%% %d %d %d %d %s", + ipp->ipp_autos, ip->ip_lbl, ipp->ip_tmpnum, + ipp->ip_lblnum, ipp->ipp_name); + if (ipp->ip_labels[0]) { + for (i = 0; ipp->ip_labels[i]; i++) + ; + printf(" + %d", i); + for (i = 0; ipp->ip_labels[i]; i++) + printf(" %d", ipp->ip_labels[i]); + } + printf("\n"); +#ifdef TARGET_IPP_MEMBERS + printf(") "); + target_members_print_epilog(ipp); + printf("\n"); +#endif + break; + default: + cerror("Missing %d", ip->type); + } + free(ip); +} +#endif + +static char * +sptostr(struct symtab *sp) +{ + char *cp = tmpalloc(32); + int n = sp->soffset; + if (n < 0) + n = -n; + snprintf(cp, 32, LABFMT, n); + return cp; +} + +static NODE * +p2tree(P1ND *p) +{ + struct attr *ap; + struct symtab *q; + NODE *np; + int ty; + + myp2tree(p); /* local action can be taken here */ + + /* Fix left imaginary types */ + if (ISITY(BTYPE(p->n_type))) + MODTYPE(p->n_type, p->n_type - (FIMAG-FLOAT)); + + ty = coptype(p->n_op); + np = memset(talloc(), 0, sizeof(NODE)); + + /* Copy common data */ + np->n_op = p->n_op; + np->n_type = p->n_type; + np->n_qual = p->n_qual; + if (ty != BITYPE) + np->n_rval = p->n_rval; + if (ty == LTYPE) { + slval(np, glval(p)); + } + + /* cleanup attributes. + * copy those that are supposed to go into pass2 */ + for (ap = p->n_ap; ap; ap = ap->next) + if (ap->atype < ATTR_MI_MAX) + np->n_ap = attr_add(np->n_ap, attr_dup(ap)); + + switch( p->n_op ){ + case NAME: + case ICON: + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0) +#ifdef GCC_COMPAT + || q->sflags == SLBLNAME +#endif + ) { + np->n_name = sptostr(q); + if ((q->sflags & SMASK) == SSTRING) + q->sflags |= SASG; + } else + np->n_name = getexname(q); + } else + np->n_name = ""; + break; + + case STASG: + case STARG: + case STCALL: + case USTCALL: + ap = attr_new(ATTR_P2STRUCT, 2); + np->n_ap = attr_add(np->n_ap, ap); + /* STASG used for stack array init */ + if (p->n_op == STASG && ISARY(p->n_type)) { + int size1 = (int)tsize(p->n_type, p->n_left->n_df, + p->n_left->n_ap)/SZCHAR; + ap->iarg(0) = (int)tsize(p->n_type, p->n_right->n_df, + p->n_right->n_ap)/SZCHAR; + if (size1 < ap->iarg(0)) + ap->iarg(0) = size1; + ap->iarg(1) = talign(p->n_type, + p->n_left->n_ap)/SZCHAR; + break; + } + /* set up size parameters */ + ap->iarg(0) = (int)((tsize(STRTY, p->n_left->n_df, + p->n_left->n_ap)+SZCHAR-1)/SZCHAR); + ap->iarg(1) = talign(STRTY,p->n_left->n_ap)/SZCHAR; + if (ap->iarg(1) == 0) + ap->iarg(1) = 1; /* At least char for packed structs */ + break; + + case XARG: + case XASM: + np->n_name = tmpstrdup(p->n_name); + break; + + default: + np->n_name = ""; + } + + if (ty != LTYPE) + np->n_left = p2tree(p->n_left); + if (ty == BITYPE) + np->n_right = p2tree(p->n_right); + return np; +} + + +/* + * Change void data types into char. + */ +static void +delvoid(P1ND *p, void *arg) +{ + /* Convert "PTR undef" (void *) to "PTR uchar" */ + if (BTYPE(p->n_type) == VOID) + p->n_type = (p->n_type & ~BTMASK) | UCHAR; + if (BTYPE(p->n_type) == BOOL) { + if (p->n_op == SCONV && p->n_type == BOOL) { + /* create a jump and a set */ + P1ND *r; + int l, l2; + + r = tempnode(0, BOOL_TYPE, NULL, 0); + cbranch(buildtree(EQ, p->n_left, bcon(0)), + bcon(l = getlab())); + *p = *r; + ecode(buildtree(ASSIGN, p1tcopy(r), bcon(1))); + branch(l2 = getlab()); + plabel(l); + ecode(buildtree(ASSIGN, r, bcon(0))); + plabel(l2); + } else + p->n_type = (p->n_type & ~BTMASK) | BOOL_TYPE; + } + +} + +/* + * Change calls inside calls to separate statement. + */ +static P1ND * +deldcall(P1ND *p, int split) +{ + P1ND *q, *r; + int o = p->n_op; + + if (cdope(o) & CALLFLG) { + if (split) { + q = cstknode(p->n_type, p->n_df, p->n_ap); + r = p1tcopy(q); + q = block(ASSIGN, q, p, p->n_type, p->n_df, p->n_ap); + ecode(q); + return r; + } + split++; + } + if (coptype(o) == BITYPE) + p->n_right = deldcall(p->n_right, split); + if (coptype(o) != LTYPE) + p->n_left = deldcall(p->n_left, split); + return p; +} + +#ifndef WORD_ADDRESSED + +static P1ND * +pprop(P1ND *p, TWORD t, struct attr *ap) +{ + int o = p->n_op; + TWORD t2; + +#ifdef PCC_DEBUG + if (p->n_op == TEMP && p->n_type != t && + !(ISPTR(p->n_type) && ISPTR(t))) { + cerror("TEMP type change: %x -> %x", p->n_type, t); + } +#endif + + p->n_type = t; + p->n_ap = ap; + switch (o) { + case UMUL: + t = INCREF(t); + break; + case ADDROF: + t2 = p->n_left->n_type; + if (p->n_left->n_op == TEMP) { + /* Will be converted to memory in pass2 */ + /* Do not convert if: + * - t2 not ptr and decref(t) != t2 + * - decref(t) not ptr and decref(t) != t2 + * XXX add PCONV again? Will be removed upwards. + */ + if ((!ISPTR(t2) && DECREF(t) != t2) || + (ISPTR(t2) && !ISPTR(DECREF(t)))) + ; /* Cannot convert this */ + else + p->n_left->n_type = DECREF(t); + return p; + } + if (ISPTR(t2) && !ISPTR(DECREF(t))) + break; /* not quite correct */ + t = DECREF(t); + break; + case PCONV: + return p; + + case PLUS: + if (!ISPTR(p->n_left->n_type)) { + if (!ISPTR(p->n_right->n_type)) + cerror("%p: no * in PLUS", p); + p->n_right = pprop(p->n_right, t, ap); + } else + p->n_left = pprop(p->n_left, t, ap); + return p; + + case MINUS: + if (ISPTR(p->n_left->n_type)) { + if (ISPTR(p->n_right->n_type)) + break; /* change both */ + p->n_left = pprop(p->n_left, t, ap); + } else + p->n_right = pprop(p->n_right, t, ap); + return p; + + case CALL: + case UCALL: + case STCALL: /* may end up here if struct passed in regs */ + case USTCALL: + return p; + + case STASG: /* if struct is cast to pointer */ + return p; + + case ASSIGN: + break; + + case COMOP: + p->n_right = pprop(p->n_right, t, ap); + return p; + + default: + if (coptype(o) == LTYPE) + break; + +#ifdef PCC_DEBUG + p1fwalk(p, eprint, 0); +#endif + cerror("pprop op error %d\n", o); + } + if (coptype(o) == BITYPE) + p->n_right = pprop(p->n_right, t, ap); + if (coptype(o) != LTYPE) + p->n_left = pprop(p->n_left, t, ap); + return p; +} + +/* + * Search for PCONV's that can be removed while still keeping + * the type correctness. + */ +P1ND * +rmpconv(P1ND *p) +{ + struct symtab *sp; + int o = p->n_op; + int ot = coptype(o); + P1ND *q, *l; + + if (ot != LTYPE) + p->n_left = rmpconv(p->n_left); + if (ot == BITYPE) + p->n_right = rmpconv(p->n_right); + if (o != PCONV) + return p; + l = p->n_left; + if (nncon(l) || (cdope(l->n_op) & CALLFLG)) + ; /* Let any nonamed constant be cast to pointer directly */ + else if (l->n_type >= INTPTR && l->n_op == ICON) { + /* named constants only if >= pointer size */ + /* create INTPTR type */ + sp = l->n_sp; + l->n_sp = NULL; + concast(l, INTPTR); + l->n_sp = sp; + } else if (!ISPTR(l->n_type)) + return p; + q = pprop(p->n_left, p->n_type, p->n_ap); + p1nfree(p); + return q; +} +#endif + +P1ND * +optloop(P1ND *p) +{ + extern int usdnodes; + int n; + + do { + n = usdnodes; + p = rmpconv(p); + p = optim(p); + } while (n != usdnodes); + + return p; +} + +void +ecode(P1ND *p) +{ + NODE *r; + /* walk the tree and write out the nodes.. */ + + if (nerrors) + return; + +#ifdef GCC_COMPAT + { + P1ND *q = p; + + if (q->n_op == UMUL) + q = p->n_left; + if (cdope(q->n_op)&CALLFLG && + attr_find(q->n_ap, GCC_ATYP_WARN_UNUSED_RESULT)) + werror("return value ignored"); + } +#endif +#ifndef WORD_ADDRESSED + p = rmpconv(p); +#endif + p = optim(p); + p = deldcall(p, 0); + p1walkf(p, delvoid, 0); +#ifdef PCC_DEBUG + if (xdebug) { + printf("Fulltree:\n"); + p1fwalk(p, eprint, 0); + } +#endif + if (p->n_op == LABEL) { + plabel(glval(p->n_left)); + p1tfree(p); + return; + } + r = p2tree(p); + p1tfree(p); + send_passt(IP_NODE, r); +} + +/* + * Send something further on to the next pass. + */ +void +send_passt(int type, ...) +{ + struct interpass *ip; + struct interpass_prolog *ipp; + extern int crslab; + va_list ap; + int sz; + + va_start(ap, type); + if (cftnsp == NULL && type != IP_ASM) { +#ifdef notyet + cerror("no function"); +#endif + if (type == IP_NODE) + tfree(va_arg(ap, NODE *)); + return; + } + if (type == IP_PROLOG || type == IP_EPILOG) + sz = sizeof(struct interpass_prolog); + else + sz = sizeof(struct interpass); + + ip = xmalloc(sz); + ip->type = type; + ip->lineno = lineno; + switch (type) { + case IP_NODE: + ip->ip_node = va_arg(ap, NODE *); + break; + case IP_EPILOG: + if (!isinlining) { + locctr(PROG, cftnsp); + defloc(cftnsp); + } + /* FALLTHROUGH */ + case IP_PROLOG: + inftn = type == IP_PROLOG ? 1 : 0; + ipp = (struct interpass_prolog *)ip; + memset(ipp->ipp_regs, (type == IP_PROLOG)? -1 : 0, + sizeof(ipp->ipp_regs)); + ipp->ipp_autos = va_arg(ap, int); + ipp->ipp_name = va_arg(ap, char *); + ipp->ipp_type = va_arg(ap, TWORD); + ipp->ipp_vis = va_arg(ap, int); + ip->ip_lbl = va_arg(ap, int); + ipp->ip_tmpnum = va_arg(ap, int); + ipp->ip_lblnum = crslab; + ipp->ip_labels = va_arg(ap, int *);; + if (type == IP_PROLOG) + ipp->ip_lblnum-=2; + break; + case IP_DEFLAB: + ip->ip_lbl = va_arg(ap, int); + break; + case IP_ASM: + if (blevel == 0) { /* outside function */ + printf("%s", va_arg(ap, char *)); + va_end(ap); + locctr(NOSEG, NULL); + return; + } + ip->ip_asm = va_arg(ap, char *); + ip->ip_asm = tmpstrdup(ip->ip_asm); + break; + default: + cerror("bad send_passt type %d", type); + } + va_end(ap); + pass1_lastchance(ip); /* target-specific info */ + if (isinlining) + inline_addarg(ip); + else + pass2_compile(ip); +} + +char * +copst(int op) +{ + if (op <= MAXOP) + return opst[op]; +#define SNAM(x,y) case x: return #y; + switch (op) { + SNAM(QUALIFIER,QUALIFIER) + SNAM(CLASS,CLASS) + SNAM(RB,]) + SNAM(DOT,.) + SNAM(ELLIPSIS,...) + SNAM(LB,[) + SNAM(TYPE,TYPE) + SNAM(COMOP,COMOP) + SNAM(QUEST,?) + SNAM(BIQUEST,?:) + SNAM(COLON,:) + SNAM(ANDAND,&&) + SNAM(OROR,||) + SNAM(NOT,!) + SNAM(CAST,CAST) + SNAM(PLUSEQ,+=) + SNAM(MINUSEQ,-=) + SNAM(MULEQ,*=) + SNAM(DIVEQ,/=) + SNAM(MODEQ,%=) + SNAM(ANDEQ,&=) + SNAM(OREQ,|=) + SNAM(EREQ,^=) + SNAM(LSEQ,<<=) + SNAM(RSEQ,>>=) + SNAM(INCR,++) + SNAM(DECR,--) + SNAM(STRING,STRING) + SNAM(SZOF,SIZEOF) + SNAM(ATTRIB,ATTRIBUTE) + SNAM(TYMERGE,TYMERGE) + SNAM(LABEL,LABEL) + SNAM(UPLUS,U+) + SNAM(ALIGN,ALIGNMENT) + SNAM(FUNSPEC,FUNSPEC) + SNAM(STREF,->) +#ifdef GCC_COMPAT + SNAM(XREAL,__real__) + SNAM(XIMAG,__imag__) +#endif + default: + cerror("bad copst %d", op); + } + return 0; /* XXX gcc */ +} + +int +cdope(int op) +{ + if (op <= MAXOP) + return dope[op]; + switch (op) { + case CLOP: + case STRING: + case QUALIFIER: + case CLASS: + case RB: + case ELLIPSIS: + case TYPE: + case ALIGN: + case FUNSPEC: + return LTYPE; + case DOT: + case SZOF: + case COMOP: + case QUEST: + case BIQUEST: + case COLON: + case LB: + case TYMERGE: + case STREF: + return BITYPE; + case XIMAG: + case XREAL: + case ATTRIB: + case LABEL: + case UPLUS: + return UTYPE; + case ANDAND: + case OROR: + return BITYPE|LOGFLG; + case NOT: + return UTYPE|LOGFLG; + case CAST: + return BITYPE|ASGFLG|ASGOPFLG; + case PLUSEQ: + return BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG; + case MINUSEQ: + return BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG; + case MULEQ: + return BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG; + case OREQ: + case EREQ: + case ANDEQ: + return BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG; + case DIVEQ: + return BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG; + case MODEQ: + return BITYPE|DIVFLG|ASGFLG|ASGOPFLG; + case LSEQ: + case RSEQ: + return BITYPE|SHFFLG|ASGFLG|ASGOPFLG; + case INCR: + case DECR: + return BITYPE|ASGFLG; + } + cerror("cdope missing op %d", op); + return 0; /* XXX gcc */ +} + +/* + * make a fresh copy of p + */ +P1ND * +p1tcopy(P1ND *p) +{ + P1ND *q; + + q = p1alloc(); + *q = *p; + + switch (coptype(q->n_op)) { + case BITYPE: + q->n_right = p1tcopy(p->n_right); + /* FALLTHROUGH */ + case UTYPE: + q->n_left = p1tcopy(p->n_left); + } + + return(q); +} + +P1ND *frelink; +int usdnodes; +/* + * Free a node, and return its left descendant. + * It is up to the caller to know whether the return value is usable. + */ +P1ND * +p1nfree(P1ND *p) +{ + P1ND *l; +#ifdef PCC_DEBUG_NODES + P1ND *q; +#endif + + if (p == NULL) + cerror("freeing blank node!"); + + l = p->n_left; + if (p->n_op == FREE) + cerror("freeing FREE node", p); +#ifdef PCC_DEBUG_NODES + q = frelink; + while (q != NULL) { + if (q == p) + cerror("freeing free node %p", p); + q = q->n_left; + } +#endif + + if (ndebug) + printf("freeing p1node %p\n", p); + p->n_op = FREE; + p->n_left = frelink; + frelink = p; + usdnodes--; + return l; +} + +P1ND * +p1alloc(void) +{ + register P1ND *p; + + usdnodes++; + + if (frelink != NULL) { + p = frelink; + frelink = p->n_left; + if (p->n_op != FREE) + cerror("node not FREE: %p", p); + if (ndebug) + printf("alloc p1node %p from freelist\n", p); + return p; + } + + p = stmtalloc(sizeof(P1ND)); + p->n_op = FREE; + if (ndebug) + printf("alloc p1node %p from memory\n", p); + return p; +} + + +/* + * free the tree p + */ +void +p1tfree(P1ND *p) +{ +#ifdef PCC_DEBUG + if (p->n_op == FREE) + cerror("freeing FREE node"); +#endif + p1walkf(p, (void (*)(P1ND *, void *))p1nfree, 0); +} + +void +p1fwalk(P1ND *t, void (*f)(P1ND *, int, int *, int *), int down) +{ + + int down1, down2; + + more: + down1 = down2 = 0; + + (*f)(t, down, &down1, &down2); + + switch (coptype( t->n_op )) { + + case BITYPE: + p1fwalk( t->n_left, f, down1 ); + t = t->n_right; + down = down2; + goto more; + + case UTYPE: + t = t->n_left; + down = down1; + goto more; + + } +} + +void +p1walkf(P1ND *t, void (*f)(P1ND *, void *), void *arg) +{ + int opty; + + opty = coptype(t->n_op); + + if (opty != LTYPE) + p1walkf( t->n_left, f, arg ); + if (opty == BITYPE) + p1walkf( t->n_right, f, arg ); + (*f)(t, arg); +} + +/* + * Do a preorder walk of the CM list p and apply function f on each element. + */ +void +p1flist(P1ND *p, void (*f)(P1ND *, void *), void *arg) +{ + if (p->n_op == CM) { + (*f)(p->n_right, arg); + p1flist(p->n_left, f, arg); + } else + (*f)(p, arg); +} + +/* + * The same as flist but postorder. + */ +void +p1listf(P1ND *p, void (*f)(P1ND *)) +{ + if (p->n_op == CM) { + p1listf(p->n_left, f); + (*f)(p->n_right); + } else + (*f)(p); +} + +P1ND * +nlabel(int label) +{ + return block(LABEL, bcon(label), NULL, 0, 0, 0); +} + +/* + * set PROG-seg label. + */ +void +plabel(int label) +{ + reached = 1; /* Will this always be correct? */ + send_passt(IP_DEFLAB, label); +} + +/* + * Perform integer promotion on node n. + */ +P1ND * +intprom(P1ND *n) +{ + if (n->n_op == FLD && UPKFSZ(n->n_rval) < SZINT) + return makety(n, INT, 0, 0, 0); + + if ((n->n_type >= CHAR && n->n_type < INT) || n->n_type == BOOL) { + if ((n->n_type == UCHAR && MAX_UCHAR > MAX_INT) || + (n->n_type == USHORT && MAX_USHORT > MAX_INT)) + return makety(n, UNSIGNED, 0, 0, 0); + return makety(n, INT, 0, 0, 0); + } + return n; +} + +/* + * Return CON/VOL/0, whichever are active for the current type. + */ +int +cqual(TWORD t, TWORD q) +{ + while (ISARY(t)) + t = DECREF(t), q = DECQAL(q); + if (t <= BTMASK) + q <<= TSHIFT; + return q & (CON|VOL); +} + +int crslab = 11; +/* + * Return a number for internal labels. + */ +int +getlab(void) +{ + int l2 = crslab++; + crslab++; + return l2; +} diff --git a/lang/pcc/pcc/cc/cpp/Makefile.in b/lang/pcc/pcc/cc/cpp/Makefile.in new file mode 100644 index 000000000..7df86a5e1 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/Makefile.in @@ -0,0 +1,82 @@ +# $Id: Makefile.in,v 1.54 2016/03/08 18:42:13 ragge Exp $ +# +# Makefile.in for cpp +# +VPATH=@srcdir@ +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +builddir=@builddir@ +top_builddir=@top_builddir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +mandir = @mandir@ +CC = @CC@ +EXEEXT = @EXEEXT@ +CFLAGS = @CFLAGS@ @ADD_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ \ + -I$(srcdir) -I$(top_builddir) -I$(builddir) -I$(MIPDIR) -I$(MDIR) \ + -I$(COMMONDIR) +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +TARGMACH = @targmach@ + +MIPDIR=$(top_srcdir)/mip +MDIR=$(top_srcdir)/arch/$(TARGMACH) +COMMONDIR=$(top_srcdir)/common + +DEST=@BINPREFIX@cpp$(EXEEXT) +MANPAGE=@BINPREFIX@cpp + +all: $(DEST) + +OBJS= compat.o cpp.o cpc.o token.o +HDRS= cpp.h + +$(OBJS): $(HDRS) + +compat.o: $(COMMONDIR)/compat.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c + +cpp.o: $(srcdir)/cpp.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cpp.c + +cpc.o: $(srcdir)/cpc.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cpc.c + +token.o: $(srcdir)/token.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/token.c + +$(DEST): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) + +test: $(DEST) + @for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do \ + echo -n "test$${n} " ; \ + ./$(DEST) < tests/test$${n} > tests/run$${n} && \ + cmp tests/run$${n} tests/res$${n} && echo ; \ + if test -f tests/res$${n}C ; then \ + echo -n "test$${n}C " ; \ + ./$(DEST) -C < tests/test$${n} > tests/run$${n}C && \ + cmp tests/run$${n}C tests/res$${n}C && echo ; \ + fi ; \ + done + +install: + test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)" + $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir) + test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1" + $(INSTALL_DATA) $(srcdir)/cpp.1 $(DESTDIR)$(mandir)/man1/$(MANPAGE).1 + +clean: + rm -f $(OBJS) $(DEST) tests/run* + +distclean: clean + rm -f Makefile diff --git a/lang/pcc/pcc/cc/cpp/cpc.c b/lang/pcc/pcc/cc/cpp/cpc.c new file mode 100644 index 000000000..a1694829a --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/cpc.c @@ -0,0 +1,320 @@ +/* $Id: cpc.c,v 1.7 2016/01/10 16:17:45 ragge Exp $ */ + +/* + * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Small recursive parser for #if statements. + */ + +#include "cpp.h" + +static int ctok; + +typedef struct nd ND; +struct nd yynode; + +void qloop(void (*fun)(ND *), ND *n1, int a0, int a1, int a2, int a3); +void shft(void); +int yyparse(void); +void expr(ND *n1); +void eqcol(ND *n1); +void eoror(ND *n1); +void eandand(ND *n1); +void exor(ND *n1); +void eand(ND *n1); +void eqne(ND *n1); +void eget(ND *n1); +void elrs(ND *n1); +void eplmin(ND *n1); +void emdv(ND *n1); +void eterm(ND *n1); +void eval(int op, ND *n1, ND *n2); + + +void +shft(void) +{ + ctok = yylex(); +} + +int +yyparse(void) +{ + ND n1; + + shft(); + expr(&n1); + if (n1.op == 0) + error("division by zero"); + if (ctok != WARN) + error("junk after expression"); + return (int)n1.nd_val; +} + +/* + * evaluate a complete preprocessor #if expression. + */ +void +expr(ND *n1) +{ + for (;;) { + eqcol(n1); + if (ctok != ',') + return; + shft(); + } +} + +/* + * evaluate ?: conditionals. + */ +void +eqcol(ND *n1) +{ + ND n2, n3; + + eoror(n1); + if (ctok != '?') + return; + + shft(); + expr(&n2); + if (ctok != ':') + error("no : found"); + shft(); + eqcol(&n3); + if (n1->nd_val) + n1->nd_val = n2.nd_val, n1->op = n2.op; + else + n1->nd_val = n3.nd_val, n1->op = n3.op; +} + +void +eoror(ND *n1) +{ + qloop(eandand, n1, OROR, 0, 0, 0); +} + +void +eandand(ND *n1) +{ + qloop(exor, n1, ANDAND, 0, 0, 0); +} + +void +exor(ND *n1) +{ + qloop(eand, n1, '|', '^', 0, 0); +} + +void +eand(ND *n1) +{ + qloop(eqne, n1, '&', 0, 0, 0); +} + +void +eqne(ND *n1) +{ + qloop(eget, n1, EQ, NE, 0, 0); +} + +void +eget(ND *n1) +{ + qloop(elrs, n1, '<', '>', LE, GE); +} + +void +elrs(ND *n1) +{ + qloop(eplmin, n1, LS, RS, 0, 0); +} + +void +eplmin(ND *n1) +{ + qloop(emdv, n1, '+', '-', 0, 0); +} + +void +emdv(ND *n1) +{ + qloop(eterm, n1, '*', '/', '%', 0); +} + +/* + * Loop to evaluate all operators on the same precedence level. + */ +void +qloop(void (*fun)(ND *), ND *n1, int a0, int a1, int a2, int a3) +{ + ND n2; + int op; + + fun(n1); + while (ctok == a0 || ctok == a1 || ctok == a2 || ctok == a3) { + op = ctok; + shft(); + fun(&n2); + eval(op, n1, &n2); + } +} + +static void +gnum(int o, ND *n1) +{ + n1->op = yynode.op; + n1->nd_val = yynode.nd_val; + shft(); +} + +/* + * Highest precedence operators + numeric terminals. + */ +void +eterm(ND *n1) +{ + int o = ctok; + + switch (o) { + case '~': + case '!': + case '+': + case '-': + shft(); + eterm(n1); + eval(o, n1, 0); + break; + + case NUMBER: + case UNUMBER: + gnum(o, n1); + break; + + case '(': + shft(); + expr(n1); + if (ctok == ')') { + shft(); + break; + } + /* FALLTHROUGH */ + default: + error("bad terminal (%d)", o); + break; + } +} + +/* + * keep all numeric evaluation here. + * evaluated value returned in n1. + */ +void +eval(int op, ND *n1, ND *n2) +{ + + if ((op == '/' || op == '%') && n2->nd_val == 0) + n1->op = 0; + + if (n1->op == 0) + return; /* div by zero involved */ + + /* unary ops */ + if (n2 == 0) { + switch (op) { + case '+': break; + case '-': n1->nd_val = -n1->nd_val; break; + case '~': n1->nd_val = ~n1->nd_val; break; + case '!': n1->nd_val = !n1->nd_val; n1->op = NUMBER; break; + } + return; + } + + if (op == OROR && n1->nd_val) { + n1->nd_val = 1, n1->op = NUMBER; + return; + } + if (op == ANDAND && n1->nd_val == 0) { + n1->op = NUMBER; + return; + } + + if (n2->op == 0) { + n1->op = 0; + return; + } + + if (n2->op == UNUMBER) + n1->op = UNUMBER; + + switch (op) { + case OROR: + if (n2->nd_val) + n1->nd_val = 1; + n1->op = NUMBER; + break; + case ANDAND: + n1->nd_val = n2->nd_val != 0; + n1->op = NUMBER; + break; + case '+': n1->nd_val += n2->nd_val; break; + case '-': n1->nd_val -= n2->nd_val; break; + case '|': n1->nd_val |= n2->nd_val; break; + case '^': n1->nd_val ^= n2->nd_val; break; + case '&': n1->nd_val &= n2->nd_val; break; + case LS: n1->nd_val <<= n2->nd_val; break; + case EQ: n1->nd_val = n1->nd_val == n2->nd_val; n1->op = NUMBER; break; + case NE: n1->nd_val = n1->nd_val != n2->nd_val; n1->op = NUMBER; break; + } + + if (n1->op == NUMBER) { + switch (op) { + case '*': n1->nd_val *= n2->nd_val; break; + case '/': n1->nd_val /= n2->nd_val; break; + case '%': n1->nd_val %= n2->nd_val; break; + case '<': n1->nd_val = n1->nd_val < n2->nd_val; break; + case '>': n1->nd_val = n1->nd_val > n2->nd_val; break; + case LE: n1->nd_val = n1->nd_val <= n2->nd_val; break; + case GE: n1->nd_val = n1->nd_val >= n2->nd_val; break; + case RS: n1->nd_val >>= n2->nd_val; break; + } + return; + } else /* op == UNUMBER */ { + switch (op) { + case '*': n1->nd_uval *= n2->nd_uval; break; + case '/': n1->nd_uval /= n2->nd_uval; break; + case '%': n1->nd_uval %= n2->nd_uval; break; + case '<': n1->nd_uval = n1->nd_uval < n2->nd_uval; break; + case '>': n1->nd_uval = n1->nd_uval > n2->nd_uval; break; + case LE: n1->nd_uval = n1->nd_uval <= n2->nd_uval; break; + case GE: n1->nd_uval = n1->nd_uval >= n2->nd_uval; break; + case RS: n1->nd_uval >>= n2->nd_uval; break; + } + return; + } + error("unexpected arithmetic"); +} diff --git a/lang/pcc/pcc/cc/cpp/cpp.1 b/lang/pcc/pcc/cc/cpp/cpp.1 new file mode 100644 index 000000000..ea8b63a5d --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/cpp.1 @@ -0,0 +1,267 @@ +.\" $Id: cpp.1,v 1.17 2013/02/26 19:27:38 plunky Exp $ +.\" +.\" Copyright (c) 2007 Jeremy C. Reed +.\" +.\" Permission to use, copy, modify, and/or distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM +.\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND +.\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +.\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +.\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +.\" THIS SOFTWARE. +.\" +.Dd February 26, 2013 +.Dt CPP 1 +.Os +.Sh NAME +.Nm cpp +.Nd C preprocessor +.Sh SYNOPSIS +.Nm +.Op Fl ACEMPtVv +.Op Fl D Ar macro Ns Oo = Ns Ar value Oc +.Op Fl d Ar flags +.Op Fl I Ar path +.Op Fl i Ar file +.Op Fl S Ar path +.Op Fl U Ar macro +.Op Ar infile | - +.Op Ar outfile +.Sh DESCRIPTION +The +.Nm +utility is a macro preprocessor used by the +.Xr pcc 1 +compiler. +It is mainly used to include header files, +expand macro definitions, +discard comments, +and perform conditional compilation. +.Nm +is written to comply with the +.St -isoC-99 +specification. +.Pp +The +.Ar infile +input file is optional. +If not provided or the file name is +.Qq - +(dash), +.Nm +reads its initial file from standard input. +The +.Ar outfile +output file is also optional, with output written to standard +output if not provided. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl A +For assembler-with-cpp input: treat non-directive lines starting +with a # as comments. +.It Fl C +Do not discard comments. +.It Fl D Ar macro Ns Oo = Ns Ar value Oc +Create a macro definition before processing any input, as if a +.Lp +.Dl #define Ar macro Ar value +.Lp +directive had appeared in the source. +If +.Ar value +is not set on the command-line, then a value of 1 is used. +.It Fl d Ar flags +Modify output according to +.Ar flags , +which can be a list of character flags. +The following flags are currently supported: +.Bl -tag -width ".Sy M" +.It Sy M +Do not process any input, but output a list of +.Dq #define +statements for all defined macros other than builtin macros +.Pq see below . +.El +.Lp +any unknown flags are ignored. +.It Fl E +Modify the exit code, if there were any warnings. +.It Fl I Ar path +Add +.Ar path +to the list of directories searched by the +.Dq #include +directive. +This may be used to override system include directories +.Pq see Fl S No option . +.Fl I +may be specified multiple times and is cumulative. +.It Fl i Ar file +Include a file before processing any input, as if a +.Lp +.Dl #include Qo Ar file Qc +.Lp +directive had appeared in the source. +.Fl i +may be specified multiple times to include several files. +.It Fl M +Instead of producing a processed C code file, output a list +of dependencies for +.Xr make 1 , +detailing the files that need to be processed when compiling +the input. +.It Fl P +Inhibit generation of line markers. This is sometimes useful when +running the preprocessor on something other than C code. +.It Fl S Ar path +Add +.Ar path +to the list of system directories searched by the +.Dq #include +directive. +The +.Fl S +option may be specified multiple times and is cumulative. +.It Fl t +Traditional cpp syntax. +Do not define the +.Dv __TIME__ , +.Dv __DATE__ , +.Dv __STDC__ , +and +.Dv __STDC_VERSION__ +macros. +.It Fl U Ar macro +Undefine a macro before processing any input, as if a +.Lp +.Dl #undef Ar macro +.Lp +directive had appeared in the source. +.It Fl V +Verbose debugging output. +.Fl V +can be repeated for greater detail. +.Po +This is only available if the +.Nm +program was built with +.Dv PCC_DEBUG +defined, which is the default +.Pc . +.It Fl v +Display version. +.El +.Pp +The +.Fl D , +.Fl i +and +.Fl U +options are processed in the order that they appear on the command +line, before any input is read but after the command line options +have been scanned. +.Pp +Files referenced by the +.Dq #include +directive as +.Qq ... , +are first looked for in the current directory, then as per +.Aq ... +files, which are first looked for in the list of +directories provided by any +.Fl I +options, then in the list of system directories provided by any +.Fl S +options. +Note that +.Nm +does not define any include directories by default; if no +.Fl I +or +.Fl S +options are given, then only the current directory will be +searched and no system files will be found. +.Ss Builtin Macros +A few macros are interpreted inside the +.Nm cpp +program: +.Bl -diag +.It __DATE__ +Expands to a quoted string literal containing the date in the form +.Qq Mmm dd yyyy , +where the names of the months are the same as those generated by the +.Xr asctime 3 +function, and the first character of dd is a space character if +the value is less than 10. +.It __FILE__ +Expands to a quoted string literal containing the presumed name of +the current source file. +When reading source from standard input, it expands to +.Qq Aq stdin . +.It __LINE__ +Expands to an integer constant representing the presumed line number +of the source line containing the macro. +.It __STDC__ +Expands to the integer constant +.Dq 1 , +meaning that the compiler conforms to +.St -isoC . +.It __STDC_VERSION__ +Expands to the integer constant +.Dq 199901L , +indicating that +.Nm +conforms to +.St -isoC-99 . +.It __TIME__ +Expands to a quoted string literal containing the time in the form +.Qq hh:mm:ss +as generated by the +.Xr asctime 3 +function. +.El +.Pp +Also see the +.Fl t +option. +.Sh EXIT STATUS +The +.Nm +utility exits with one of the following values: +.Lp +.Bl -tag -width Ds -offset indent -compact +.It 0 +Successfully finished. +.It 1 +An error occurred. +.It 2 +The +.Fl E +option was given, and warnings were issued. +.El +.Sh SEE ALSO +.Xr as 1 , +.Xr ccom 1 , +.Xr make 1 , +.Xr pcc 1 , +.Xr asctime 3 +.Sh HISTORY +The +.Nm +command comes from the original Portable C Compiler by +.An "S. C. Johnson" , +written in the late 70's. +The code originates from the V6 preprocessor with some additions +from V7 cpp and ansi/c99 support. +.Pp +A lot of the PCC code was rewritten by +.An "Anders Magnusson" . +.Pp +This product includes software developed or owned by Caldera +International, Inc. diff --git a/lang/pcc/pcc/cc/cpp/cpp.c b/lang/pcc/pcc/cc/cpp/cpp.c new file mode 100644 index 000000000..05e4d3799 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/cpp.c @@ -0,0 +1,2598 @@ +/* $Id: cpp.c,v 1.258 2016/03/14 20:27:56 ragge Exp $ */ + +/* + * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * The C preprocessor. + * This code originates from the V6 preprocessor with some additions + * from V7 cpp, and at last ansi/c99 support. + * + * - kfind() expands the input buffer onto an output buffer. + * - exparg() expand one buffer into another. + * Recurses into submac() for fun-like macros. + * - submac() replaces the given macro. + * Recurses into subarg() for fun-like macros. + * - subarg() expands fun-like macros. + * Create strings, concats args, recurses into exparg. + */ + +#include "config.h" + +#include + +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include + +#include "compat.h" +#include "cpp.h" + +#ifndef S_ISDIR +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#endif + +/* + * Buffers used: + * - expansion buffers (via getobuf etc...) + * - string buffers (used to store macros) + * - tree buffers (used by macro search algorithm) + * - scratch buffer (identifier readin) + */ + + + + +#define SBSIZE 1000000 + +static usch sbf[SBSIZE]; +static int counter; +/* C command */ + +int tflag; /* traditional cpp syntax */ +#ifdef PCC_DEBUG +int dflag; /* debug printouts */ +//static void imp(const char *); +static void prline(const usch *s); +static void prrep(const usch *s); +#define DPRINT(x) if (dflag) printf x +#define DDPRINT(x) if (dflag > 1) printf x +#define IMP(x) if (dflag > 1) imp(x) +#else +#define DPRINT(x) +#define DDPRINT(x) +#define IMP(x) +#endif + +int Aflag, Cflag, Eflag, Mflag, dMflag, Pflag, MPflag, MMDflag; +char *Mfile, *MPfile; +struct initar *initar; +char *Mxfile; +int warnings, Mxlen; +FILE *of; + +/* include dirs */ +struct incs { + struct incs *next; + usch *dir; + dev_t dev; + ino_t ino; +} *incdir[2]; + +static struct symtab *filloc; +static struct symtab *linloc; +static struct symtab *pragloc; +static struct symtab *defloc; +static struct symtab *ctrloc; +int trulvl; +int flslvl; +int elflvl; +int elslvl; +usch *stringbuf = sbf; + +/* + * Macro replacement list syntax: + * - For object-type macros, replacement strings are stored as-is. + * - For function-type macros, macro args are substituted for the + * character WARN followed by the argument number. + * - The value element points to the beginning of the string. + * + * The first character in the replacement list is the number of arguments: + * VARG - ends with ellipsis, next char is argcount without ellips. + * OBJCT - object-type macro + * 0 - empty parenthesis, foo() + * 1-> - number of args. + * + * WARN is used: + * - in stored replacement lists to tell that an argument comes + * - When expanding replacement lists to tell that the list ended. + * + * To ensure that an already expanded identifier won't get expanded + * again a EBLOCK char + its number is stored directly before any + * expanded identifier. + */ + +/* args for lookup() */ +#define FIND 0 +#define ENTER 1 + +/* + * No-replacement array. If a macro is found and exists in this array + * then no replacement shall occur. + */ +struct blocker { + struct blocker *next; + struct symtab *sp; +}; +struct blocker *blkidx[RECMAX]; +int blkidp; + +static struct iobuf *readargs2(usch **, struct symtab *sp, const usch **args); +static int readargs1(struct symtab *sp, const usch **args); +static struct iobuf *exparg(int, struct iobuf *, struct iobuf *, struct blocker *); +static struct iobuf *subarg(struct symtab *sp, const usch **args, int, struct blocker *); +static void usage(void); +static usch *xstrdup(const usch *str); +static void addidir(char *idir, struct incs **ww); +static void vsheap(struct iobuf *, const char *, va_list); +static int skipws(struct iobuf *ib); +static int getyp(usch *s); + +usch locs[] = + { FILLOC, LINLOC, PRAGLOC, DEFLOC, + 'd','e','f','i','n','e','d',0, CTRLOC }; + +int +main(int argc, char **argv) +{ + struct initar *it; + register int ch; + const usch *fn1, *fn2; + +#ifdef TIMING + struct timeval t1, t2; + + (void)gettimeofday(&t1, NULL); +#endif + + while ((ch = getopt(argc, argv, "ACD:d:EI:i:MPS:tU:Vvx:")) != -1) { + switch (ch) { + case 'A': /* assembler input */ + Aflag++; + break; + + case 'C': /* Do not discard comments */ + Cflag++; + break; + + case 'E': /* treat warnings as errors */ + Eflag++; + break; + + case 'D': /* define something */ + case 'i': /* include */ + case 'U': /* undef */ + /* XXX should not need malloc() here */ + if ((it = xmalloc(sizeof(struct initar))) == NULL) + error("couldn't apply -%c %s", ch, optarg); + it->type = ch; + it->str = optarg; + it->next = initar; + initar = it; + break; + + case 'd': + while (*optarg) { + switch(*optarg) { + case 'M': /* display macro definitions */ + dMflag = 1; + Mflag = 1; + break; + + default: /* ignore others */ + break; + } + optarg++; + } + break; + + case 'I': + case 'S': + addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]); + break; + + case 'M': /* Generate dependencies for make */ + Mflag++; + break; + + case 'P': /* Inhibit generation of line numbers */ + Pflag++; + break; + + case 't': + tflag = 1; + break; + +#ifdef PCC_DEBUG + case 'V': + dflag++; + break; +#endif + case 'v': + fprintf(stderr, "PCC preprocessor version "VERSSTR"\n"); + break; + + case 'x': + if (strcmp(optarg, "MMD") == 0) { + MMDflag++; + } else if (strcmp(optarg, "MP") == 0) { + MPflag++; + } else if (strncmp(optarg, "MT,", 3) == 0 || + strncmp(optarg, "MQ,", 3) == 0) { + int l = strlen(optarg+3) + 2; + char *cp, *up; + + if (optarg[1] == 'Q') + for (cp = optarg+3; *cp; cp++) + if (*cp == '$') + l++; + Mxlen += l; + Mxfile = cp = realloc(Mxfile, Mxlen); + for (up = Mxfile; *up; up++) + ; + if (up != Mxfile) + *up++ = ' '; + for (cp = optarg+3; *cp; cp++) { + *up++ = *cp; + if (optarg[1] == 'Q' && *cp == '$') + *up++ = *cp; + } + *up = 0; + } else + usage(); + break; + + case '?': + default: + usage(); + } + } + + argc -= optind; + argv += optind; + + filloc = lookup((const usch *)"__FILE__", ENTER); + linloc = lookup((const usch *)"__LINE__", ENTER); + pragloc = lookup((const usch *)"_Pragma", ENTER); + defloc = lookup((const usch *)"defined", ENTER); + ctrloc = lookup((const usch *)"__COUNTER__", ENTER); + filloc->value = locs; + linloc->value = locs+1; + pragloc->value = locs+2; + defloc->value = locs+3; /* also have macro name here */ + ctrloc->value = locs+12; + + if (Mflag && !dMflag) { + char *c; + + if (argc < 1) + error("-M and no infile"); + if ((c = strrchr(argv[0], '/')) == NULL) + c = argv[0]; + else + c++; + Mfile = (char *)xstrdup((usch *)c); + if (MPflag) + MPfile = (char *)xstrdup((usch *)c); + if (Mxfile) + Mfile = Mxfile; + if ((c = strrchr(Mfile, '.')) == NULL) + error("-M and no extension: "); + c[1] = 'o'; + c[2] = 0; + } + + if (argc == 2) { + if ((of = freopen(argv[1], "w", stdout)) == NULL) + error("Can't creat %s", argv[1]); + } else + of = stdout; + + if (argc && strcmp(argv[0], "-")) { + fn1 = fn2 = (usch *)argv[0]; + } else { + fn1 = NULL; + fn2 = (const usch *)""; + } + if (pushfile(fn1, fn2, 0, NULL)) + error("cannot open %s", argv[0]); + + fclose(of); +#ifdef TIMING + (void)gettimeofday(&t2, NULL); + t2.tv_sec -= t1.tv_sec; + t2.tv_usec -= t1.tv_usec; + if (t2.tv_usec < 0) { + t2.tv_usec += 1000000; + t2.tv_sec -= 1; + } + fprintf(stderr, "cpp total time: %ld s %ld us\n", + (long)t2.tv_sec, (long)t2.tv_usec); +#endif + if (Eflag && warnings > 0) + return 2; + + return 0; +} + +/* + * Write a character to an out buffer. + */ +void +putob(struct iobuf *ob, int ch) +{ + if (ob->cptr == ob->bsz) { + int sz = ob->bsz - ob->buf; + ob->buf = xrealloc(ob->buf, sz + BUFSIZ); + ob->cptr = ob->buf + sz; + ob->bsz = ob->buf + sz + BUFSIZ; + } +// DDPRINT(("putob: iob %p pos %p ch %c (%d)\n", ob, ob->cptr, ch, ch)); + *ob->cptr++ = ch; +} + +static int nbufused; +/* + * Write a character to an out buffer. + */ +struct iobuf * +getobuf(void) +{ + struct iobuf *iob = xmalloc(sizeof(struct iobuf)); + + nbufused++; + iob->buf = iob->cptr = xmalloc(BUFSIZ); + iob->bsz = iob->buf + BUFSIZ; + iob->ro = 0; + return iob; +} + +/* + * Create a read-only input buffer. + */ +static struct iobuf * +mkrobuf(const usch *s) +{ + struct iobuf *iob = xmalloc(sizeof(struct iobuf)); + + nbufused++; + DPRINT(("mkrobuf %s\n", s)); + iob->buf = iob->cptr = (usch *)s; + iob->bsz = iob->buf + strlen((char *)iob->buf); + iob->ro = 1; + return iob; +} + +/* + * Copy a string to a buffer. + */ +static struct iobuf * +strtobuf(usch *str, struct iobuf *iob) +{ + DPRINT(("strtobuf iob %p buf %p str %s\n", iob, iob->buf, str)); + if (iob == NULL) + iob = getobuf(); + do { + putob(iob, *str); + } while (*str++); + iob->cptr--; + return iob; +} + +static usch *macbase; +static int macpos, cmbase; + +static void +macsav(int ch) +{ + if (macbase == NULL) + macbase = xmalloc(CPPBUF); + if (macpos == CPPBUF) { + usch *tb; + if (cmbase == 0) + error("macro too large"); + tb = xmalloc(CPPBUF); + memcpy(tb, macbase+cmbase, CPPBUF-cmbase); + xrealloc(macbase, cmbase); + macpos -= cmbase; + cmbase = 0; + macbase = tb; + } + macbase[macpos++] = ch; +} + +static void +macstr(const usch *s) +{ + do { + macsav(*s); + } while (*s++ != 0); + macpos--; +} + +#define setcmbase() cmbase = macpos +#define clrcmbase() macpos = cmbase + +void +bufree(struct iobuf *iob) +{ + nbufused--; + if (iob->ro == 0) + free(iob->buf); + free(iob); +} + +static void +addidir(char *idir, struct incs **ww) +{ + struct incs *w; + struct stat st; + + if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode)) + return; /* ignore */ + if (*ww != NULL) { + for (w = *ww; w->next; w = w->next) { +#ifdef _WIN32 + if (strcmp(w->dir, idir) == 0) + return; +#else + if (w->dev == st.st_dev && w->ino == st.st_ino) + return; +#endif + } +#ifdef _WIN32 + if (strcmp(w->dir, idir) == 0) + return; +#else + if (w->dev == st.st_dev && w->ino == st.st_ino) + return; +#endif + ww = &w->next; + } + if ((w = calloc(sizeof(struct incs), 1)) == NULL) + error("couldn't add path %s", idir); + w->dir = (usch *)idir; + w->dev = st.st_dev; + w->ino = st.st_ino; + *ww = w; +} + +void +line(void) +{ + struct iobuf *ob; + struct symtab *nl; + int c, n, ln; + usch *cp, *dp; + + c = skipws(0); + if (ISID0(c)) { /* expand macro */ + dp = readid(c); + if ((nl = lookup(dp, FIND)) == 0 || (ob = kfind(nl)) == 0) + goto bad; + } else { + ob = getobuf(); + do { + putob(ob, c); + } while (ISDIGIT(c = cinput())); + cunput(c); + putob(ob, 0); + } + cp = ob->buf; + + n = 0; + while (ISDIGIT(*cp)) + n = n * 10 + *cp++ - '0'; + if (*cp != 0) + goto bad; + bufree(ob); + + /* Can only be decimal number here between 1-2147483647 */ + if (n < 1 || n > 2147483647) + goto bad; + + ln = n; + ifiles->escln = 0; + if ((c = skipws(NULL)) != '\n') { + if (c == 'L' || c == 'U' || c == 'u') { + n = c, c = cinput(); + if (n == 'u' && c == '8') + c = cinput(); + if (c == '\"') + warning("#line only allows character literals"); + } + if (c != '\"') + goto bad; + + setcmbase(); + ifiles->fname = macbase+1; + faststr(c, macsav); + macbase[--macpos] = 0; + if (strcmp((char *)ifiles->fname, (char *)macbase+cmbase+1)) + ifiles->fname = xstrdup(macbase+cmbase+1); + clrcmbase(); + + c = skipws(0); + } + if (c != '\n') + goto bad; + + ifiles->lineno = ln; + prtline(1); + ifiles->lineno--; + cunput('\n'); + return; + +bad: error("bad #line"); +} + +#ifdef MACHOABI + +/* + * Search for framework header file. + * Return 1 on success. + */ + +static int +fsrch_macos_framework(const usch *fn, const usch *dir) +{ + usch *saved_stringbuf = stringbuf; + usch *s = (usch *)strchr((const char*)fn, '/'); + usch *nm; + usch *p; + int len = s - fn; + + if (s == NULL) + return 0; + +// fprintf(stderr, "searching for %s in %s\n", (const char *)fn, (const char *)dir); + + nm = savstr(dir); + savch(0); + p = savstr(fn); + stringbuf = p + len; + savch(0); +// fprintf(stderr, "comparing \"%s\" against \"%.*s\"\n", nm, len, fn); + p = (usch *)strstr((const char *)nm, (const char *)p); +// fprintf(stderr, "p = %s\n", (const char *)p); + if (p != NULL) { + stringbuf = p; + savch(0); + return fsrch_macos_framework(fn, nm); + } + + p = nm + strlen((char *)nm) - 1; + while (*p == '/') + p--; + while (*p != '/') + p--; + stringbuf = ++p; + savstr((const usch *)"Frameworks/"); + stringbuf = savstr(fn) + len; + savstr((const usch*)".framework/Headers"); + savstr(s); + savch(0); + +// fprintf(stderr, "nm: %s\n", nm); + + if (pushfile(nm, fn, SYSINC, NULL) == 0) + return 1; +// fprintf(stderr, "not found %s, continuing...\n", nm); + + stringbuf = saved_stringbuf; + + return 0; +} + +#endif + +/* + * Search for and include next file. + * Return 1 on success. + */ +static int +fsrch(const usch *fn, int idx, struct incs *w) +{ + int i; + + setcmbase(); + for (i = idx; i < 2; i++) { + if (i > idx) + w = incdir[i]; + for (; w; w = w->next) { + macstr(w->dir); macsav('/'); + macstr(fn); macsav(0); + if (pushfile(macbase+cmbase, fn, i, w->next) == 0) + return 1; + clrcmbase(); + } + } + +#ifdef MACHOABI + /* + * On MacOS, we may have to do some clever stuff + * to resolve framework headers. + */ + { + usch *dir = stringbuf; + savstr(ifiles->orgfn); + stringbuf = (usch *)strrchr((char *)dir, '/'); + if (stringbuf != NULL) { + stringbuf++; + savch(0); + if (fsrch_macos_framework(fn, dir) == 1) + return 1; + } + stringbuf = dir; + + if (fsrch_macos_framework(fn, (const usch *)"/Library/Frameworks/") == 1) + return 1; + + if (fsrch_macos_framework(fn, (const usch *)"/System/Library/Frameworks/") == 1) + return 1; + } +#endif + + return 0; +} + +static void +prem(void) +{ + error("premature EOF"); +} + +static struct iobuf * +incfn(void) +{ + struct iobuf *ob; + struct symtab *nl; + usch *dp; + int c; + + if (spechr[c = skipws(NULL)] & C_ID0) { + dp = readid(c); + if ((nl = lookup(dp, FIND)) == NULL) + return NULL; + + if ((ob = kfind(nl)) == 0) + return NULL; + } else { + ob = getobuf(); + putob(ob, c); + while ((c = cinput()) && c != '\n') + putob(ob, c); + if (c != '\n') + return NULL; + cunput(c); + } + + /* now we have an (expanded?) filename in obuf */ + while (ob->buf < ob->cptr && ISWS(ob->cptr[-1])) + ob->cptr--; + + if (ob->buf[0] != '\"' && ob->buf[0] != '<') + return NULL; + if (ob->cptr[-1] != '\"' && ob->cptr[-1] != '>') + return NULL; + ob->cptr[-1] = 0; + return ob; +} + +/* + * Include a file. Include order: + * - For <...> files, first search -I directories, then system directories. + * - For "..." files, first search "current" dir, then as <...> files. + */ +void +include(void) +{ + struct iobuf *ob; + usch *fn, *nm = NULL; + + if (flslvl) + return; + + if ((ob = incfn()) == NULL) /* get include file name in obuf */ + error("bad #include"); + + fn = xstrdup(ob->buf) + 1; /* Save on string heap? */ + bufree(ob); + /* test absolute path first */ + if (fn[0] == '/' && pushfile(fn, fn, 0, NULL) == 0) + goto okret; + if (fn[-1] == '\"') { + /* nope, failed, try to create a path for it */ + if ((nm = (usch *)strrchr((char *)ifiles->orgfn, '/'))) { + ob = strtobuf((usch *)ifiles->orgfn, NULL); + ob->cptr = ob->buf + (nm - ifiles->orgfn) + 1; + strtobuf(fn, ob); + putob(ob, 0); + nm = xstrdup(ob->buf); + bufree(ob); + } else { + nm = xstrdup(fn); + } + if (pushfile(nm, nm, 0, NULL) == 0) { + free(fn-1); + goto okret; + } + } + if (fsrch(fn, 0, incdir[0])) + goto okret; + + error("cannot find '%s'", fn); + /* error() do not return */ + +okret: + if (nm) + free(nm); + prtline(1); +} + +void +include_next(void) +{ + struct iobuf *ob; + usch *nm; + + if (flslvl) + return; + + if ((ob = incfn()) == NULL) /* get include file name in obuf */ + error("bad #include_next"); + + nm = xstrdup(ob->buf+1); + bufree(ob); + + if (fsrch(nm, ifiles->idx, ifiles->incs) == 0) + error("cannot find '%s'", nm); + prtline(1); +} + +/* + * Compare two replacement lists, taking in account comments etc. + */ +static int +cmprepl(const usch *o, const usch *n) +{ + for (; *o; o++, n++) { + /* comment skip */ + if (*o == '/' && o[1] == '*') { + while (*o != '*' || o[1] != '/') + o++; + o += 2; + } + if (*n == '/' && n[1] == '*') { + while (*n != '*' || n[1] != '/') + n++; + n += 2; + } + while (*o == ' ' || *o == '\t') + o++; + while (*n == ' ' || *n == '\t') + n++; + if (*o != *n) + return 1; + } + return 0; +} + +static int +isell(void) +{ + if (cinput() != '.' || cinput() != '.') + return 0; + return 1; +} + +static int +skipwscmnt(struct iobuf *ib) +{ + /* XXX comment */ + return skipws(ib); +} + +static int +findarg(usch *s, usch **args, int narg) +{ + int i; + + for (i = 0; i < narg; i++) + if (strcmp((char *)s, (char *)args[i]) == 0) + return i; + return -1; +} + +/* + * gcc extensions: + * #define e(a...) f(s, a) -> a works as __VA_ARGS__ + * #define e(fmt, ...) f(s, fmt , ##__VA_ARGS__) -> remove , if no args + */ +void +define(void) +{ + struct symtab *np; + usch *args[MAXARGS+1], cc[2], *vararg, *dp; + int c, i, redef, oCflag, t; + int narg = -1; + int wascon; + + if (flslvl) + return; + + oCflag = Cflag, Cflag = 0; /* Ignore comments here */ + if (!ISID0(c = skipws(0))) + goto bad; + + setcmbase(); + dp = readid(c); + np = lookup(dp, ENTER); + if (np->value) { + redef = 1; + } else { + np->namep = xstrdup(dp); + redef = 0; + } + + vararg = NULL; + macsav(0); /* set type slot */ + if ((c = cinput()) == '(') { + narg = 0; + /* function-like macros, deal with identifiers */ + c = skipws(0); + for (;;) { + switch (c) { + case ')': + break; + case '.': + if (isell() == 0 || (c = skipws(0)) != ')') + goto bad; + vararg = (usch *)"__VA_ARGS__"; + break; + default: + if (!ISID0(c)) + goto bad; + + dp = readid(c); + /* make sure there is no arg of same name */ + if (findarg(dp, args, narg) >= 0) + error("Duplicate parameter \"%s\"", dp); + if (narg == MAXARGS) + error("Too many macro args"); + args[narg++] = xstrdup(dp); + switch ((c = skipws(0))) { + case ',': break; + case ')': continue; + case '.': + if (isell() == 0 || skipws(0) != ')') + goto bad; + vararg = args[--narg]; + c = ')'; + continue; + default: + goto bad; + } + c = skipws(0); + } + if (c == ')') + break; + } + c = skipws(0); + } else if (c == '\n') { + /* #define foo */ + ; + } else if (c == 0) { + prem(); + } else if (!ISWS(c)) + goto bad; + + Cflag = oCflag; /* Enable comments again */ + + if (vararg) + macsav(0); /* for macro type */ + + if (ISWS(c)) + c = skipwscmnt(0); + +#define DELEWS() while (macpos > cmbase+1+(vararg!=NULL) && \ + ISWS(macbase[macpos-1])) macpos-- + + /* parse replacement-list, substituting arguments */ + wascon = 0; + while (c != '\n') { + cc[0] = c, cc[1] = inc2(); + t = getyp(cc); + cunput(cc[1]); + + switch (t) { + case ' ': + case '\t': + macsav(' '); /* save only one space */ + while ((c = cinput()) == ' ' || c == '\t') + ; + continue; + + case '#': + if (cc[1] == '#') { + /* concat op */ + (void)cinput(); /* eat # */ + DELEWS(); + macsav(CONC); + if (ISID0(c = skipws(0)) && narg >= 0) + wascon = 1; + if (c == '\n') + goto bad; /* 6.10.3.3 p1 */ + continue; + } + + if (narg < 0) { + /* no meaning in object-type macro */ + macsav('#'); + break; + } + + /* remove spaces between # and arg */ + macsav(SNUFF); + c = skipws(0); /* whitespace, ignore */ + if (!ISID0(c)) + goto bad; + dp = readid(c); + if (vararg && strcmp((char *)dp, (char *)vararg) == 0) { + macsav(WARN); + macsav(VARG); + macsav(SNUFF); + break; + + } + if ((i = findarg(dp, args, narg)) < 0) + goto bad; + macsav(WARN); + macsav(i); + macsav(SNUFF); + break; + + case NUMBER: + c = fastnum(c, macsav); + continue; + + case STRING: + if (c == 'L' || c == 'u' || c == 'U') { + macsav(c); + if ((c = cinput()) == '8') { + macsav(c); + c = cinput(); + } + } + if (tflag) + macsav(c); + else + faststr(c, macsav); + break; + + case IDENT: + dp = readid(c); + if (narg < 0) { + macstr(dp); + break; /* keep on heap */ + } + if (vararg && strcmp((char *)dp, (char *)vararg) == 0) { + macsav(WARN); + macsav(wascon ? GCCARG : VARG); + break; + } + + /* check if its an argument */ + if ((i = findarg(dp, args, narg)) < 0) { + macstr(dp); + break; + } + macsav(WARN); + macsav(i); + break; + + case 0: + goto bad; + + default: + macsav(c); + break; + } + wascon = 0; + c = cinput(); + } + cunput(c); + /* remove trailing whitespace */ + DELEWS(); + + if (macbase[cmbase+1+(vararg != 0)] == CONC) + goto bad; /* 6.10.3.3 p1 */ + + if (vararg) { + macbase[cmbase] = VARG; + macbase[cmbase+1] = narg; + } else + macbase[cmbase] = (narg < 0 ? OBJCT : narg); + macsav(0); + + if (redef && ifiles->idx != SYSINC) { + if (cmprepl(np->value, macbase+cmbase)) { /* not equal */ + np->value = macbase+cmbase; + warning("%s redefined (previously defined at \"%s\" line %d)", + np->namep, np->file, np->line); + } else + macpos = cmbase; /* forget this space */ + } else + np->value = macbase+cmbase; + +#ifdef PCC_DEBUG + if (dflag) { + const usch *w = np->value; + + printf("!define %s: ", np->namep); + if (*w == OBJCT) + printf("[object]"); + else if (*w == VARG) + printf("[VARG%d]", *++w); + else + printf("[%d]", *w); + putchar('\''); + prrep(++w); + printf("\'\n"); + } +#endif + for (i = 0; i < narg; i++) + free(args[i]); + return; + +bad: error("bad #define"); +} + +void +warning(const char *fmt, ...) +{ + va_list ap; + + if (ifiles != NULL) + fprintf(stderr, "%s:%d: warning: ", + ifiles->fname, ifiles->lineno); + + va_start(ap,fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); + + warnings++; +} + +void +error(const char *fmt, ...) +{ + va_list ap; + + if (ifiles != NULL) + fprintf(stderr, "%s:%d: error: ", + ifiles->fname, ifiles->lineno); + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); + exit(1); +} + +/* + * store a character into the "define" buffer. + */ +void +savch(int c) +{ + if (stringbuf >= &sbf[SBSIZE]) + error("out of macro space!"); + + *stringbuf++ = (usch)c; +} + +static int +pragwin(struct iobuf *ib) +{ + return ib ? *ib->cptr++ : cinput(); +} + +static int +skipws(struct iobuf *ib) +{ + int t; + + while ((t = pragwin(ib)) == ' ' || t == '\t') + ; + return t; +} + +/* + * convert _Pragma() to #pragma for output. + * Syntax is already correct. + */ +static void +pragoper(struct iobuf *ib) +{ + int t; + struct iobuf *ob = getobuf(); + + if (skipws(ib) != '(' || ((t = skipws(ib)) != '\"' && t != 'L')) + goto err; + if (t == 'L' && (t = pragwin(ib)) != '\"') + goto err; + strtobuf((usch *)"\n#pragma ", ob); + while ((t = pragwin(ib)) != '\"') { + if (t == BLKID) { + pragwin(ib); + continue; + } + if (t == '\"') + continue; + if (t == '\\') { + if ((t = pragwin(ib)) != '\"' && t != '\\') + putob(ob, '\\'); + } + putob(ob, t); + } + bsheap(ob, "\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname); + putstr(ob->buf); + bufree(ob); + if (skipws(ib) == ')') + return; + +err: error("_Pragma() syntax error"); +} + +static int +expok(struct symtab *sp, int l) +{ + struct blocker *w; + + if (l == 0) + return 1; +#ifdef PCC_DEBUG +if (dflag) { printf("expok blocked: "); for (w = blkidx[l]; w; w = w->next) printf("%s ", w->sp->namep); printf("\n"); } +#endif + w = blkidx[l]; + while (w) { + if (w->sp == sp) + return 0; + w = w->next; + } + return 1; +} + +static int +expokb(struct symtab *sp, struct blocker *bl) +{ + struct blocker *w; + + if (bl == 0) + return 1; +#ifdef PCC_DEBUG +if (dflag) { printf("expokb blocked: "); for (w = bl; w; w = w->next) printf("%s ", w->sp->namep); printf("\n"); } +#endif + w = bl; + while (w) { + if (w->sp == sp) + return 0; + w = w->next; + } + return 1; +} + +static struct blocker * +blkget(struct symtab *sp, struct blocker *obl) +{ + struct blocker *bl = calloc(sizeof(*obl), 1); + + bl->sp = sp; + bl->next = obl; + return bl; +} + +static int +blkix(struct blocker *obl) +{ + if (blkidp > 1 && blkidx[blkidp-1] == obl) + return blkidp-1; + if (blkidp == RECMAX) + error("blkix"); + blkidx[blkidp] = obl; + return blkidp++; +} + +static struct blocker * +mergeadd(struct blocker *bl, int m) +{ + struct blocker *w, *ww; + + DPRINT(("mergeadd: %p %d\n", bl, m)); + if (bl == 0) + return blkidx[m]; + if (m == 0) + return bl; + + blkidx[blkidp] = bl; + for (w = blkidx[m]; w; w = w->next) { + ww = calloc(sizeof(*w), 1); + ww->sp = w->sp; + ww->next = blkidx[blkidp]; + blkidx[blkidp] = ww; + } + DPRINT(("mergeadd return: %d ", blkidp)); +#ifdef PCC_DEBUG + if (dflag) { + for (w = blkidx[blkidp]; w; w = w->next) + printf("%s ", w->sp->namep); + printf("\n"); + } +#endif + return blkidx[blkidp++]; +} + +static void +storeblk(int l, struct iobuf *ob) +{ + DPRINT(("storeblk: %d\n", l)); + putob(ob, BLKID); + putob(ob, l); +} + +/* + * Save filename on heap (with escaped chars). + */ +static struct iobuf * +unfname(void) +{ + struct iobuf *ob = getobuf(); + const usch *bp = ifiles->fname; + + putob(ob, '\"'); + for (; *bp; bp++) { + if (*bp == '\"' || *bp == '\'' || *bp == '\\') + putob(ob, '\\'); + putob(ob, *bp); + } + putob(ob, '\"'); + return ob; +} + +/* + * Version of fastnum that reads from a string and saves in ob. + * We know that it is a number before calling this routine. + */ +static usch * +fstrnum(usch *s, struct iobuf *ob) +{ + if (*s == '.') { + /* not digit, dot. Next will be digit */ + putob(ob, *s++); + } + for (;;) { + putob(ob, *s++); + if ((spechr[*s] & C_EP)) { + if (s[1] != '-' && s[1] != '+') + break; + putob(ob, *s++); + } else if ((*s != '.') && ((spechr[*s] & C_ID) == 0)) + break; + } + return s; +} + +/* + * get a string or character constant. + * similar to faststr. + */ +static usch * +fstrstr(usch *s, struct iobuf *ob) +{ + int ch; + + if (*s == 'L' || *s == 'U' || *s == 'u') + putob(ob, *s++); + if (*s == '8') + putob(ob, *s++); + ch = *s; + putob(ob, *s++); + while (*s != ch) { + if (*s == '\\') + putob(ob, *s++); + putob(ob, *s++); + } + putob(ob, *s++); + return s; +} + +/* + * Save standard comments if found. + */ +static usch * +fcmnt(usch *s, struct iobuf *ob) +{ + putob(ob, *s++); /* / */ + putob(ob, *s++); /* * */ + for (;;s++) { + putob(ob, *s); + if (s[-1] == '*' && *s == '/') + break; + } + return s+1; +} + +static int +getyp(usch *s) +{ + + if (ISID0(*s)) return IDENT; + if ((*s == 'L' || *s == 'U' || *s == 'u') && + (s[1] == '\'' || s[1] == '\"')) return STRING; + if (s[0] == 'u' && s[1] == 'U' && s[2] == '\"') return STRING; + if (s[0] == '\'' || s[0] == '\"') return STRING; + if (spechr[*s] & C_DIGIT) return NUMBER; + if (*s == '.' && (spechr[s[1]] & C_DIGIT)) return NUMBER; + if (*s == '/' && (s[1] == '/' || s[1] == '*')) return CMNT; + return *s; + +} + +/* + * Check ib and print out the symbols there. + * If expandable symbols found recurse and expand them. + * If last identifier on the input list is expandable return it. + * Expect ib to be zero-terminated. + */ +static struct symtab * +loopover(struct iobuf *ib, struct iobuf *ob) +{ + struct iobuf *xb, *xob; + struct symtab *sp; + usch *cp; + int l, c, t; + + ib->cptr = ib->buf; /* start from beginning */ +#ifdef PCC_DEBUG + if (dflag) { + printf("loopover: '"); + prline(ib->cptr); + printf("'\n"); + } +#endif + + xb = getobuf(); + while ((c = *ib->cptr)) { + switch (t = getyp(ib->cptr)) { + case CMNT: + ib->cptr = fcmnt(ib->cptr, ob); + continue; + case NUMBER: + ib->cptr = fstrnum(ib->cptr, ob); + continue; + case STRING: + xb->cptr = xb->buf; + ib->cptr = fstrstr(ib->cptr,xb); + *xb->cptr = 0; + for (cp = xb->buf; *cp; cp++) { + if (*cp <= BLKID) { + if (*cp == BLKID) + cp++; + continue; + } + putob(ob, *cp); + } + continue; + case BLKID: + l = ib->cptr[1]; + ib->cptr+=2; + /* FALLTHROUGH */ + case IDENT: + if (t != BLKID) + l = 0; + /* + * Tricky: if this is the last identifier + * in the expanded list, and it is defined + * as a function-like macro, then push it + * back on the input stream and let fastscan + * handle it as a new macro. + * BUT: if this macro is blocked then this + * should not be done. + */ + for (cp = ib->cptr; ISID(*ib->cptr); ib->cptr++) + ; + if ((sp = lookup(cp, FIND)) == NULL) { +sstr: for (; cp < ib->cptr; cp++) + putob(ob, *cp); + continue; + } + if (expok(sp, l) == 0) { + /* blocked */ + goto sstr; + } else { + if (*sp->value != OBJCT) { + cp = ib->cptr; + while (ISWS(*ib->cptr)) + ib->cptr++; + if (*ib->cptr == 0) { + bufree(xb); + return sp; + } + ib->cptr = cp; + } +newmac: if ((xob = submac(sp, 1, ib, NULL)) == NULL) { + strtobuf((usch *)sp->namep, ob); + } else { + sp = loopover(xob, ob); + bufree(xob); + if (sp != NULL) + goto newmac; + } + } + continue; + default: + putob(ob, c); + } + + ib->cptr++; + } + + bufree(xb); + DPRINT(("loopover return 0\n")); + return 0; +} + +/* + * Handle defined macro keywords found on input stream. + * When finished print out the full expanded line. + * Input here is from the lex buffer. + * Return 1 if success, 0 otherwise. fastscan restores stringbuf. + * Scanned data is stored on heap. Last scan prints out the buffer. + */ +struct iobuf * +kfind(struct symtab *sp) +{ + extern int inexpr; + struct blocker *bl; + struct iobuf *ib, *ob, *outb; + const usch *argary[MAXARGS+1], *sbp; + int c, n = 0; + + blkidp = 1; + outb = NULL; + sbp = stringbuf; + DPRINT(("%d:enter kfind(%s)\n",0,sp->namep)); + switch (*sp->value) { + case FILLOC: + ob = unfname(); + return ob; + + case LINLOC: + return bsheap(NULL, "%d", ifiles->lineno); + + case PRAGLOC: + pragoper(NULL); + return getobuf(); + + case DEFLOC: + case OBJCT: + bl = blkget(sp, NULL); + ib = mkrobuf(sp->value+1); + ob = getobuf(); + ob = exparg(1, ib, ob, bl); + bufree(ib); + break; + + case CTRLOC: + return bsheap(NULL, "%d", counter++); + + default: + /* Search for '(' */ + while (ISWSNL(c = cinput())) + if (c == '\n') + n++; + if (c != '(') { + if (inexpr == 0) + putstr(sp->namep); + if (n == 0) + putch(' '); + else for (ifiles->lineno += n; n; n--) + putch('\n'); + cunput(c); + return 0; /* Failed */ + } + + /* fetch arguments */ +again: if (readargs1(sp, argary)) + error("readargs"); + + bl = blkget(sp, NULL); + ib = subarg(sp, argary, 1, bl); + ob = getobuf(); + ob = exparg(1, ib, ob, bl); + bufree(ib); + break; + } + + /* + * Loop over stringbuf, output the data and remove remaining + * directives. Start with extracting the last keyword (if any). + */ + putob(ob, 0); /* XXX needed? */ + + if (outb == NULL) + outb = getobuf(); + + stringbuf = (usch *)sbp; /* XXX should check cleanup */ + if ((sp = loopover(ob, outb))) { + /* Search for '(' */ + while (ISWSNL(c = cinput())) + if (c == '\n') + n++; + if (c == '(') { + bufree(ob); + goto again; + } + cunput(c); + strtobuf((usch *)sp->namep, outb); + } + bufree(ob); + + for (ifiles->lineno += n; n; n--) + putob(outb, '\n'); + stringbuf = (usch *)sbp; + if (nbufused != 1) + error("lost buffer"); + return outb; +} + +/* + * Replace and push-back on input stream the eventual replaced macro. + * The check for whether it can expand or not should already have been done. + * Blocks for this identifier will be added via insblock() after expansion. + * The same as kfind but read a string. + */ +struct iobuf * +submac(struct symtab *sp, int lvl, struct iobuf *ib, struct blocker *obl) +{ + struct blocker *bl; + struct iobuf *ob, *ab; + const usch *argary[MAXARGS+1]; + usch *cp, *pr; + + DPRINT(("%d:submac: trying '%s'\n", lvl, sp->namep)); + switch (*sp->value) { + case FILLOC: + ob = unfname(); + break; + case LINLOC: + ob = bsheap(NULL, "%d", ifiles->lineno); + break; + case PRAGLOC: + pragoper(ib); + ob = getobuf(); + break; + case OBJCT: + bl = blkget(sp, obl); + ib = mkrobuf(sp->value+1); + ob = getobuf(); + DPRINT(("%d:submac: calling exparg\n", lvl)); + ob = exparg(lvl+1, ib, ob, bl); + bufree(ib); + DPRINT(("%d:submac: return exparg\n", lvl)); + break; + case CTRLOC: + ob = bsheap(NULL, "%d", counter++); + break; + default: + cp = ib->cptr; + while (ISWSNL(*ib->cptr)) + ib->cptr++; + if (*ib->cptr != '(') { + ib->cptr = cp; + return 0; + } + cp = ib->cptr++; + pr = stringbuf; + if ((ab = readargs2(&ib->cptr, sp, argary)) == 0) { + /* Bailed out in the middle of arg list */ + ib->cptr = cp; /* XXX */ + return 0; + } + bl = blkget(sp, obl); + ib = subarg(sp, argary, lvl+1, bl); + bufree(ab); + stringbuf = pr; + + ob = getobuf(); + DPRINT(("%d:submac(: calling exparg\n", lvl)); + ob = exparg(lvl+1, ib, ob, bl); + bufree(ib); + DPRINT(("%d:submac(: return exparg\n", lvl)); + break; + } + putob(ob, 0); + ob->cptr--; + + return ob; +} + +static int +isdir(void) +{ + usch ch; + + while ((ch = cinput()) == ' ' || ch == '\t') + ; + if (ch == '#') + return 1; + cunput(ch); + return 0; +} + +/* + * Deal with directives inside a macro. + * Doing so is really ugly but gcc allows it, so... + */ +static void +chkdir(void) +{ + usch ch; + + for (;;) { + if (isdir()) { +#ifndef GCC_COMPAT + warning("conditionals inside macro arg list"); +#endif + ppdir(); + } + if (flslvl == 0) + return; + while ((ch = cinput()) != '\n') + ; + ifiles->lineno++; + putch('\n'); + } +} + +static int +ra1_wsnl(int sp) +{ + int c; + + while (ISWSNL(c = cinput())) { + if (c == '\n') { + putch('\n'); + chkdir(); + ifiles->lineno++; + if (sp) savch(' '); + } + } + return c; +} + +/* + * Read arguments and put in argument array. + * If EOF is encountered return 1, otherwise 0. + */ +int +readargs1(struct symtab *sp, const usch **args) +{ + struct iobuf *ob; + const usch *vp = sp->value; + int c, i, plev, narg, ellips = 0; + + DPRINT(("readargs1\n")); + narg = *vp++; + if (narg == VARG) { + narg = *vp++; + ellips = 1; + } +#ifdef PCC_DEBUG + if (dflag > 1) { + printf("narg %d varg %d: ", narg, ellips); + prrep(vp); + printf("\n"); + } +#endif + + /* + * read arguments and store them on heap. + */ + c = '('; + for (i = 0; i < narg && c != ')'; i++) { + args[i] = stringbuf; + plev = 0; + + c = ra1_wsnl(0); + for (;;) { + if (plev == 0 && (c == ')' || c == ',')) + break; + if (c == '(') plev++; + if (c == ')') plev--; + if (c == 0) + error("eof in macro"); + else if (c == '/') Ccmnt(savch); + else if (c == '\"' || c == '\'') faststr(c, savch); + else if (ISID0(c)) { + usch *bp = stringbuf; + do { + savch(c); + } while ((spechr[c = cinput()] & C_ID)); + if ((sp = lookup(bp, FIND)) != NULL) { + if (sp == linloc) { + stringbuf = bp; + ob = bsheap(NULL, "%d", ifiles->lineno); + savstr(ob->buf); + bufree(ob); + } else if (sp == ctrloc) { + stringbuf = bp; + ob = bsheap(NULL, "%d", counter++); + savstr(ob->buf); + bufree(ob); + } + } + cunput(c); + } else + savch(c); + if ((c = cinput()) == '\n') { + chkdir(); + ifiles->lineno++, putch(c), c = ' '; + } + } + + while (args[i] < stringbuf && ISWSNL(stringbuf[-1])) + stringbuf--; + savch('\0'); +#ifdef PCC_DEBUG + if (dflag) { + printf("readargs: save arg %d '", i); + prline(args[i]); + printf("'\n"); + } +#endif + } + + /* Handle varargs readin */ + if (ellips) + args[i] = (const usch *)""; + if (ellips && c != ')') { + args[i] = stringbuf; + plev = 0; + c = ra1_wsnl(0); + for (;;) { + if (plev == 0 && c == ')') + break; + if (c == '(') plev++; + if (c == ')') plev--; + if (c == '\"' || c == '\'') faststr(c, savch); + else + savch(c); + if ((c = cinput()) == '\n') + ifiles->lineno++, c = ' '; + } + while (args[i] < stringbuf && ISWSNL(stringbuf[-1])) + stringbuf--; + savch('\0'); +#ifdef PCC_DEBUG + if (dflag) { + printf("readargs: vararg arg %d '", i); + prline(args[i]); + printf("'\n"); + } +#endif + + } + if (narg == 0 && ellips == 0) + c = ra1_wsnl(0); + + if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1)) + error("wrong arg count"); + return 0; +} + +static usch *raptr; +static int +raread(void) +{ + int rv; + + if (raptr) { + if ((rv = *raptr)) + raptr++; + } else + rv = cinput(); + return rv; +} + + +/* + * Read arguments and put in argument array. + * If EOF is encountered return 1, otherwise 0. + */ +struct iobuf * +readargs2(usch **inp, struct symtab *sp, const usch **args) +{ + struct iobuf *ab; + const usch *vp = sp->value; + int argary[MAXARGS+1]; + int c, i, j, plev, narg, ellips = 0; + + DPRINT(("readargs2 %s '", sp->namep)); +#ifdef PCC_DEBUG + if (dflag && inp) { + prline(*inp); + printf("'\n"); + } +#endif + raptr = inp ? *inp : 0; + narg = *vp++; + if (narg == VARG) { + narg = *vp++; + ellips = 1; + } +#ifdef PCC_DEBUG + if (dflag > 1) { + prrep(vp); + printf("\n"); + } +#endif + + /* + * read arguments and store them on heap. + */ + ab = getobuf(); + c = '('; + for (i = 0; i < narg && c != ')'; i++) { + argary[i] = ab->cptr - ab->buf; + plev = 0; + + while ((c = raread()) == ' ' || c == '\t') + ; + for (;;) { + if (plev == 0 && (c == ')' || c == ',')) + break; + if (c == '(') plev++; + if (c == ')') plev--; + if (c == 0) { + if (raptr) { + *inp = raptr; + raptr = 0; + } else + error("eof in macro"); + } else if (c == BLKID) { + putob(ab, c), putob(ab, raread()); + } else if (c == '/') { + if ((c = raread()) == '*') + error("FIXME ccmnt"); + putob(ab, '/'); + continue; + } else if (c == '\"' || c == '\'') { + if (raptr) { + raptr = fstrstr(raptr-1, ab); + } else { + int mp = macpos; + faststr(c, macsav); + strtobuf(macbase+mp, ab); + macpos = mp; + } + } else if (ISID0(c)) { + int mp = macpos; + do { + macsav(c); + } while (ISID(c = raread())); + macsav(0); + macpos = mp; + if ((sp = lookup(macbase+mp, FIND)) && + (sp == linloc)) { + bsheap(ab, "%d", ifiles->lineno); + } else + strtobuf(macbase+mp, ab); + continue; + } else + putob(ab, c); + c = raread(); + } + + while (argary[i] < ab->cptr-ab->buf && ISWSNL(ab->cptr[-1])) + ab->cptr--; + putob(ab, '\0'); +#ifdef PCC_DEBUG + if (dflag) { + printf("readargs2: save arg %d '", i); + prline(ab->buf+argary[i]); + printf("'\n"); + } +#endif + } + + /* Handle varargs readin */ + if (ellips) + args[i] = (const usch *)""; + if (ellips && c != ')') { + argary[i] = ab->cptr - ab->buf; + plev = 0; + while ((c = raread()) == ' ' || c == '\t') + ; + for (;;) { + if (plev == 0 && c == ')') + break; + if (c == '(') plev++; + if (c == ')') plev--; + if (c == '\"' || c == '\'') { + if (raptr) { + raptr = fstrstr(raptr-1, ab); + } else { + int mp = macpos; + faststr(c, macsav); + strtobuf(macbase+mp, ab); + macpos = mp; + } + } else + putob(ab, c); + c = raread(); + } + while (argary[i] < ab->cptr-ab->buf && ISWSNL(ab->cptr[-1])) + ab->cptr--; + putob(ab, '\0'); + i++; + } + if (narg == 0 && ellips == 0) { + while ((c = raread()) == ' ' || c == '\t') + ; + } + + if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1)) + error("wrong arg count"); + if (raptr) + *inp = raptr; + for (j = 0; j < i; j++) + args[j] = ab->buf + argary[j]; + return ab; +} + +/* + * expand a function-like macro. + * vp points to end of replacement-list + * reads function arguments from input stream. + * result is pushed-back for more scanning. + */ +struct iobuf * +subarg(struct symtab *nl, const usch **args, int lvl, struct blocker *bl) +{ + struct blocker *w; + struct iobuf *ob, *cb, *nb; + int narg, instr, snuff; + const usch *sp, *bp, *ap, *vp, *tp; + + DPRINT(("%d:subarg '%s'\n", lvl, nl->namep)); + ob = getobuf(); + vp = nl->value; + narg = *vp++; + if (narg == VARG) + narg = *vp++; + + sp = vp; + instr = snuff = 0; +#ifdef PCC_DEBUG + if (dflag>1) { + printf("%d:subarg ARGlist for %s: '", lvl, nl->namep); + prrep(vp); + printf("' "); + for (w = bl; w; w = w->next) + printf("%s ", w->sp->namep); + printf("\n"); + } +#endif + + /* + * walk forward over replacement-list while replacing + * arguments. Arguments are macro-expanded if required. + */ + while (*sp) { + if (*sp == SNUFF) + putob(ob, '\"'), snuff ^= 1; + else if (*sp == CONC) + ; + else if (*sp == WARN) { + + if (sp[1] == VARG) { + bp = ap = args[narg]; + sp++; +#ifdef GCC_COMPAT + } else if (sp[1] == GCCARG) { + /* XXX remove last , not add 0 */ + ap = args[narg]; + if (ap[0] == 0) + ap = (const usch *)"0"; + bp = ap; + sp++; +#endif + } else + bp = ap = args[(int)*++sp]; +#ifdef PCC_DEBUG + if (dflag>1){ + printf("%d:subarg GOTwarn; arglist '", lvl); + prline(bp); + printf("'\n"); + } +#endif + if (sp[-2] != CONC && !snuff && sp[1] != CONC) { + /* + * Expand an argument; 6.10.3.1: + * "A parameter in the replacement list, + * is replaced by the corresponding argument + * after all macros contained therein have + * been expanded.". + */ + w = bl ? bl->next : NULL; + cb = mkrobuf(bp); + nb = getobuf(); + DPRINT(("%d:subarg: calling exparg\n", lvl)); + nb = exparg(lvl+1, cb, nb, w); + DPRINT(("%d:subarg: return exparg\n", lvl)); + bufree(cb); + strtobuf(nb->buf, ob); + bufree(nb); + } else { + while (*bp) { + if (snuff && !instr && ISWS(*bp)) { + while (ISWS(*bp)) + bp++; + putob(ob, ' '); + } + + if (snuff && + (*bp == '\'' || *bp == '"')) { + instr ^= 1; + for (tp = bp - 1; *tp == '\\'; tp--) + instr ^= 1; + if (*bp == '"') + putob(ob, '\\'); + } + if (snuff && instr && *bp == '\\') + putob(ob, '\\'); + putob(ob, *bp); + bp++; + } + } + } else if (ISID0(*sp)) { + if (lookup(sp, FIND)) + storeblk(blkix(bl), ob); + while (ISID(*sp)) + putob(ob, *sp++); + sp--; + } else + putob(ob, *sp); + sp++; + } + putob(ob, 0); + ob->cptr = ob->buf; + DPRINT(("%d:subarg retline %s\n", lvl, ob->buf)); + return ob; +} + +/* + * Do a (correct) expansion of a WARN-terminated buffer of tokens. + * Data is read from the lex buffer, result on lex buffer, WARN-terminated. + * Expansion blocking is not altered here unless when tokens are + * concatenated, in which case they are removed. + */ +struct iobuf * +exparg(int lvl, struct iobuf *ib, struct iobuf *ob, struct blocker *bl) +{ + extern int inexpr; + struct iobuf *nob; + struct symtab *nl; + int c, m; + usch *cp, *bp, *sbp; + + DPRINT(("%d:exparg: entry ib %s\n", lvl, ib->cptr)); +#ifdef PCC_DEBUG + if (dflag > 1) { + printf("exparg entry: full "); + prline(ib->cptr); + printf("\n"); + } +#endif + + while ((c = getyp(ib->cptr)) != 0) { + ib->cptr++; + + switch (c) { + + case CMNT: + ib->cptr = fcmnt(ib->cptr-1, ob); + break; + case NUMBER: + ib->cptr = fstrnum(ib->cptr-1, ob); + break; + case STRING: + ib->cptr = fstrstr(ib->cptr-1, ob); + break; + case BLKID: + m = *ib->cptr++; + ib->cptr++; + /* FALLTHROUGH */ + case IDENT: + if (c != BLKID) + m = 0; + for (cp = ib->cptr-1; ISID(*cp); cp++) + ; +#ifdef PCC_DEBUG +if (dflag) { printf("!! ident "); prline(ib->cptr-1); printf("\n"); } +#endif + sbp = stringbuf; + if (*cp == BLKID) { + /* concatenation */ + bp = stringbuf; + for (cp = ib->cptr-1; + ISID(*cp) || *cp == BLKID; cp++) { + if (*cp == BLKID) { + /* XXX add to block list */ + cp++; + } else + savch(*cp); + } + ib->cptr = cp; + cp = stringbuf; + savch(0); + } else { + bp = ib->cptr-1; + ib->cptr = cp; + } +#ifdef PCC_DEBUG +if (dflag) { printf("!! ident2 "); prline(bp); printf("\n"); } +#endif + if ((nl = lookup(bp, FIND)) == NULL) { +sstr: for (; bp < cp; bp++) + putob(ob, *bp); + stringbuf = sbp; + break; + } else if (inexpr && *nl->value == DEFLOC) { + int gotlp = 0; + while (ISWS(*ib->cptr)) ib->cptr++; + if (*ib->cptr == '(') + gotlp++, ib->cptr++; + while (ISWS(*ib->cptr)) ib->cptr++; + if (!ISID0(*ib->cptr)) + error("bad defined"); + putob(ob, lookup(ib->cptr, FIND) ? '1' : '0'); + while (ISID(*ib->cptr)) ib->cptr++; + while (ISWS(*ib->cptr)) ib->cptr++; + if (gotlp && *ib->cptr != ')') + error("bad defined"); + ib->cptr++; + break; + } + stringbuf = sbp; + if (expokb(nl, bl) && expok(nl, m)) { + if ((nob = submac(nl, lvl+1, ib, bl))) { + if (nob->buf[0] == '-' || + nob->buf[0] == '+') + putob(ob, ' '); + strtobuf(nob->buf, ob); + if (ob->cptr[-1] == '-' || + ob->cptr[-1] == '+') + putob(ob, ' '); + bufree(nob); + } else { + goto sblk; + } + } else { + /* blocked */ +sblk: storeblk(blkix(mergeadd(bl, m)), ob); + goto sstr; + } + break; + + default: + putob(ob, c); + break; + } + } + putob(ob, 0); + ob->cptr--; + DPRINT(("%d:exparg return: ob %s\n", lvl, ob->buf)); +#ifdef PCC_DEBUG + if (dflag > 1) { + printf("%d:exparg: full ", lvl); + prline(ob->buf); + printf("\n"); + } +#endif + return ob; +} + +#ifdef PCC_DEBUG + +static void +prrep(const usch *s) +{ + while (*s) { + switch (*s) { + case WARN: + if (s[1] == VARG) printf(""); + else if (s[1] == GCCARG) printf(""); + else printf("", s[1]); + s++; + break; + case CONC: printf(""); break; + case SNUFF: printf(""); break; + case BLKID: printf("",s[1]); s++; break; + default: printf("%c", *s); break; + } + s++; + } +} + +static void +prline(const usch *s) +{ + while (*s) { + switch (*s) { + case BLKID: printf("", *++s); break; + case WARN: printf(""); break; + case CONC: printf(""); break; + case SNUFF: printf(""); break; + case '\n': printf(""); break; + default: + if (*s > 0x7f) + printf("<0x%x>", *s); + else + printf("%c", *s); + break; + } + s++; + } +} +#endif + +usch * +savstr(const usch *str) +{ + usch *rv = stringbuf; + + do { + if (stringbuf >= &sbf[SBSIZE]) + error("out of macro space!"); + } while ((*stringbuf++ = *str++)); + stringbuf--; + return rv; +} + +void +putch(int ch) +{ + if (Mflag) + return; + fputc(ch, stdout); +} + +void +putstr(const usch *s) +{ + for (; *s; s++) { + if (Mflag == 0) + fputc(*s, stdout); + } +} + +/* + * convert a number to an ascii string. Store it on the heap. + */ +static void +num2str(struct iobuf *ob, int num) +{ + static usch buf[12]; + usch *b = buf; + int m = 0; + + if (num < 0) + num = -num, m = 1; + do { + *b++ = (usch)(num % 10 + '0'); + num /= 10; + } while (num); + if (m) + *b++ = '-'; + while (b > buf) + putob(ob, *--b); +} + +/* + * similar to sprintf, but only handles %c, %s and %d. + * saves result on heap. + */ +static void +vsheap(struct iobuf *ob, const char *fmt, va_list ap) +{ + for (; *fmt; fmt++) { + if (*fmt == '%') { + fmt++; + switch (*fmt) { + case 's': + strtobuf(va_arg(ap, usch *), ob); + break; + case 'd': + num2str(ob, va_arg(ap, int)); + break; + case 'c': + putob(ob, va_arg(ap, int)); + break; + default: + error("bad sheap"); + } + } else + putob(ob, *fmt); + } + putob(ob, 0); + ob->cptr--; +} + +struct iobuf * +bsheap(struct iobuf *ob, const char *fmt, ...) +{ + va_list ap; + + if (ob == NULL) + ob = getobuf(); + + va_start(ap, fmt); + vsheap(ob, fmt, ap); + va_end(ap); + + return ob; +} + +static void +usage(void) +{ + error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]"); +} + +#ifdef notyet +/* + * Symbol table stuff. + * The data structure used is a patricia tree implementation using only + * bytes to store offsets. + * The information stored is (lower address to higher): + * + * unsigned char bitno[2]; bit number in the string + * unsigned char left[3]; offset from base to left element + * unsigned char right[3]; offset from base to right element + */ +#endif + +/* + * This patricia implementation is more-or-less the same as + * used in ccom for string matching. + */ +struct tree { + int bitno; + struct tree *lr[2]; +}; + +#define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF)) +#define LEFT_IS_LEAF 0x80000000 +#define RIGHT_IS_LEAF 0x40000000 +#define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0) +#define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0) +#define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1 +#define CHECKBITS 8 + +static struct tree *sympole; +static int numsyms; + +static struct tree * +gtree(void) +{ + static int ntrees; + static struct tree *tp; + + if (ntrees == 0) { + tp = xmalloc(BUFSIZ); + ntrees = BUFSIZ/sizeof(*tp); + } + return &tp[--ntrees]; +} + +/* + * Allocate a symtab struct and store the string. + */ +static struct symtab * +getsymtab(const usch *str) +{ + static int nsyms; + static struct symtab *spp; + struct symtab *sp; + + if (nsyms == 0) { + spp = xmalloc(BUFSIZ); + nsyms = BUFSIZ/sizeof(*sp); + } + sp = &spp[--nsyms]; + + sp->namep = str; + sp->value = NULL; + sp->file = ifiles ? ifiles->orgfn : (const usch *)""; + sp->line = ifiles ? ifiles->lineno : 0; + return sp; +} + +/* + * Do symbol lookup in a patricia tree. + * Only do full string matching, no pointer optimisations. + */ +struct symtab * +lookup(const usch *key, int enterf) +{ + struct symtab *sp; + struct tree *w, *new, *last; + int len, cix, bit, fbit, svbit, ix, bitno; + const usch *k, *m; + + /* Count full string length */ + for (k = key, len = 0; ISID(*k) & C_ID; k++, len++) + ; + + switch (numsyms) { + case 0: /* no symbols yet */ + if (enterf != ENTER) + return NULL; + sympole = (struct tree *)getsymtab(key); + numsyms++; + return (struct symtab *)sympole; + + case 1: + w = sympole; + svbit = 0; /* XXX gcc */ + break; + + default: + w = sympole; + bitno = len * CHECKBITS; + for (;;) { + bit = BITNO(w->bitno); + fbit = bit >= bitno ? 0 : P_BIT(key, bit); + svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : + IS_LEFT_LEAF(w->bitno); + w = w->lr[fbit]; + if (svbit) + break; + } + } + + sp = (struct symtab *)w; + + m = sp->namep; + k = key; + + /* Check for correct string and return */ + for (cix = 0; *m && ISID(*k) && *m == *k; m++, k++, cix += CHECKBITS) + ; + if (*m == 0 && ISID(*k) == 0) { + if (enterf != ENTER && sp->value == NULL) + return NULL; + return sp; + } + + if (enterf != ENTER) + return NULL; /* no string found and do not enter */ + + ix = *m ^ *k; + while ((ix & 1) == 0) + ix >>= 1, cix++; + + /* Create new node */ + new = gtree(); + bit = P_BIT(key, cix); + new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + new->lr[bit] = (struct tree *)getsymtab(key); + + if (numsyms++ == 1) { + new->lr[!bit] = sympole; + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + sympole = new; + return (struct symtab *)new->lr[bit]; + } + + w = sympole; + last = NULL; + for (;;) { + fbit = w->bitno; + bitno = BITNO(w->bitno); + if (bitno == cix) + error("bitno == cix"); + if (bitno > cix) + break; + svbit = P_BIT(key, bitno); + last = w; + w = w->lr[svbit]; + if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) + break; + } + + new->lr[!bit] = w; + if (last == NULL) { + sympole = new; + } else { + last->lr[svbit] = new; + last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + } + if (bitno < cix) + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + return (struct symtab *)new->lr[bit]; +} + +void * +xmalloc(int sz) +{ + usch *rv; + + if ((rv = (void *)malloc(sz)) == NULL) + error("xmalloc: out of mem"); + return rv; +} + +void * +xrealloc(void *p, int sz) +{ + usch *rv; + + if ((rv = (void *)realloc(p, sz)) == NULL) + error("xrealloc: out of mem"); + return rv; +} + +static usch * +xstrdup(const usch *str) +{ + usch *rv; + + if ((rv = (usch *)strdup((const char *)str)) == NULL) + error("xstrdup: out of mem"); + return rv; +} + + diff --git a/lang/pcc/pcc/cc/cpp/cpp.h b/lang/pcc/pcc/cc/cpp/cpp.h new file mode 100644 index 000000000..9e21af15c --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/cpp.h @@ -0,0 +1,207 @@ +/* $Id: cpp.h,v 1.93 2016/03/12 15:46:06 ragge Exp $ */ + +/* + * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 /* for debug/printf */ + +typedef unsigned char usch; +extern usch *stringbuf; + +extern int trulvl; +extern int flslvl; +extern int elflvl; +extern int elslvl; +extern int dflag; +extern int tflag, Aflag, Cflag, Pflag; +extern int Mflag, dMflag, MPflag, MMDflag; +extern char *Mfile, *MPfile; +extern int defining; +extern FILE *of; + +/* args for lookup() */ +#define FIND 0 +#define ENTER 1 + +/* buffer used internally */ +#ifndef CPPBUF +#if defined(mach_pdp11) +#define CPPBUF BUFSIZ +#define BUF_STACK +#else +#define CPPBUF 16384 +#endif +#endif + +#define MAXARGS 128 /* Max # of args to a macro. Should be enough */ +#define MAXIDSZ 63 /* Max length of C99 identifier; 5.2.4.1 */ + +#define PBMAX 10 /* min pushbackbuffer size */ +#define BBUFSZ (PBMAX+CPPBUF+1) + +#define CTRLOC 0xf8 /* __COUNTER__ */ +#define DEFLOC 0xf9 /* defined */ +#define PRAGLOC 0xfa /* _Pragma */ +#define LINLOC 0xfb /* __LINE__ */ +#define FILLOC 0xfc /* __FILE__ */ +#define GCCARG 0xfd /* has gcc varargs that may be replaced with 0 */ +#define VARG 0xfe /* has varargs */ +#define OBJCT 0xff +#define WARN 1 /* SOH, not legal char */ +#define CONC 2 /* STX, not legal char */ +#define SNUFF 3 /* ETX, not legal char */ +#define BLKID 4 /* EOT, not legal char */ + +/* Used in macro expansion */ +#define RECMAX 10000 /* max # of recursive macros */ +#define MKB(l,h) (l+((h)<<8)) + +/* quick checks for some characters */ +#define C_SPEC 0001 /* for fastscan() parsing */ +#define C_2 0002 /* for yylex() tokenizing */ +#define C_WSNL 0004 /* ' ','\t','\r','\n' */ +#define C_ID 0010 /* [_a-zA-Z0-9] */ +#define C_ID0 0020 /* [_a-zA-Z] */ +#define C_EP 0040 /* [epEP] */ +#define C_DIGIT 0100 /* [0-9] */ +#define C_HEX 0200 /* [0-9a-fA-F] */ + +extern usch spechr[]; + +#define ISWSNL(x) (spechr[x] & (C_WSNL)) +#define ISWS(x) ((x) == '\t' || (x) == ' ') +#define ISID(x) (spechr[x] & C_ID) +#define ISID0(x) (spechr[x] & C_ID0) +#define ISDIGIT(x) (spechr[x] & C_DIGIT) + +/* + * definition for include file info + */ +struct includ { + struct includ *next; + const usch *fname; /* current fn, changed if #line found */ + const usch *orgfn; /* current fn, not changed */ + int lineno; + int escln; /* escaped newlines, to be added */ + int infil; + usch *curptr; + usch *maxread; + usch *ostr; + usch *buffer; + int idx; + void *incs; + const usch *fn; +#ifdef BUF_STACK + usch bbuf[BBUFSZ]; +#else + usch *bbuf; +#endif +}; +#define INCINC 0 +#define SYSINC 1 + +extern struct includ *ifiles; + +/* Symbol table entry */ +struct symtab { + const usch *namep; + const usch *value; + const usch *file; + int line; +}; + +struct initar { + struct initar *next; + int type; + char *str; +}; + +/* buffer definition */ +struct iobuf { + usch *buf; + usch *cptr; + usch *bsz; + int ro:1, inuse:1; +}; +struct iobuf *getobuf(void); +void putob(struct iobuf *ob, int ch); +void bufree(struct iobuf *iob); + +/* + * Struct used in parse tree evaluation. + * op is one of: + * - number type (NUMBER, UNUMBER) + * - zero (0) if divided by zero. + */ +struct nd { + int op; + union { + long long val; + unsigned long long uval; + } n; +}; +extern struct nd yynode; + +#define nd_val n.val +#define nd_uval n.uval + +enum { NUMBER = 257, UNUMBER, LS, RS, EQ, NE, STRING, WSPACE, CMNT, IDENT, + OROR, ANDAND, DEFINED, LE, GE }; + +#define SLO_IGNOREWS 001 + +struct symtab *lookup(const usch *namep, int enterf); +struct blocker; +struct iobuf *submac(struct symtab *nl, int, struct iobuf *, struct blocker *); +struct iobuf *kfind(struct symtab *nl); +void ppdir(void); + +void define(void); +void include(void); +void include_next(void); +void line(void); + +int pushfile(const usch *fname, const usch *fn, int idx, void *incs); +void prtline(int nl); +int yylex(void); +void cunput(int); +int yyparse(void); +usch *savstr(const usch *str); +void savch(int c); +void putch(int); +void putstr(const usch *s); +usch *sheap(const char *fmt, ...); +struct iobuf *bsheap(struct iobuf *, const char *fmt, ...); +void warning(const char *fmt, ...); +void error(const char *fmt, ...); +int cinput(void); +int inc2(void); +int Ccmnt(void (*d)(int)); +usch *heapid(int ch); +usch *readid(int ch); +void faststr(int bc, void (*d)(int)); +int fastnum(int ch, void (*d)(int)); +void *xrealloc(void *p, int sz); +void *xmalloc(int sz); diff --git a/lang/pcc/pcc/cc/cpp/cpy.y b/lang/pcc/pcc/cc/cpp/cpy.y new file mode 100644 index 000000000..9af54c1af --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/cpy.y @@ -0,0 +1,221 @@ +/* $Id: cpy.y,v 1.21 2014/05/28 08:52:42 plunky Exp $ */ + +/* + * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 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. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "config.h" + +#include "cpp.h" + +void yyerror(const char *); +int setd(int l, int r); + +#define EVALUNARY(tok, l, r) l.nd_val = tok r.nd_val; l.op = r.op +#define EVALBIN(tok, d, l, r) \ + d.op = setd(l.op, r.op); d.nd_val = l.nd_val tok r.nd_val +#define EVALUBIN(tok, d, l, r, t) \ + d.op = setd(l.op, r.op); \ + if (d.op == NUMBER) d.nd_val = l.nd_val tok r.nd_val; \ + else d.nd_uval = l.nd_uval tok r.nd_uval; \ + if (t && d.op) d.op = NUMBER +#define XEVALUBIN(tok, d, l, r) \ + if (r.nd_val) { EVALUBIN(tok, d, l, r, 0); } else d.op = 0 +%} + +%term stop +%term EQ NE LE GE LS RS +%term ANDAND OROR IDENT NUMBER UNUMBER DEFINED +/* + * The following terminals are not used in the yacc code. + */ +%term STRING WSPACE CMNT + +%left ',' +%right '?' ':' +%left OROR +%left ANDAND +%left '|' '^' +%left '&' +%binary EQ NE +%binary '<' '>' LE GE +%left LS RS +%left '+' '-' +%left '*' '/' '%' +%right '!' '~' UMINUS +%left '(' + +%union { + struct nd node; +} + +%type term e NUMBER UNUMBER + +%% +S: e '\n' { + if ($1.op == 0) + error("division by zero"); + return $1.nd_val; + } + +e: e '*' e + { EVALUBIN(*, $$, $1, $3, 0); } + | e '/' e + { XEVALUBIN(/, $$, $1, $3); } + | e '%' e + { XEVALUBIN(%, $$, $1, $3); } + | e '+' e + { EVALBIN(+, $$, $1, $3); } + | e '-' e + { EVALBIN(-, $$, $1, $3); } + | e LS e + { EVALBIN(<<, $$, $1, $3); } + | e RS e + { EVALUBIN(>>, $$, $1, $3, 0); } + | e '<' e + { EVALUBIN(<, $$, $1, $3, 1); } + | e '>' e + { EVALUBIN(>, $$, $1, $3, 1); } + | e LE e + { EVALUBIN(<=, $$, $1, $3, 1); } + | e GE e + { EVALUBIN(>=, $$, $1, $3, 1); } + | e EQ e + { EVALUBIN(==, $$, $1, $3, 1); } + | e NE e + { EVALUBIN(!=, $$, $1, $3, 1); } + | e '&' e + { EVALBIN(&, $$, $1, $3); } + | e '^' e + { EVALBIN(^, $$, $1, $3); } + | e '|' e + { EVALBIN(|, $$, $1, $3); } + | e ANDAND e { + $$ = $1; + if ($1.nd_val) { + $$.op = setd($1.op, $3.op); + $$.nd_val = ($3.nd_val != 0); + } + if ($$.op == UNUMBER) $$.op = NUMBER; + } + | e OROR e { + if ($1.nd_val != 0) { + $$.nd_val = ($1.nd_val != 0); + $$.op = $1.op; + } else { + $$.nd_val = ($3.nd_val != 0); + $$.op = setd($1.op, $3.op); + } + if ($$.op == UNUMBER) $$.op = NUMBER; + } + | e '?' e ':' e { + if ($1.op == 0) + $$ = $1; + else if ($1.nd_val) + $$ = $3; + else + $$ = $5; + } + | e ',' e { + $$.op = setd($1.op, $3.op); + $$.nd_val = $3.nd_val; + if ($$.op) $$.op = $3.op; + } + | term + {$$ = $1;} +term: + '-' term %prec UMINUS + { EVALUNARY(-, $$, $2); } + | '+' term %prec UMINUS + {$$ = $2;} + | '!' term + { $$.nd_val = ! $2.nd_val; $$.op = $2.op ? NUMBER : 0; } + | '~' term + { EVALUNARY(~, $$, $2); } + | '(' e ')' + {$$ = $2;} + | DEFINED '(' NUMBER ')' + {$$= $3;} + | DEFINED NUMBER + {$$ = $2;} + | NUMBER + {$$ = $1;} +%% + +void +yyerror(const char *err) +{ + error(err); +} + +/* + * Set return type of an expression. + */ +int +setd(int l, int r) +{ + if (!l || !r) + return 0; /* div by zero involved */ + if (l == UNUMBER || r == UNUMBER) + return UNUMBER; + return NUMBER; +} + diff --git a/lang/pcc/pcc/cc/cpp/scanner.l b/lang/pcc/pcc/cc/cpp/scanner.l new file mode 100644 index 000000000..670e0315d --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/scanner.l @@ -0,0 +1,939 @@ +%{ +/* $Id: scanner.l,v 1.50 2011/06/03 15:42:45 plunky Exp $ */ + +/* + * Copyright (c) 2004 Anders Magnusson. All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "config.h" + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "compat.h" +#include "cpp.h" +#include "y.tab.h" +%} + +%{ +static void cvtdig(int rad); +static int charcon(usch *); +static void elsestmt(void); +static void ifdefstmt(void); +static void ifndefstmt(void); +static void endifstmt(void); +static void ifstmt(void); +static void cpperror(void); +static void pragmastmt(void); +static void undefstmt(void); +static void cpperror(void); +static void elifstmt(void); +static void storepb(void); +static void badop(const char *); +void include(void); +void define(void); + +extern int yyget_lineno (void); +extern void yyset_lineno (int); + +static int inch(void); + +static int scale, gotdef, contr; +int inif; + +#ifdef FLEX_SCANNER /* should be set by autoconf instead */ +static int +yyinput(char *b, int m) +{ + int c, i; + + for (i = 0; i < m; i++) { + if ((c = inch()) < 0) + break; + *b++ = c; + if (c == '\n') { + i++; + break; + } + } + return i; +} +#undef YY_INPUT +#undef YY_BUF_SIZE +#define YY_BUF_SIZE (8*65536) +#define YY_INPUT(b,r,m) (r = yyinput(b, m)) +#ifdef HAVE_CPP_VARARG_MACRO_GCC +#define fprintf(x, ...) error(__VA_ARGS__) +#endif +#define ECHO putstr((usch *)yytext) +#undef fileno +#define fileno(x) 0 + +#if YY_FLEX_SUBMINOR_VERSION >= 31 +/* Hack to avoid unnecessary warnings */ +FILE *yyget_in (void); +FILE *yyget_out (void); +int yyget_leng (void); +char *yyget_text (void); +void yyset_in (FILE * in_str ); +void yyset_out (FILE * out_str ); +int yyget_debug (void); +void yyset_debug (int bdebug ); +int yylex_destroy (void); +#endif +#else /* Assume lex here */ +#undef input +#undef unput +#define input() inch() +#define unput(ch) unch(ch) +#endif +#define PRTOUT(x) if (YYSTATE || slow) return x; if (!flslvl) putstr((usch *)yytext); +/* protection against recursion in #include */ +#define MAX_INCLEVEL 100 +static int inclevel; +%} + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +FS (f|F|l|L) +IS (u|U|l|L)* +WS [\t ] + +%s IFR CONTR DEF COMMENT + +%% + +"\n" { int os = YYSTATE; + if (os != IFR) + BEGIN 0; + ifiles->lineno++; + if (flslvl == 0) { + if (ifiles->lineno == 1) + prtline(); + else + putch('\n'); + } + if ((os != 0 || slow) && !contr) + return '\n'; + contr = 0; + } + +"\r" { ; /* Ignore CR's */ } + +"++" { badop("++"); } +"--" { badop("--"); } +"==" { return EQ; } +"!=" { return NE; } +"<=" { return LE; } +"<<" { return LS; } +">>" { return RS; } +">=" { return GE; } +"||" { return OROR; } +"&&" { return ANDAND; } +"defined" { int p, c; + gotdef = 1; + if ((p = c = yylex()) == '(') + c = yylex(); + if (c != IDENT || (p != IDENT && p != '(')) + error("syntax error"); + if (p == '(' && yylex() != ')') + error("syntax error"); + return NUMBER; + } + +{WS}+ { ; } +{L}({L}|{D})* { + yylval.node.op = NUMBER; + if (gotdef) { + yylval.node.nd_val + = lookup((usch *)yytext, FIND) != 0; + gotdef = 0; + return IDENT; + } + yylval.node.nd_val = 0; + return NUMBER; + } + +[0-9][0-9]* { + if (slow && !YYSTATE) + return IDENT; + scale = yytext[0] == '0' ? 8 : 10; + goto num; + } + +0[xX]{H}+{IS}? { scale = 16; + num: if (YYSTATE == IFR) + cvtdig(scale); + PRTOUT(NUMBER); + } +0{D}+{IS}? { scale = 8; goto num; } +{D}+{IS}? { scale = 10; goto num; } +'(\\.|[^\\'])+' { + if (YYSTATE || slow) { + yylval.node.op = NUMBER; + yylval.node.nd_val = charcon((usch *)yytext); + return (NUMBER); + } + if (tflag) + yyless(1); + if (!flslvl) + putstr((usch *)yytext); + } + +. { return yytext[0]; } + +{D}+{E}{FS}? { PRTOUT(FPOINT); } +{D}*"."{D}+({E})?{FS}? { PRTOUT(FPOINT); } +{D}+"."{D}*({E})?{FS}? { PRTOUT(FPOINT); } + +^{WS}*#{WS}* { extern int inmac; + + if (inmac) + error("preprocessor directive found " + "while expanding macro"); + contr = 1; + BEGIN CONTR; + } +{WS}+ { PRTOUT(WSPACE); } + +"ifndef" { contr = 0; ifndefstmt(); } +"ifdef" { contr = 0; ifdefstmt(); } +"if" { contr = 0; storepb(); BEGIN IFR; ifstmt(); BEGIN 0; } +"include" { contr = 0; BEGIN 0; include(); prtline(); } +"else" { contr = 0; elsestmt(); } +"endif" { contr = 0; endifstmt(); } +"error" { contr = 0; if (slow) return IDENT; cpperror(); BEGIN 0; } +"define" { contr = 0; BEGIN DEF; define(); BEGIN 0; } +"undef" { contr = 0; if (slow) return IDENT; undefstmt(); } +"line" { contr = 0; storepb(); BEGIN 0; line(); } +"pragma" { contr = 0; pragmastmt(); BEGIN 0; } +"elif" { contr = 0; storepb(); BEGIN IFR; elifstmt(); BEGIN 0; } + + + +"//".*$ { /* if (tflag) yyless(..) */ + if (Cflag && !flslvl && !slow) + putstr((usch *)yytext); + else if (!flslvl) + putch(' '); + } +"/*" { int c, wrn; + int prtcm = Cflag && !flslvl && !slow; + extern int readmac; + + if (Cflag && !flslvl && readmac) + return CMNT; + + if (prtcm) + putstr((usch *)yytext); + wrn = 0; + more: while ((c = input()) && c != '*') { + if (c == '\n') + putch(c), ifiles->lineno++; + else if (c == 1) /* WARN */ + wrn = 1; + else if (prtcm) + putch(c); + } + if (c == 0) + return 0; + if (prtcm) + putch(c); + if ((c = input()) && c != '/') { + unput(c); + goto more; + } + if (prtcm) + putch(c); + if (c == 0) + return 0; + if (!tflag && !Cflag && !flslvl) + unput(' '); + if (wrn) + unput(1); + } + +"##" { return CONCAT; } +"#" { return MKSTR; } +"..." { return ELLIPS; } +"__VA_ARGS__" { return VA_ARGS; } + +L?\"(\\.|[^\\"])*\" { PRTOUT(STRING); } +[a-zA-Z_0-9]+ { /* {L}({L}|{D})* */ + struct symtab *nl; + if (slow) + return IDENT; + if (YYSTATE == CONTR) { + if (flslvl == 0) { + /*error("undefined control");*/ + while (input() != '\n') + ; + unput('\n'); + BEGIN 0; + goto xx; + } else { + BEGIN 0; /* do nothing */ + } + } + if (flslvl) { + ; /* do nothing */ + } else if (isdigit((int)yytext[0]) == 0 && + (nl = lookup((usch *)yytext, FIND)) != 0) { + usch *op = stringbuf; + putstr(gotident(nl)); + stringbuf = op; + } else + putstr((usch *)yytext); + xx: ; + } + +. { + if (contr) { + while (input() != '\n') + ; + unput('\n'); + BEGIN 0; + contr = 0; + goto yy; + } + if (YYSTATE || slow) + return yytext[0]; + if (yytext[0] == 6) { /* PRAGS */ + usch *obp = stringbuf; + extern usch *prtprag(usch *); + *stringbuf++ = yytext[0]; + do { + *stringbuf = input(); + } while (*stringbuf++ != 14); + prtprag(obp); + stringbuf = obp; + } else { + PRTOUT(yytext[0]); + } + yy:; + } + +%% + +usch *yyp, yybuf[CPPBUF]; + +int yylex(void); +int yywrap(void); + +static int +inpch(void) +{ + int len; + + if (ifiles->curptr < ifiles->maxread) + return *ifiles->curptr++; + + if ((len = read(ifiles->infil, ifiles->buffer, CPPBUF)) < 0) + error("read error on file %s", ifiles->orgfn); + if (len == 0) + return -1; + ifiles->curptr = ifiles->buffer; + ifiles->maxread = ifiles->buffer + len; + return inpch(); +} + +#define unch(c) *--ifiles->curptr = c + +static int +inch(void) +{ + int c; + +again: switch (c = inpch()) { + case '\\': /* continued lines */ +msdos: if ((c = inpch()) == '\n') { + ifiles->lineno++; + putch('\n'); + goto again; + } else if (c == '\r') + goto msdos; + unch(c); + return '\\'; + case '?': /* trigraphs */ + if ((c = inpch()) != '?') { + unch(c); + return '?'; + } + switch (c = inpch()) { + case '=': c = '#'; break; + case '(': c = '['; break; + case ')': c = ']'; break; + case '<': c = '{'; break; + case '>': c = '}'; break; + case '/': c = '\\'; break; + case '\'': c = '^'; break; + case '!': c = '|'; break; + case '-': c = '~'; break; + default: + unch(c); + unch('?'); + return '?'; + } + unch(c); + goto again; + default: + return c; + } +} + +/* + * Let the command-line args be faked defines at beginning of file. + */ +static void +prinit(struct initar *it, struct includ *ic) +{ + char *a, *pre, *post; + + if (it->next) + prinit(it->next, ic); + pre = post = NULL; /* XXX gcc */ + switch (it->type) { + case 'D': + pre = "#define "; + if ((a = strchr(it->str, '=')) != NULL) { + *a = ' '; + post = "\n"; + } else + post = " 1\n"; + break; + case 'U': + pre = "#undef "; + post = "\n"; + break; + case 'i': + pre = "#include \""; + post = "\"\n"; + break; + default: + error("prinit"); + } + strlcat((char *)ic->buffer, pre, CPPBUF+1); + strlcat((char *)ic->buffer, it->str, CPPBUF+1); + if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1) + error("line exceeds buffer size"); + + ic->lineno--; + while (*ic->maxread) + ic->maxread++; +} + +/* + * A new file included. + * If ifiles == NULL, this is the first file and already opened (stdin). + * Return 0 on success, -1 if file to be included is not found. + */ +int +pushfile(usch *file) +{ + extern struct initar *initar; + struct includ ibuf; + struct includ *ic; + int c, otrulvl; + + ic = &ibuf; + ic->next = ifiles; + + slow = 0; + if (file != NULL) { + if ((ic->infil = open((char *)file, O_RDONLY)) < 0) + return -1; + ic->orgfn = ic->fname = file; + if (++inclevel > MAX_INCLEVEL) + error("Limit for nested includes exceeded"); + } else { + ic->infil = 0; + ic->orgfn = ic->fname = (usch *)""; + } + ic->buffer = ic->bbuf+NAMEMAX; + ic->curptr = ic->buffer; + ifiles = ic; + ic->lineno = 1; + ic->maxread = ic->curptr; + prtline(); + if (initar) { + *ic->maxread = 0; + prinit(initar, ic); + if (dMflag) + write(ofd, ic->buffer, strlen((char *)ic->buffer)); + initar = NULL; + } + + otrulvl = trulvl; + + if ((c = yylex()) != 0) + error("yylex returned %d", c); + + if (otrulvl != trulvl || flslvl) + error("unterminated conditional"); + + ifiles = ic->next; + close(ic->infil); + inclevel--; + return 0; +} + +/* + * Print current position to output file. + */ +void +prtline() +{ + usch *s, *os = stringbuf; + + if (Mflag) { + if (dMflag) + return; /* no output */ + if (ifiles->lineno == 1) { + s = sheap("%s: %s\n", Mfile, ifiles->fname); + write(ofd, s, strlen((char *)s)); + } + } else if (!Pflag) + putstr(sheap("# %d \"%s\"\n", ifiles->lineno, ifiles->fname)); + stringbuf = os; +} + +void +cunput(int c) +{ +#ifdef PCC_DEBUG + extern int dflag; + if (dflag)printf(": '%c'(%d)", c > 31 ? c : ' ', c); +#endif + unput(c); +} + +int yywrap(void) { return 1; } + +static int +dig2num(int c) +{ + if (c >= 'a') + c = c - 'a' + 10; + else if (c >= 'A') + c = c - 'A' + 10; + else + c = c - '0'; + return c; +} + +/* + * Convert string numbers to unsigned long long and check overflow. + */ +static void +cvtdig(int rad) +{ + unsigned long long rv = 0; + unsigned long long rv2 = 0; + char *y = yytext; + int c; + + c = *y++; + if (rad == 16) + y++; + while (isxdigit(c)) { + rv = rv * rad + dig2num(c); + /* check overflow */ + if (rv / rad < rv2) + error("Constant \"%s\" is out of range", yytext); + rv2 = rv; + c = *y++; + } + y--; + while (*y == 'l' || *y == 'L') + y++; + yylval.node.op = *y == 'u' || *y == 'U' ? UNUMBER : NUMBER; + yylval.node.nd_uval = rv; + if ((rad == 8 || rad == 16) && yylval.node.nd_val < 0) + yylval.node.op = UNUMBER; + if (yylval.node.op == NUMBER && yylval.node.nd_val < 0) + /* too large for signed */ + error("Constant \"%s\" is out of range", yytext); +} + +static int +charcon(usch *p) +{ + int val, c; + + p++; /* skip first ' */ + val = 0; + if (*p++ == '\\') { + switch (*p++) { + case 'a': val = '\a'; break; + case 'b': val = '\b'; break; + case 'f': val = '\f'; break; + case 'n': val = '\n'; break; + case 'r': val = '\r'; break; + case 't': val = '\t'; break; + case 'v': val = '\v'; break; + case '\"': val = '\"'; break; + case '\'': val = '\''; break; + case '\\': val = '\\'; break; + case 'x': + while (isxdigit(c = *p)) { + val = val * 16 + dig2num(c); + p++; + } + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + p--; + while (isdigit(c = *p)) { + val = val * 8 + (c - '0'); + p++; + } + break; + default: val = p[-1]; + } + + } else + val = p[-1]; + return val; +} + +static void +chknl(int ignore) +{ + int t; + + slow = 1; + while ((t = yylex()) == WSPACE) + ; + if (t != '\n') { + if (ignore) { + warning("newline expected, got \"%s\"", yytext); + /* ignore rest of line */ + while ((t = yylex()) && t != '\n') + ; + } + else + error("newline expected, got \"%s\"", yytext); + } + slow = 0; +} + +static void +elsestmt(void) +{ + if (flslvl) { + if (elflvl > trulvl) + ; + else if (--flslvl!=0) { + flslvl++; + } else { + trulvl++; + prtline(); + } + } else if (trulvl) { + flslvl++; + trulvl--; + } else + error("If-less else"); + if (elslvl==trulvl+flslvl) + error("Too many else"); + elslvl=trulvl+flslvl; + chknl(1); +} + +static void +ifdefstmt(void) +{ + int t; + + if (flslvl) { + /* just ignore the rest of the line */ + while (input() != '\n') + ; + unput('\n'); + yylex(); + flslvl++; + return; + } + slow = 1; + do + t = yylex(); + while (t == WSPACE); + if (t != IDENT) + error("bad ifdef"); + slow = 0; + if (flslvl == 0 && lookup((usch *)yytext, FIND) != 0) + trulvl++; + else + flslvl++; + chknl(0); +} + +static void +ifndefstmt(void) +{ + int t; + + slow = 1; + do + t = yylex(); + while (t == WSPACE); + if (t != IDENT) + error("bad ifndef"); + slow = 0; + if (flslvl == 0 && lookup((usch *)yytext, FIND) == 0) + trulvl++; + else + flslvl++; + chknl(0); +} + +static void +endifstmt(void) +{ + if (flslvl) { + flslvl--; + if (flslvl == 0) + prtline(); + } else if (trulvl) + trulvl--; + else + error("If-less endif"); + if (flslvl == 0) + elflvl = 0; + elslvl = 0; + chknl(1); +} + +/* + * Note! Ugly! + * Walk over the string s and search for defined, and replace it with + * spaces and a 1 or 0. + */ +static void +fixdefined(usch *s) +{ + usch *bc, oc; + + for (; *s; s++) { + if (*s != 'd') + continue; + if (memcmp(s, "defined", 7)) + continue; + /* Ok, got defined, can scratch it now */ + memset(s, ' ', 7); + s += 7; +#define WSARG(x) (x == ' ' || x == '\t') + if (*s != '(' && !WSARG(*s)) + continue; + while (WSARG(*s)) + s++; + if (*s == '(') + s++; + while (WSARG(*s)) + s++; +#define IDARG(x) ((x>= 'A' && x <= 'Z') || (x >= 'a' && x <= 'z') || (x == '_')) +#define NUMARG(x) (x >= '0' && x <= '9') + if (!IDARG(*s)) + error("bad defined arg"); + bc = s; + while (IDARG(*s) || NUMARG(*s)) + s++; + oc = *s; + *s = 0; + *bc = (lookup(bc, FIND) != 0) + '0'; + memset(bc+1, ' ', s-bc-1); + *s = oc; + } +} + +/* + * get the full line of identifiers after an #if, pushback a WARN and + * the line and prepare for expmac() to expand. + * This is done before switching state. When expmac is finished, + * pushback the expanded line, change state and call yyparse. + */ +static void +storepb(void) +{ + usch *opb = stringbuf; + int c; + + while ((c = input()) != '\n') { + if (c == '/') { + if ((c = input()) == '*') { + /* ignore comments here whatsoever */ + usch *g = stringbuf; + getcmnt(); + stringbuf = g; + continue; + } else if (c == '/') { + while ((c = input()) && c != '\n') + ; + break; + } + unput(c); + c = '/'; + } + savch(c); + } + cunput('\n'); + savch(0); + fixdefined(opb); /* XXX can fail if #line? */ + cunput(1); /* WARN XXX */ + unpstr(opb); + stringbuf = opb; + slow = 1; + expmac(NULL); + slow = 0; + /* line now expanded */ + while (stringbuf > opb) + cunput(*--stringbuf); +} + +static void +ifstmt(void) +{ + if (flslvl == 0) { + slow = 1; + if (yyparse()) + ++trulvl; + else + ++flslvl; + slow = 0; + } else + ++flslvl; +} + +static void +elifstmt(void) +{ + if (flslvl == 0) + elflvl = trulvl; + if (flslvl) { + if (elflvl > trulvl) + ; + else if (--flslvl!=0) + ++flslvl; + else { + slow = 1; + if (yyparse()) { + ++trulvl; + prtline(); + } else + ++flslvl; + slow = 0; + } + } else if (trulvl) { + ++flslvl; + --trulvl; + } else + error("If-less elif"); +} + +static usch * +svinp(void) +{ + int c; + usch *cp = stringbuf; + + while ((c = input()) && c != '\n') + savch(c); + savch('\n'); + savch(0); + BEGIN 0; + return cp; +} + +static void +cpperror(void) +{ + usch *cp; + int c; + + if (flslvl) + return; + c = yylex(); + if (c != WSPACE && c != '\n') + error("bad error"); + cp = svinp(); + if (flslvl) + stringbuf = cp; + else + error("%s", cp); +} + +static void +undefstmt(void) +{ + struct symtab *np; + + slow = 1; + if (yylex() != WSPACE || yylex() != IDENT) + error("bad undef"); + if (flslvl == 0 && (np = lookup((usch *)yytext, FIND))) + np->value = 0; + slow = 0; + chknl(0); +} + +static void +pragmastmt(void) +{ + int c; + + slow = 1; + if (yylex() != WSPACE) + error("bad pragma"); + if (!flslvl) + putstr((usch *)"#pragma "); + do { + c = input(); + if (!flslvl) + putch(c); /* Do arg expansion instead? */ + } while (c && c != '\n'); + ifiles->lineno++; + prtline(); + slow = 0; +} + +static void +badop(const char *op) +{ + error("invalid operator in preprocessor expression: %s", op); +} + +int +cinput() +{ + return input(); +} diff --git a/lang/pcc/pcc/cc/cpp/tests/res1 b/lang/pcc/pcc/cc/cpp/tests/res1 new file mode 100644 index 000000000..bff9a2506 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res1 @@ -0,0 +1,8 @@ + +# 1 "" + + + + +char p[] = "x ## y"; + diff --git a/lang/pcc/pcc/cc/cpp/tests/res10 b/lang/pcc/pcc/cc/cpp/tests/res10 new file mode 100644 index 000000000..5f294c9bf --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res10 @@ -0,0 +1,16 @@ + +# 1 "" + + + + + +int midiopen(int); + + + + + + + +foo_optarg diff --git a/lang/pcc/pcc/cc/cpp/tests/res11 b/lang/pcc/pcc/cc/cpp/tests/res11 new file mode 100644 index 000000000..4c49d1853 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res11 @@ -0,0 +1,22 @@ + +# 1 "" + + + + + +a +a b +a b c +a b c d + + + + + + +__attribute__((__noreturn__)) + + +1 2 + diff --git a/lang/pcc/pcc/cc/cpp/tests/res12 b/lang/pcc/pcc/cc/cpp/tests/res12 new file mode 100644 index 000000000..05bab6656 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res12 @@ -0,0 +1,21 @@ + +# 1 "" + + + + + +2 2 2 2 2; + + + + + + + + + + + + +(0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, diff --git a/lang/pcc/pcc/cc/cpp/tests/res13 b/lang/pcc/pcc/cc/cpp/tests/res13 new file mode 100644 index 000000000..5ec9b4110 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res13 @@ -0,0 +1,13 @@ + +# 1 "" + + + + +long + + + + + + diff --git a/lang/pcc/pcc/cc/cpp/tests/res14 b/lang/pcc/pcc/cc/cpp/tests/res14 new file mode 100644 index 000000000..dbd86d1cd --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res14 @@ -0,0 +1,11 @@ + +# 1 "" + + + +AB + + + +i1(c) q p + diff --git a/lang/pcc/pcc/cc/cpp/tests/res15 b/lang/pcc/pcc/cc/cpp/tests/res15 new file mode 100644 index 000000000..ea414dec0 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res15 @@ -0,0 +1,18 @@ + +# 1 "" + +do { _foo_X (); } while ( 0); + + +do { _foo_Y (); } while ( 0); + + +do { _foo_(); } while ( 0); + + + + +(111 FIRST 111); +(222 SECOND 222); +(111 (222 THIRD 222) 111); +(222 (111 FOURTH 111) 222); diff --git a/lang/pcc/pcc/cc/cpp/tests/res15C b/lang/pcc/pcc/cc/cpp/tests/res15C new file mode 100644 index 000000000..2b763e3f4 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res15C @@ -0,0 +1,18 @@ + +# 1 "" + +do { _foo_X (); } while (/* CONSTCOND */0); + + +do { _foo_Y (); } while (/* CONSTCOND */0); + + +do { _foo_(); } while (/* CONSTCOND */0); + + + + +(111 /*LINTED*/ FIRST 111); +(222 SECOND /*LINTED*/ 222); +(111 /*LINTED*/ (222 THIRD /*LINTED*/ 222) 111); +(222 (111 /*LINTED*/ FOURTH 111) /*LINTED*/ 222); diff --git a/lang/pcc/pcc/cc/cpp/tests/res16 b/lang/pcc/pcc/cc/cpp/tests/res16 new file mode 100644 index 000000000..8a84a5853 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res16 @@ -0,0 +1,108 @@ + +# 1 "" +This file is testing line counting in various scenarios involving +escaped newlines, including using the trigraph escape sequence + +--> 4 4 +"multi-line string" + + +--> 8 8 +'multi-line character constant' + + +--> 12 12 +multi-line 012345678 integer constant + + + +--> 17 17 +multi-line list of tokens + + + + + +--> 24 24 + + + +--> 28 28 + + + + + + + +--> 36 36 + + + +--> 40 40 + + + + + + + +--> 48 48 + +#pragma multi-line #pragma directive +# 49 "" + + + +--> 52 52 + + + + +--> 57 57 +multi-line macro embedded +--> 59 59 + + + + +--> 64 64 +macro with a leading comment +--> 66 66 + + + +--> 70 70 +macro with leading whitespace and escaped newlines +--> 72 72 + +a token split by escaped newlines + + +--> 77 77 + + + + + + + +#pragma multi-line #pragma inside if-true block +# 84 "" + + + +--> 87 87 + +--> 89 89 + +#pragma with a preceding comment +# 90 "" + +--> 91 91 + + + + + +--> 97 97 diff --git a/lang/pcc/pcc/cc/cpp/tests/res16C b/lang/pcc/pcc/cc/cpp/tests/res16C new file mode 100644 index 000000000..301fe95fa --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res16C @@ -0,0 +1,105 @@ + +# 1 "" +This file is testing line counting in various scenarios involving +escaped newlines, including using the trigraph escape sequence + +--> 4 4 +"multi-line string" + + +--> 8 8 +'multi-line character constant' + + +--> 12 12 +multi-line 012345678 integer constant + + + +--> 17 17 +multi-line list of tokens + + + + + +--> 24 24 +/* multi-line comment */ + + +--> 28 28 + /*/ comment with escaped newlines /* + in the markers +*/ + + + + +--> 36 36 +// multi-line C++ comment + + +--> 40 40 + // C++ comment with leading whitespace and escaped newlines + + + + + + +--> 48 48 + +#pragma multi-line #pragma directive +# 49 "" + + + +--> 52 52 + + + + +--> 57 57 +multi-line macro /* with a comment */ embedded +--> 59 59 +/* comment before directive */ #define BAR macro with a leading comment + + + +--> 64 64 +BAR +--> 66 66 + + + +--> 70 70 +macro with leading whitespace and escaped newlines +--> 72 72 + +a token split by escaped newlines + + +--> 77 77 + + + + + + + +#pragma multi-line #pragma inside if-true block +# 84 "" + + + +--> 87 87 + +--> 89 89 +/* comment */ # pragma with a preceding comment +--> 91 91 + + + + + +--> 97 97 diff --git a/lang/pcc/pcc/cc/cpp/tests/res17 b/lang/pcc/pcc/cc/cpp/tests/res17 new file mode 100644 index 000000000..9cc042bab --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res17 @@ -0,0 +1,33 @@ + +# 1 "" +testing that pp-numbers are parsed correctly + + + + + +123.4e+foo +123.4f+FOO +123.4e+foo + + + + +123.4e+foo + + + + +FOO.123.foo.456+FOO+789.foo + + +0xfaff + + + +0xfe00 + + + +0xfeff + diff --git a/lang/pcc/pcc/cc/cpp/tests/res18 b/lang/pcc/pcc/cc/cpp/tests/res18 new file mode 100644 index 000000000..f248e8bc7 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res18 @@ -0,0 +1,13 @@ + +# 1 "" + + +"foo" +"\"foo\"" +"\"foo\\n\"" +"\"\\\"foo\\\"\"" +"\"foo\\\\\"" +"\"\\\\\\\"foo\"" +"\"foo\\\\\\\\\"" +"foo\n" +"foo\\n" diff --git a/lang/pcc/pcc/cc/cpp/tests/res2 b/lang/pcc/pcc/cc/cpp/tests/res2 new file mode 100644 index 000000000..30da3c465 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res2 @@ -0,0 +1,27 @@ + +# 1 "" + + + + + + + + + + + + + + +f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); +f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1)) +^m(0,1); +int i[] = { 1, 23, 4, 5, }; +char c[2][6] = { "hello", "" }; + + + + + + diff --git a/lang/pcc/pcc/cc/cpp/tests/res3 b/lang/pcc/pcc/cc/cpp/tests/res3 new file mode 100644 index 000000000..d42b7e02a --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res3 @@ -0,0 +1,17 @@ + +# 1 "" + + + + + + + + + +printf("x" "1" "= %d, x" "2" "= %s", x1, x2); +fputs( +"strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s); +\#include "vers2.h" +"hello"; +"hello" ", world" diff --git a/lang/pcc/pcc/cc/cpp/tests/res4 b/lang/pcc/pcc/cc/cpp/tests/res4 new file mode 100644 index 000000000..8e7649ab5 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res4 @@ -0,0 +1,6 @@ + +# 1 "" + + + +(1) diff --git a/lang/pcc/pcc/cc/cpp/tests/res5 b/lang/pcc/pcc/cc/cpp/tests/res5 new file mode 100644 index 000000000..7d57f95a8 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res5 @@ -0,0 +1,5 @@ + +# 1 "" + +int j[] = { 123, 45, 67, 89, + 10, 11, 12, }; diff --git a/lang/pcc/pcc/cc/cpp/tests/res6 b/lang/pcc/pcc/cc/cpp/tests/res6 new file mode 100644 index 000000000..ee2ea69f0 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res6 @@ -0,0 +1,7 @@ + +# 1 "" + + + + +foo diff --git a/lang/pcc/pcc/cc/cpp/tests/res7 b/lang/pcc/pcc/cc/cpp/tests/res7 new file mode 100644 index 000000000..6d7c47c11 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res7 @@ -0,0 +1,6 @@ + +# 1 "" + + +a +YES diff --git a/lang/pcc/pcc/cc/cpp/tests/res8 b/lang/pcc/pcc/cc/cpp/tests/res8 new file mode 100644 index 000000000..118ead4df --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res8 @@ -0,0 +1,9 @@ + +# 1 "" + + + + + +(hej.s_s.s_pos) + diff --git a/lang/pcc/pcc/cc/cpp/tests/res9 b/lang/pcc/pcc/cc/cpp/tests/res9 new file mode 100644 index 000000000..631ecf16f --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/res9 @@ -0,0 +1,6 @@ + +# 1 "" + + + +ao diff --git a/lang/pcc/pcc/cc/cpp/tests/test1 b/lang/pcc/pcc/cc/cpp/tests/test1 new file mode 100644 index 000000000..79a3c5dc5 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test1 @@ -0,0 +1,6 @@ +#define hash_hash # ## # +#define mkstr(a) # a +#define in_between(a) mkstr(a) +#define join(c, d) in_between(c hash_hash d) +char p[] = join(x, y); // equivalent to + // char p[] = "x ## y"; diff --git a/lang/pcc/pcc/cc/cpp/tests/test10 b/lang/pcc/pcc/cc/cpp/tests/test10 new file mode 100644 index 000000000..dfba8b379 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test10 @@ -0,0 +1,14 @@ +#define __CONCAT(x,y) x ## y +#define dev_type_open(n) int n(int) +#define dev_decl(n,t) __CONCAT(dev_type_,t)(__CONCAT(n,t)) +#define cdev_decl(n) dev_decl(n,open) + +cdev_decl(midi); + +# define __GETOPT_PREFIX foo_ +# define __GETOPT_CONCAT(x, y) x ## y +# define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y) +# define __GETOPT_ID(y) __GETOPT_XCONCAT (__GETOPT_PREFIX, y) +# define optarg __GETOPT_ID (optarg) + +optarg diff --git a/lang/pcc/pcc/cc/cpp/tests/test11 b/lang/pcc/pcc/cc/cpp/tests/test11 new file mode 100644 index 000000000..5bf4249f0 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test11 @@ -0,0 +1,20 @@ +#define D1(s, ...) s +#define D2(s, ...) s D1(__VA_ARGS__) +#define D3(s, ...) s D2(__VA_ARGS__) +#define D4(s, ...) s D3(__VA_ARGS__) + +D1(a) +D2(a, b) +D3(a, b, c) +D4(a, b, c, d) + + +#define __sun_attr___noreturn__ __attribute__((__noreturn__)) +#define ___sun_attr_inner(__a) __sun_attr_##__a +#define __sun_attr__(__a) ___sun_attr_inner __a +#define __NORETURN __sun_attr__((__noreturn__)) +__NORETURN +#define X(...) +#define Y(...) 1 __VA_ARGS__ 2 +Y(X X() ()) + diff --git a/lang/pcc/pcc/cc/cpp/tests/test12 b/lang/pcc/pcc/cc/cpp/tests/test12 new file mode 100644 index 000000000..a0a36f125 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test12 @@ -0,0 +1,19 @@ +#define y 2 +#define fe(p) sfe(p) p +#define sfe(p) p +#define Y fe(y) y fe(y) + +Y; + +# define S2B_QMIN 0 +# define S2B_CMIN (S2B_QMIN + 8) +#define S2B_1(i) i, +#define S2B_2(i) S2B_1(i) S2B_1(i) +#define S2B_4(i) S2B_2(i) S2B_2(i) +#define S2B_8(i) S2B_4(i) S2B_4(i) +#define S2B_16(i) S2B_8(i) S2B_8(i) +#define S2B_32(i) S2B_16(i) S2B_16(i) +#define S2B_64(i) S2B_32(i) S2B_32(i) +#define S2B_128(i) S2B_64(i) S2B_64(i) +#define S2B_256(i) S2B_128(i) S2B_128(i) +S2B_256(S2B_CMIN + 0) diff --git a/lang/pcc/pcc/cc/cpp/tests/test13 b/lang/pcc/pcc/cc/cpp/tests/test13 new file mode 100644 index 000000000..51e2385dc --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test13 @@ -0,0 +1,11 @@ + +#define UL long, foo +#define D(I,F) I +#define E(I) D(I) +E(UL) + +#define FOO 1 + +#if (FOO == 1) + +#endif /* FOO */ diff --git a/lang/pcc/pcc/cc/cpp/tests/test14 b/lang/pcc/pcc/cc/cpp/tests/test14 new file mode 100644 index 000000000..45c1892e5 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test14 @@ -0,0 +1,9 @@ +#define A(x) A ## x +#define AB A(B) + +AB + +#define i1(w) i2(w) p +#define i2(x) i1(x) q +i1(c) + diff --git a/lang/pcc/pcc/cc/cpp/tests/test15 b/lang/pcc/pcc/cc/cpp/tests/test15 new file mode 100644 index 000000000..adca9acdc --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test15 @@ -0,0 +1,16 @@ +#define FOO(x) do { _foo_ ## x (); } while (/* CONSTCOND */0) +FOO(X); + +#define BAR FOO(Y) +BAR; + +#define BAZ do { _foo_(); } while (/* CONSTCOND */0) +BAZ; + +#define foo(a) (111 /*LINTED*/ a 111) +#define bar(a) (222 a /*LINTED*/ 222) + +foo(FIRST); +bar(SECOND); +foo(bar(THIRD)); +bar(foo(FOURTH)); diff --git a/lang/pcc/pcc/cc/cpp/tests/test16 b/lang/pcc/pcc/cc/cpp/tests/test16 new file mode 100644 index 000000000..a7f329510 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test16 @@ -0,0 +1,97 @@ +This file is testing line counting in various scenarios involving +escaped newlines, including using the trigraph escape sequence + +--> __LINE__ 4 +"multi-\ +line ??/ +string" +--> __LINE__ 8 +'multi-\ +line ??/ +character constant' +--> __LINE__ 12 +multi-\ +line 012\ +345??/ +678 integer constant +--> __LINE__ 17 +multi-\ +line\ + li??/ +st ??/ +of \ +tokens +--> __LINE__ 24 +/* multi-\ +line ??/ +comment */ +--> __LINE__ 28 + /\ +??/ +*/ comment with escaped newlines /* + in the markers +??/ +*\ +/ +--> __LINE__ 36 +// multi-\ +line ??/ +C++ comment +--> __LINE__ 40 +\ + \ + /\ +??/ +\ +/ ??/ + C++ comment with leading whitespace and escaped newlines +--> __LINE__ 48 +#pragma multi-\ +line ??/ +#pragma directive +--> __LINE__ 52 +#define FOO multi-\ +line macro /* with\ + a comment *??/ +/ embedded +--> __LINE__ 57 +FOO +--> __LINE__ 59 +/??/ +* comment \ + before ??/ + directive */ #define BAR macro with a leading comment +--> __LINE__ 64 +BAR +--> __LINE__ 66 +\ + ??/ + #define BAZ macro with leading whitespace and escaped newlines +--> __LINE__ 70 +BAZ +--> __LINE__ 72 +#define POTATO a token split by escaped newlines +PO\ +TA??/ +TO +--> __LINE__ 77 +#if 0 +#pragma multi-??/ +line \ +#pragma inside if-false block +--> __LINE__ 82 +#else +#pragma multi-??/ +line \ +#pragma inside if-true block +--> __LINE__ 87 +#endif +--> __LINE__ 89 +/* comment */ # pragma with a preceding comment +--> __LINE__ 91 +#if 0 +/* multi-\ + * line comment at flslvl=1 + */ +#endif +--> __LINE__ 97 diff --git a/lang/pcc/pcc/cc/cpp/tests/test17 b/lang/pcc/pcc/cc/cpp/tests/test17 new file mode 100644 index 000000000..de260986b --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test17 @@ -0,0 +1,31 @@ +testing that pp-numbers are parsed correctly + +#define e E +#define f F +#define foo FOO + +123.4e+foo +123.4f+foo +12\ +3.4\ +e\ ++\ +foo +123??/ +.4??/ +e??/ ++??/ +foo +foo.123.foo.456+foo+789.foo + +#if 0xfaff +0xfaff +#endif + +#if 0xfe00 +0xfe00 +#endif + +#if 0xfeff +0xfeff +#endif diff --git a/lang/pcc/pcc/cc/cpp/tests/test18 b/lang/pcc/pcc/cc/cpp/tests/test18 new file mode 100644 index 000000000..caad73739 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test18 @@ -0,0 +1,11 @@ +#define str(a) #a + +str(foo) +str("foo") +str("foo\n") +str("\"foo\"") +str("foo\\") +str("\\\"foo") +str("foo\\\\") +str(foo\n) +str(foo\\n) diff --git a/lang/pcc/pcc/cc/cpp/tests/test19 b/lang/pcc/pcc/cc/cpp/tests/test19 new file mode 100644 index 000000000..52ed28ea0 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test19 @@ -0,0 +1,33 @@ +#define S(x) S0(x) +#define S0(x) #x +#define T(x,y)\ +S(x)\ +S(y) +#define T0(x,y)\ +S0(x)\ +S0(y) +#define U(x)\ +S(x)\ +S(x) +#define U0(x)\ +S0(x)\ +S0(x) +#define V(x)\ +V_(x)\ +V_(x) +#define V_(x)\ +S(x) +#define V0(x)\ +V0_(x)\ +V0_(x) +#define V0_(x)\ +S0(x) +__COUNTER__ +S(__COUNTER__) +S0(__COUNTER__) +T(__COUNTER__,__COUNTER__) +T0(__COUNTER__,__COUNTER__) +U(__COUNTER__) +U0(__COUNTER__) +V(__COUNTER__) +V0(__COUNTER__) diff --git a/lang/pcc/pcc/cc/cpp/tests/test2 b/lang/pcc/pcc/cc/cpp/tests/test2 new file mode 100644 index 000000000..283d4fbc1 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test2 @@ -0,0 +1,25 @@ +#define x 3 +#define f(a) f(x * (a)) +#undef x +#define x 2 +#define g f +#define z z[0] +#define h g(~ +#define m(a) a(w) +#define w 0,1 +#define t(a) a +#define p() int +#define q(x) x +#define r(x,y) x ## y +#define str(x) # x +f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); +g(x+(3,4)-w) | h 5) & m +(f)^m(m); +p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) }; +char c[2][6] = { str(hello), str() }; +/* + * f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); + * f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); + * int i[] = { 1, 23, 4, 5, }; + * char c[2][6] = { "hello", "" }; + */ diff --git a/lang/pcc/pcc/cc/cpp/tests/test3 b/lang/pcc/pcc/cc/cpp/tests/test3 new file mode 100644 index 000000000..a659245ec --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test3 @@ -0,0 +1,15 @@ +#define str(s) # s +#define xstr(s) str(s) +#define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \ + x ## s, x ## t) +#define INCFILE(n) vers ## n +#define glue(a, b) a ## b +#define xglue(a, b) glue(a, b) +#define HIGHLOW "hello" +#define LOW LOW ", world" +debug(1, 2); +fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away + == 0) str(: @\n), s); +\#include xstr(INCFILE(2).h) +glue(HIGH, LOW); +xglue(HIGH, LOW) diff --git a/lang/pcc/pcc/cc/cpp/tests/test4 b/lang/pcc/pcc/cc/cpp/tests/test4 new file mode 100644 index 000000000..0068f3751 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test4 @@ -0,0 +1,4 @@ +#define foobar 1 +#define C(x,y) x##y +#define D(x) (C(x,bar)) +D(foo) diff --git a/lang/pcc/pcc/cc/cpp/tests/test5 b/lang/pcc/pcc/cc/cpp/tests/test5 new file mode 100644 index 000000000..3ca0bb6c9 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test5 @@ -0,0 +1,3 @@ +#define t(x,y,z) x ## y ## z +int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), + t(10,,), t(,11,), t(,,12), t(,,) }; diff --git a/lang/pcc/pcc/cc/cpp/tests/test6 b/lang/pcc/pcc/cc/cpp/tests/test6 new file mode 100644 index 000000000..28cfddece --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test6 @@ -0,0 +1,5 @@ +#define X(a,b, \ + c,d) \ + foo + +X(1,2,3,4) diff --git a/lang/pcc/pcc/cc/cpp/tests/test7 b/lang/pcc/pcc/cc/cpp/tests/test7 new file mode 100644 index 000000000..b22b22bbc --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test7 @@ -0,0 +1,4 @@ +#define a() YES +#define b() a +b() +b()() diff --git a/lang/pcc/pcc/cc/cpp/tests/test8 b/lang/pcc/pcc/cc/cpp/tests/test8 new file mode 100644 index 000000000..c5d2f9a14 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test8 @@ -0,0 +1,7 @@ +// test macro expansion in arguments +#define s_pos s_s.s_pos +#define foo(x) (x) + +//hej.s_pos +foo(hej.s_pos) + diff --git a/lang/pcc/pcc/cc/cpp/tests/test9 b/lang/pcc/pcc/cc/cpp/tests/test9 new file mode 100644 index 000000000..4d4368d56 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/tests/test9 @@ -0,0 +1,4 @@ +#define C(a,b,c) a##b##c +#define N(x,y) C(x,_,y) +#define A_O ao +N(A,O) diff --git a/lang/pcc/pcc/cc/cpp/token.c b/lang/pcc/pcc/cc/cpp/token.c new file mode 100644 index 000000000..2b13b17c4 --- /dev/null +++ b/lang/pcc/pcc/cc/cpp/token.c @@ -0,0 +1,1446 @@ +/* $Id: token.c,v 1.162 2016/03/12 15:46:06 ragge Exp $ */ + +/* + * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Tokenizer for the C preprocessor. + * There are three main routines: + * - fastscan() loops over the input stream searching for magic + * characters that may require actions. + * - yylex() returns something from the input stream that + * is suitable for yacc. + * + * Other functions of common use: + * - inpch() returns a raw character from the current input stream. + * - inch() is like inpch but \\n and trigraphs are expanded. + * - unch() pushes back a character to the input stream. + * + * Input data can be read from either stdio or a buffer. + * If a buffer is read, it will return EOF when ended and then jump back + * to the previous buffer. + * - setibuf(usch *ptr). Buffer to read from, until NULL, return EOF. + * When EOF returned, pop buffer. + * - setobuf(usch *ptr). Buffer to write to + * + * There are three places data is read: + * - fastscan() which has a small loop that will scan over input data. + * - flscan() where everything is skipped except directives (flslvl) + * - inch() that everything else uses. + * + * 5.1.1.2 Translation phases: + * 1) Convert UCN to UTF-8 which is what pcc uses internally (chkucn). + * Remove \r (unwanted) + * Convert trigraphs (chktg) + * 2) Remove \\\n. Need extra care for identifiers and #line. + * 3) Tokenize. + * Remove comments (fastcmnt) + */ + +#include "config.h" + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "compat.h" +#include "cpp.h" + +static void cvtdig(usch **); +static int dig2num(int); +static int charcon(usch **); +static void elsestmt(void); +static void ifdefstmt(void); +static void ifndefstmt(void); +static void endifstmt(void); +static void ifstmt(void); +static void cpperror(void); +static void cppwarning(void); +static void undefstmt(void); +static void pragmastmt(void); +static void elifstmt(void); + +static int inpch(void); +static int chktg(void); +static int chkucn(void); +static void unch(int c); + +#define PUTCH(ch) if (!flslvl) putch(ch) +/* protection against recursion in #include */ +#define MAX_INCLEVEL 100 +static int inclevel; + +struct includ *ifiles; + +/* some common special combos for init */ +#define C_NL (C_SPEC|C_WSNL) +#define C_DX (C_SPEC|C_ID|C_DIGIT|C_HEX) +#define C_I (C_SPEC|C_ID|C_ID0) +#define C_IP (C_SPEC|C_ID|C_ID0|C_EP) +#define C_IX (C_SPEC|C_ID|C_ID0|C_HEX) +#define C_IXE (C_SPEC|C_ID|C_ID0|C_HEX|C_EP) + +usch spechr[256] = { + 0, 0, 0, 0, C_SPEC, C_SPEC, 0, 0, + 0, C_WSNL, C_NL, 0, 0, C_WSNL, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + + C_WSNL, C_2, C_SPEC, 0, 0, 0, C_2, C_SPEC, + 0, 0, 0, C_2, 0, C_2, 0, C_SPEC, + C_DX, C_DX, C_DX, C_DX, C_DX, C_DX, C_DX, C_DX, + C_DX, C_DX, 0, 0, C_2, C_2, C_2, C_SPEC, + + 0, C_IX, C_IX, C_IX, C_IX, C_IXE, C_IX, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_IP, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, 0, C_SPEC, 0, 0, C_I, + + 0, C_IX, C_IX, C_IX, C_IX, C_IXE, C_IX, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_IP, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, 0, C_2, 0, 0, 0, + +/* utf-8 */ + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, + C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, +}; + +/* + * fill up the input buffer + */ +static int +inpbuf(void) +{ + int len; + + if (ifiles->infil == -1) + return 0; + len = read(ifiles->infil, ifiles->buffer, CPPBUF); + if (len == -1) + error("read error on file %s", ifiles->orgfn); + if (len > 0) { + ifiles->buffer[len] = 0; + ifiles->curptr = ifiles->buffer; + ifiles->maxread = ifiles->buffer + len; + } + return len; +} + +/* + * Fillup input buffer to contain at least minsz characters. + */ +static int +refill(int minsz) +{ + usch *dp; + int i, sz; + + if (ifiles->curptr+minsz < ifiles->maxread) + return 0; /* already enough in input buffer */ + + sz = ifiles->maxread - ifiles->curptr; + dp = ifiles->buffer - sz; + for (i = 0; i < sz; i++) + dp[i] = ifiles->curptr[i]; + i = inpbuf(); + ifiles->curptr = dp; + if (i == 0) { + ifiles->maxread = ifiles->buffer; + ifiles->buffer[0] = 0; + } + return 0; +} +#define REFILL(x) if (ifiles->curptr+x >= ifiles->maxread) refill(x) + +/* + * return a raw character from the input stream + */ +static inline int +inpch(void) +{ + + do { + if (ifiles->curptr < ifiles->maxread) + return *ifiles->curptr++; + } while (inpbuf() > 0); + + return -1; +} + +/* + * push a character back to the input stream + */ +static void +unch(int c) +{ + if (c == -1) + return; + + ifiles->curptr--; + if (ifiles->curptr < ifiles->bbuf) + error("pushback buffer full"); + *ifiles->curptr = (usch)c; +} + +/* + * Check for (and convert) trigraphs. + */ +static int +chktg(void) +{ + int ch; + + if ((ch = inpch()) != '?') { + unch(ch); + return 0; + } + + switch (ch = inpch()) { + case '=': return '#'; + case '(': return '['; + case ')': return ']'; + case '<': return '{'; + case '>': return '}'; + case '/': return '\\'; + case '\'': return '^'; + case '!': return '|'; + case '-': return '~'; + } + + unch(ch); + unch('?'); + return 0; +} + +/* + * 5.1.1.2 Translation phase 1. + */ +static int +inc1(void) +{ + int ch, c2; + + do { + ch = inpch(); + } while (ch == '\r' || (ch == '\\' && chkucn())); + if (ch == '?' && (c2 = chktg())) + ch = c2; + return ch; +} + + +/* + * 5.1.1.2 Translation phase 2. + */ +int +inc2(void) +{ + int ch, c2; + + if ((ch = inc1()) != '\\') + return ch; + if ((c2 = inc1()) == '\n') { + ifiles->escln++; + ch = inc2(); + } else + unch(c2); + return ch; +} + +static int incmnt; +/* + * deal with comments in the fast scanner. + * ps prints out the initial '/' if failing to batch comment. + */ +static int +fastcmnt(int ps) +{ + int ch, rv = 1; + + incmnt = 1; + if ((ch = inc2()) == '/') { /* C++ comment */ + while ((ch = inc2()) != '\n') + ; + unch(ch); + } else if (ch == '*') { + for (;;) { + if ((ch = inc2()) < 0) + break; + if (ch == '*') { + if ((ch = inc2()) == '/') { + break; + } else + unch(ch); + } else if (ch == '\n') { + ifiles->lineno++; + putch('\n'); + } + } + } else { + if (ps) PUTCH('/'); /* XXX ? */ + unch(ch); + rv = 0; + } + if (ch < 0) + error("file ends in comment"); + incmnt = 0; + return rv; +} + +/* + * return next char, partly phase 3. + */ +static int +inch(void) +{ + int ch, n; + + ch = inc2(); + n = ifiles->lineno; + if (ch == '/' && Cflag == 0 && fastcmnt(0)) { + /* Comments 5.1.1.2 p3 */ + /* no space if traditional or multiline */ + ch = (tflag || n != ifiles->lineno) ? inch() : ' '; + } + return ch; +} + +/* + * check for universal-character-name on input, and + * unput to the pushback buffer encoded as UTF-8. + */ +static int +chkucn(void) +{ + unsigned long cp, m; + int ch, n; + + if (incmnt) + return 0; + if ((ch = inpch()) == -1) + return 0; + if (ch == 'u') + n = 4; + else if (ch == 'U') + n = 8; + else { + unch(ch); + return 0; + } + + cp = 0; + while (n-- > 0) { + if ((ch = inpch()) == -1 || (spechr[ch] & C_HEX) == 0) { + warning("invalid universal character name"); + // XXX should actually unput the chars and return 0 + unch(ch); // XXX eof + break; + } + cp = cp * 16 + dig2num(ch); + } + + if ((cp < 0xa0 && cp != 0x24 && cp != 0x40 && cp != 0x60) + || (cp >= 0xd800 && cp <= 0xdfff)) /* 6.4.3.2 */ + error("universal character name cannot be used"); + + if (cp > 0x7fffffff) + error("universal character name out of range"); + + n = 0; + m = 0x7f; + while (cp > m) { + unch(0x80 | (cp & 0x3f)); + cp >>= 6; + m >>= (n++ ? 1 : 2); + } + unch(((m << 1) ^ 0xfe) | cp); + return 1; +} + +/* + * deal with comments when -C is active. + * Save comments in expanded macros??? + */ +int +Ccmnt(void (*d)(int)) +{ + int ch; + + if ((ch = inch()) == '/') { /* C++ comment */ + d(ch); + do { + d(ch); + } while ((ch = inch()) != '\n'); + unch(ch); + return 1; + } else if (ch == '*') { + d('/'); + d('*'); + for (;;) { + ch = inch(); + d(ch); + if (ch == '*') { + if ((ch = inch()) == '/') { + d(ch); + return 1; + } else + unch(ch); + } else if (ch == '\n') { + ifiles->lineno++; + } + } + } + d('/'); + unch(ch); + return 0; +} + +/* + * Traverse over spaces and comments from the input stream, + * Returns first non-space character. + */ +static int +fastspc(void) +{ + int ch; + + while ((ch = inch()), ISWS(ch)) + ; + return ch; +} + +/* + * As above but only between \n and #. + */ +static int +fastspcg(void) +{ + int ch, c2; + + while ((ch = inch()) == '/' || ch == '%' || ISWS(ch)) { + if (ch == '%') { + if ((c2 = inch()) == ':') + ch = '#'; /* digraphs */ + else + unch(c2); + break; + } + if (ch == '/') { + if (Cflag) + return ch; + if (fastcmnt(0) == 0) + break; + putch(' '); + } else + putch(ch); + } + return ch; +} + +usch idbuf[MAXIDSZ+1]; +/* + * readin chars and store in buf. Warn about too long names. + */ +usch * +readid(int ch) +{ + int p = 0; + + do { + if (p == MAXIDSZ) + warning("identifier exceeds C99 5.2.4.1, truncating"); + if (p < MAXIDSZ) + idbuf[p] = ch; + p++; + } while (spechr[ch = inch()] & C_ID); + idbuf[p] = 0; + unch(ch); + return idbuf; +} + +/* + * get a string or character constant and save it as given by d. + */ +void +faststr(int bc, void (*d)(int)) +{ + int ch; + + incmnt = 1; + d(bc); + while ((ch = inc2()) != bc) { + if (ch == '\n') { + warning("unterminated literal"); + incmnt = 0; + unch(ch); + return; + } + if (ch < 0) + return; + if (ch == '\\') { + incmnt = 0; + if (chkucn()) + continue; + incmnt = 1; + d(ch); + ch = inc2(); + } + d(ch); + } + d(ch); + incmnt = 0; +} + +/* + * get a preprocessing number and save it as given by d. + * Initial char ch is always stored. + * returns first non-pp-number char. + * + * pp-number: digit + * . digit + * pp-number digit + * pp-number identifier-nondigit + * pp-number e sign + * pp-number E sign + * pp-number p sign + * pp-number P sign + * pp-number . + */ +int +fastnum(int ch, void (*d)(int)) +{ + int c2; + + if ((spechr[ch] & C_DIGIT) == 0) { + /* not digit, dot */ + d(ch); + ch = inch(); + if ((spechr[ch] & C_DIGIT) == 0) + return ch; + } + for (;;) { + d(ch); + if ((ch = inch()) < 0) + return -1; + if ((spechr[ch] & C_EP)) { + if ((c2 = inch()) != '-' && c2 != '+') { + if (c2 >= 0) + unch(c2); + break; + } + d(ch); + ch = c2; + } else if (ch == '.' || (spechr[ch] & C_ID)) { + continue; + } else + break; + } + return ch; +} + +/* + * Scan quickly the input file searching for: + * - '#' directives + * - keywords (if not flslvl) + * - comments + * + * Handle strings, numbers and trigraphs with care. + * Only data from pp files are scanned here, never any rescans. + * This loop is always at trulvl. + */ +static void +fastscan(void) +{ + struct iobuf *ob; + struct symtab *nl; + int ch, c2, i, nch; + usch *cp, *dp; + + goto run; + + for (;;) { + /* tight loop to find special chars */ + /* should use getchar/putchar here */ + for (;;) { + if (ifiles->curptr < ifiles->maxread) { + ch = *ifiles->curptr++; + } else { + if (inpbuf() > 0) + continue; + return; + } +xloop: if (ch < 0) + return; /* EOF */ + if ((spechr[ch] & C_SPEC) != 0) + break; + putch(ch); + } + + REFILL(2); + nch = *ifiles->curptr; + switch (ch) { + case WARN: + case CONC: + error("bad char passed"); + break; + + case '/': /* Comments */ + if (nch != '/' && nch != '*') { + putch(ch); + continue; + } + if (Cflag == 0) { + if (fastcmnt(1)) + putch(' '); /* 5.1.1.2 p3 */ + } else + Ccmnt(putch); + break; + + case '\n': /* newlines, for pp directives */ + /* take care of leftover \n */ + i = ifiles->escln + 1; + ifiles->lineno += i; + ifiles->escln = 0; + while (i-- > 0) + putch('\n'); + + /* search for a # */ +run: while ((ch = inch()) == '\t' || ch == ' ') + putch(ch); + if (ch == '%') { + if ((c2 = inch()) != ':') + unch(c2); + else + ch = '#'; + } + if (ch == '#') + ppdir(); + else + goto xloop; + break; + + case '?': + if (nch == '?' && (ch = chktg())) + goto xloop; + putch('?'); + break; + + case '\'': /* character constant */ + if (tflag) { + putch(ch); + break; /* character constants ignored */ + } + /* FALLTHROUGH */ + case '\"': /* strings */ + faststr(ch, putch); + break; + + case '.': /* for pp-number */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + ch = fastnum(ch, putch); + goto xloop; + + case 'u': + if (nch == '8' && ifiles->curptr[1] == '\"') { + putch(ch); + break; + } + /* FALLTHROUGH */ + case 'L': + case 'U': + if (nch == '\"' || nch == '\'') { + putch(ch); + break; + } + /* FALLTHROUGH */ + default: +#ifdef PCC_DEBUG + if ((spechr[ch] & C_ID) == 0) + error("fastscan"); +#endif + ident: + if (flslvl) + error("fastscan flslvl"); + dp = readid(ch); + if ((nl = lookup(dp, FIND))) { + if ((ob = kfind(nl))) { + if (*ob->buf == '-' || *ob->buf == '+') + putch(' '); + for (cp = ob->buf; cp < ob->cptr; cp++) + putch(*cp); + if (ob->cptr[-1] == '-' || + ob->cptr[-1] == '+') + putch(' '); + bufree(ob); + } + } else + putstr(dp); + break; + + case '\\': + if (nch == '\n') { + ifiles->escln++; + ifiles->curptr++; + break; + } + if (chkucn()) { + ch = inch(); + goto ident; + } + putch('\\'); + break; + } + } + +/*eof:*/ warning("unexpected EOF"); + putch('\n'); +} + +/* + * Store an if/elif line on heap for parsing, evaluate macros and + * call yyparse(). + */ +static usch *yyinp; +int inexpr; +static int +exprline(void) +{ + struct iobuf *ob; + struct symtab *nl; + int oCflag = Cflag; + usch *bp = stringbuf, *dp; + int c, d, ifdef; + + Cflag = ifdef = 0; + + while ((c = inch()) != '\n') { + if (c == '\'' || c == '\"') { + faststr(c, savch); + continue; + } + if (ISDIGIT(c) || c == '.') { + c = fastnum(c, savch); + if (c == '\n') + break; + unch(c); + continue; + } + if (c == 'L' || c == 'u' || c == 'U') { + unch(d = inch()); + if (d == '\'') /* discard wide designator */ + continue; + } + if (ISID0(c)) { + dp = readid(c); + nl = lookup(dp, FIND); + if (nl && *nl->value == DEFLOC) { + ifdef = 1; + } else if (ifdef) { + savch(nl ? '1' : '0'); + ifdef = 0; + } else if (nl != NULL) { + inexpr = 1; + if ((ob = kfind(nl))) { + putob(ob, 0); + savstr(ob->buf); + bufree(ob); + } else + savch('0'); + inexpr = 0; + } else + savch('0'); + } else + savch(c); + } + savch(0); + unch('\n'); + yyinp = bp; + c = yyparse(); + stringbuf = bp; + Cflag = oCflag; + return c; +} + +int +yylex(void) +{ + int ch, c2, t; + + while ((ch = *yyinp++) == ' ' || ch == '\t') + ; + t = ISDIGIT(ch) ? NUMBER : ch; + if (ch < 128 && (spechr[ch] & C_2)) + c2 = *yyinp++; + else + c2 = 0; + + switch (t) { + case 0: return WARN; + case '=': + if (c2 == '=') return EQ; + break; + case '!': + if (c2 == '=') return NE; + break; + case '|': + if (c2 == '|') return OROR; + break; + case '&': + if (c2 == '&') return ANDAND; + break; + case '<': + if (c2 == '<') return LS; + if (c2 == '=') return LE; + break; + case '>': + if (c2 == '>') return RS; + if (c2 == '=') return GE; + break; + case '+': + case '-': + if (ch == c2) + error("invalid preprocessor operator %c%c", ch, c2); + break; + + case '\'': + yynode.op = NUMBER; + yynode.nd_val = charcon(&yyinp); + return NUMBER; + + case NUMBER: + cvtdig(&yyinp); + return NUMBER; + + default: + if (ISID0(t)) { + yyinp--; + while (ISID(*yyinp)) + yyinp++; + yynode.nd_val = 0; + return NUMBER; + } + return ch; + } + yyinp--; + return ch; +} + +/* + * Let the command-line args be faked defines at beginning of file. + */ +static void +prinit(struct initar *it, struct includ *ic) +{ + const char *pre, *post; + char *a; + + if (it->next) + prinit(it->next, ic); + pre = post = NULL; /* XXX gcc */ + switch (it->type) { + case 'D': + pre = "#define "; + if ((a = strchr(it->str, '=')) != NULL) { + *a = ' '; + post = "\n"; + } else + post = " 1\n"; + break; + case 'U': + pre = "#undef "; + post = "\n"; + break; + case 'i': + pre = "#include \""; + post = "\"\n"; + break; + default: + error("prinit"); + } + strlcat((char *)ic->buffer, pre, CPPBUF+1); + strlcat((char *)ic->buffer, it->str, CPPBUF+1); + if (strlcat((char *)ic->buffer, post, CPPBUF+1) >= CPPBUF+1) + error("line exceeds buffer size"); + + ic->lineno--; + while (*ic->maxread) + ic->maxread++; +} + +/* + * A new file included. + * If ifiles == NULL, this is the first file and already opened (stdin). + * Return 0 on success, -1 if file to be included is not found. + */ +int +pushfile(const usch *file, const usch *fn, int idx, void *incs) +{ + extern struct initar *initar; + struct includ ibuf; + struct includ *ic; + int otrulvl; + + ic = &ibuf; + ic->next = ifiles; + + if (file != NULL) { + if ((ic->infil = open((const char *)file, O_RDONLY)) < 0) + return -1; + ic->orgfn = ic->fname = file; + if (++inclevel > MAX_INCLEVEL) + error("limit for nested includes exceeded"); + } else { + ic->infil = 0; + ic->orgfn = ic->fname = (const usch *)""; + } +#ifndef BUF_STACK + ic->bbuf = malloc(BBUFSZ); +#endif + ic->buffer = ic->bbuf+PBMAX; + ic->curptr = ic->buffer; + ifiles = ic; + ic->lineno = 1; + ic->escln = 0; + ic->maxread = ic->curptr; + ic->idx = idx; + ic->incs = incs; + ic->fn = fn; + prtline(1); + if (initar) { + int oin = ic->infil; + ic->infil = -1; + *ic->maxread = 0; + prinit(initar, ic); + initar = NULL; + if (dMflag) + printf("%s", (char *)ic->buffer); + fastscan(); + prtline(1); + ic->infil = oin; + } + + otrulvl = trulvl; + + fastscan(); + + if (otrulvl != trulvl || flslvl) + error("unterminated conditional"); + +#ifndef BUF_STACK + free(ic->bbuf); +#endif + ifiles = ic->next; + close(ic->infil); + inclevel--; + return 0; +} + +/* + * Print current position to output file. + */ +void +prtline(int nl) +{ + struct iobuf *ob; + + if (Mflag) { + if (dMflag) + return; /* no output */ + if (ifiles->lineno == 1 && + (MMDflag == 0 || ifiles->idx != SYSINC)) { + printf("%s: %s\n", Mfile, ifiles->fname); + if (MPflag && + strcmp((const char *)ifiles->fname, (char *)MPfile)) + printf("%s:\n", ifiles->fname); + } + } else if (!Pflag) { + ob = bsheap(0, "\n# %d \"%s\"", ifiles->lineno, ifiles->fname); + if (ifiles->idx == SYSINC) + bsheap(ob, " 3"); + if (nl) bsheap(ob, "\n"); + putstr(ob->buf); + bufree(ob); + } +} + +void +cunput(int c) +{ +#ifdef PCC_DEBUG +// if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c); +#endif + unch(c); +} + +static int +dig2num(int c) +{ + if (c >= 'a') + c = c - 'a' + 10; + else if (c >= 'A') + c = c - 'A' + 10; + else + c = c - '0'; + return c; +} + +/* + * Convert string numbers to unsigned long long and check overflow. + */ +static void +cvtdig(usch **yyp) +{ + unsigned long long rv = 0; + unsigned long long rv2 = 0; + usch *y = *yyp; + int rad; + + y--; + rad = *y != '0' ? 10 : y[1] == 'x' || y[1] == 'X' ? 16 : 8; + if (rad == 16) + y += 2; + while ((spechr[*y] & C_HEX)) { + rv = rv * rad + dig2num(*y); + /* check overflow */ + if (rv / rad < rv2) + error("constant is out of range"); + rv2 = rv; + y++; + } + yynode.op = NUMBER; + while (*y == 'l' || *y == 'L' || *y == 'u' || *y == 'U') { + if (*y == 'u' || *y == 'U') + yynode.op = UNUMBER; + y++; + } + yynode.nd_uval = rv; + if ((rad == 8 || rad == 16) && yynode.nd_val < 0) + yynode.op = UNUMBER; + if (yynode.op == NUMBER && yynode.nd_val < 0) + /* too large for signed, see 6.4.4.1 */ + error("constant is out of range"); + *yyp = y; +} + +static int +charcon(usch **yyp) +{ + int val, c; + usch *p = *yyp; + + val = 0; + if (*p++ == '\\') { + switch (*p++) { + case 'a': val = '\a'; break; + case 'b': val = '\b'; break; + case 'f': val = '\f'; break; + case 'n': val = '\n'; break; + case 'r': val = '\r'; break; + case 't': val = '\t'; break; + case 'v': val = '\v'; break; + case '\"': val = '\"'; break; + case '\'': val = '\''; break; + case '\\': val = '\\'; break; + case 'x': + while ((spechr[c = *p] & C_HEX)) { + val = val * 16 + dig2num(c); + p++; + } + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + p--; + while ((spechr[c = *p] & C_DIGIT)) { + val = val * 8 + (c - '0'); + p++; + } + break; + default: val = p[-1]; + } + + } else + val = p[-1]; + if (*p != '\'') + error("bad charcon"); + *yyp = ++p; + return val; +} + +static void +chknl(int ignore) +{ + void (*f)(const char *, ...); + int t; + + f = ignore ? warning : error; + if ((t = fastspc()) != '\n') { + if (t) { + f("newline expected"); + /* ignore rest of line */ + while ((t = inch()) >= 0 && t != '\n') + ; + } else + f("no newline at end of file"); + } + unch(t); +} + +static void +elsestmt(void) +{ + if (flslvl) { + if (elflvl > trulvl) + ; + else if (--flslvl!=0) + flslvl++; + else + trulvl++; + } else if (trulvl) { + flslvl++; + trulvl--; + } else + error("#else in non-conditional section"); + if (elslvl==trulvl+flslvl) + error("too many #else"); + elslvl=trulvl+flslvl; + chknl(1); +} + +static void +ifdefstmt(void) +{ + usch *bp; + int ch; + + if (!ISID0(ch = fastspc())) + error("bad #ifdef"); + bp = readid(ch); + + if (lookup(bp, FIND) == NULL) + flslvl++; + else + trulvl++; + chknl(0); +} + +static void +ifndefstmt(void) +{ + usch *bp; + int ch; + + if (!ISID0(ch = fastspc())) + error("bad #ifndef"); + bp = readid(ch); + if (lookup(bp, FIND) != NULL) + flslvl++; + else + trulvl++; + chknl(0); +} + +static void +endifstmt(void) +{ + if (flslvl) + flslvl--; + else if (trulvl) + trulvl--; + else + error("#endif in non-conditional section"); + if (flslvl == 0) + elflvl = 0; + elslvl = 0; + chknl(1); +} + +static void +ifstmt(void) +{ + exprline() ? trulvl++ : flslvl++; +} + +static void +elifstmt(void) +{ + if (flslvl == 0) + elflvl = trulvl; + if (flslvl) { + if (elflvl > trulvl) + ; + else if (--flslvl!=0) + flslvl++; + else if (exprline()) + trulvl++; + else + flslvl++; + } else if (trulvl) { + flslvl++; + trulvl--; + } else + error("#elif in non-conditional section"); +} + +/* save line into stringbuf */ +static usch * +savln(void) +{ + int c; + usch *cp = stringbuf; + + while ((c = inch()) != -1) { + if (c == '\n') { + unch(c); + break; + } + savch(c); + } + savch(0); + + return cp; +} + +static void +cpperror(void) +{ + usch *cp; + + cp = savln(); + error("#error %s", cp); + stringbuf = cp; +} + +static void +cppwarning(void) +{ + usch *cp; + + cp = savln(); + warning("#warning %s", cp); + stringbuf = cp; +} + +static void +undefstmt(void) +{ + struct symtab *np; + usch *bp; + int ch; + + if (!ISID0(ch = fastspc())) + error("bad #undef"); + bp = readid(ch); + if ((np = lookup(bp, FIND)) != NULL) + np->value = 0; + chknl(0); +} + +static void +identstmt(void) +{ + struct iobuf *ob = NULL; + struct symtab *sp; + usch *bp; + int ch; + + if (ISID0(ch = fastspc())) { + bp = readid(ch); + if ((sp = lookup(bp, FIND))) + ob = kfind(sp); + if (ob->buf[0] != '\"') + goto bad; + if (ob) + bufree(ob); + } else if (ch == '\"') { + faststr(ch, savch); + } else + goto bad; + chknl(1); + return; +bad: + error("bad #ident directive"); +} + +static void +pragmastmt(void) +{ + int ch; + + putstr((const usch *)"\n#pragma"); + while ((ch = inch()) != '\n' && ch > 0) + putch(ch); + unch(ch); + prtline(1); +} + +int +cinput(void) +{ + + return inch(); +} + +#define DIR_FLSLVL 001 +#define DIR_FLSINC 002 +static struct { + const char *name; + void (*fun)(void); + int flags; +} ppd[] = { + { "ifndef", ifndefstmt, DIR_FLSINC }, + { "ifdef", ifdefstmt, DIR_FLSINC }, + { "if", ifstmt, DIR_FLSINC }, + { "include", include, 0 }, + { "else", elsestmt, DIR_FLSLVL }, + { "endif", endifstmt, DIR_FLSLVL }, + { "error", cpperror, 0 }, + { "warning", cppwarning, 0 }, + { "define", define, 0 }, + { "undef", undefstmt, 0 }, + { "line", line, 0 }, + { "pragma", pragmastmt, 0 }, + { "elif", elifstmt, DIR_FLSLVL }, + { "ident", identstmt, 0 }, +#ifdef GCC_COMPAT + { "include_next", include_next, 0 }, +#endif +}; +#define NPPD (int)(sizeof(ppd) / sizeof(ppd[0])) + +static void +skpln(void) +{ + int ch; + + /* just ignore the rest of the line */ + while ((ch = inch()) != -1) { + if (ch == '\n') { + unch('\n'); + break; + } + } +} + +/* + * do an even faster scan than fastscan while at flslvl. + * just search for a new directive. + */ +static void +flscan(void) +{ + int ch; + + for (;;) { + switch (ch = inch()) { + case -1: + return; + case '\n': + ifiles->lineno++; + putch('\n'); + if ((ch = fastspcg()) == '#') + return; + unch(ch); + break; + case '/': + fastcmnt(0); /* may be around directives */ + break; + } + } +} + + +/* + * Handle a preprocessor directive. + * # is already found. + */ +void +ppdir(void) +{ + int ch, i, oldC; + usch *bp; + + oldC = Cflag; +redo: Cflag = 0; + if ((ch = fastspc()) == '\n') { /* empty directive */ + unch(ch); + Cflag = oldC; + return; + } + Cflag = oldC; + if ((spechr[ch] & C_ID0) == 0) + goto out; + bp = readid(ch); + + /* got some keyword */ + for (i = 0; i < NPPD; i++) { + if (bp[0] == ppd[i].name[0] && + strcmp((char *)bp, ppd[i].name) == 0) { + if (flslvl == 0) { + (*ppd[i].fun)(); + if (flslvl == 0) + return; + } else { + if (ppd[i].flags & DIR_FLSLVL) { + (*ppd[i].fun)(); + if (flslvl == 0) + return; + }else if (ppd[i].flags & DIR_FLSINC) + flslvl++; + } + flscan(); + goto redo; + } + } + flscan(); + goto redo; + +out: + if (flslvl == 0 && Aflag == 0) + error("invalid preprocessor directive"); + + unch(ch); + skpln(); +} diff --git a/lang/pcc/pcc/cc/cxxcom/Makefile.in b/lang/pcc/pcc/cc/cxxcom/Makefile.in new file mode 100644 index 000000000..b2b2ec029 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/Makefile.in @@ -0,0 +1,186 @@ +# $Id: Makefile.in,v 1.7 2016/03/08 18:42:13 ragge Exp $ +# +# Makefile.in for cxxcom +# +VPATH=@srcdir@ +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +builddir=@builddir@ +top_builddir=@top_builddir@ +CC = @CC@ +EXEEXT = @EXEEXT@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ @ADD_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -D_ISOC99_SOURCE -DLANG_CXX \ + -Dos_$(TARGOS) -Dmach_$(TARGMACH) \ + -I$(srcdir) -I$(builddir) -I$(top_builddir) -I$(MIPDIR) -I$(MDIR) \ + -I$(top_srcdir)/os/$(TARGOS) -I$(COMMONDIR) +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LFLAGS = +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +TARGOS = @targos@ +TARGOSVER = @targosver@ +TARGMACH = @targmach@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +mandir = @mandir@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +MDIR=$(top_srcdir)/arch/$(TARGMACH) +MIPDIR=$(top_srcdir)/mip +COMMONDIR=$(top_srcdir)/common + +DEST=@BINPREFIX@cxxcom$(EXEEXT) +MANPAGE=@BINPREFIX@cxxcom +MKEXT=mkext$(EXEEXT) + +all: $(DEST) + +OBJS= builtins.o cgram.o code.o common.o compat.o external.o \ + gcc_compat.o init.o inline.o local.o local2.o main.o cxxcode.o \ + match.o optim.o optim2.o order.o pftn.o reader.o \ + regs.o scan.o stabs.o symtabs.o table.o trees.o + +LOBJS= mkext.lo common.lo table.lo + +HDRS= $(srcdir)/pass1.h $(MIPDIR)/pass2.h $(MIPDIR)/manifest.h \ + $(MDIR)/macdefs.h $(MIPDIR)/node.h $(COMMONDIR)/compat.h + +# +# round 1: generate external.[ch], cgram.[ch] & scan.c +# + +$(LOBJS): $(HDRS) + +mkext.lo: $(MIPDIR)/mkext.c + $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/mkext.c + +common.lo: $(MIPDIR)/common.c + $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/common.c + +table.lo: $(MDIR)/table.c + $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MDIR)/table.c + +$(MKEXT): $(LOBJS) + $(CC_FOR_BUILD) $(LDFLAGS) $(LOBJS) -o $@ $(LIBS) + +external.c: $(MKEXT) + $(builddir)/$(MKEXT) + +cgram.c: $(srcdir)/cgram.y + $(YACC) $(YFLAGS) -d $(srcdir)/cgram.y + mv -f y.tab.c cgram.c + mv -f y.tab.h cgram.h + +scan.c: $(srcdir)/scan.l + $(LEX) $(LFLAGS) $(srcdir)/scan.l + mv -f $(LEX_OUTPUT_ROOT).c scan.c + +# +# round 2: compile $(OBJS) +# + +$(OBJS): $(HDRS) external.c cgram.c + +builtins.o: $(srcdir)/builtins.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/builtins.c + +cgram.o: cgram.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ cgram.c + +code.o: $(MDIR)/code.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/code.c + +common.o: $(MIPDIR)/common.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c + +compat.o: $(COMMONDIR)/compat.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c + +cxxcode.o: $(srcdir)/cxxcode.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cxxcode.c + +external.o: external.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ external.c + +gcc_compat.o: $(srcdir)/gcc_compat.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/gcc_compat.c + +init.o: $(srcdir)/init.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/init.c + +inline.o: $(srcdir)/inline.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/inline.c + +local.o: $(MDIR)/local.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local.c + +local2.o: $(MDIR)/local2.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local2.c + +main.o: $(srcdir)/main.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c + +match.o: $(MIPDIR)/match.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/match.c + +optim.o: $(srcdir)/optim.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/optim.c + +optim2.o: $(MIPDIR)/optim2.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/optim2.c + +order.o: $(MDIR)/order.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/order.c + +pftn.o: $(srcdir)/pftn.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/pftn.c + +reader.o: $(MIPDIR)/reader.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/reader.c + +regs.o: $(MIPDIR)/regs.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/regs.c + +scan.o: scan.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ scan.c + +stabs.o: $(srcdir)/stabs.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/stabs.c + +symtabs.o: $(srcdir)/symtabs.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/symtabs.c + +table.o: $(MDIR)/table.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/table.c + +trees.o: $(srcdir)/trees.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/trees.c + +# +# round 3: build $(DEST) +# + +$(DEST): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) + +install: $(DEST) + test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)" + $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir) + test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1" +# $(INSTALL_DATA) $(srcdir)/ccom.1 $(DESTDIR)$(mandir)/man1/$(MANPAGE).1 + +clean: + rm -f $(DEST) $(OBJS) $(MKEXT) $(LOBJS) $(LEX_OUTPUT_ROOT).c \ + scan.c y.tab.[ch] cgram.[ch] external.[ch] + +distclean: clean + rm -f Makefile diff --git a/lang/pcc/pcc/cc/cxxcom/builtins.c b/lang/pcc/pcc/cc/cxxcom/builtins.c new file mode 100644 index 000000000..f863be3e8 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/builtins.c @@ -0,0 +1,808 @@ +/* $Id: builtins.c,v 1.7 2016/03/05 15:31:25 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + +#ifndef NO_C_BUILTINS + +/* + * replace an alloca function with direct allocation on stack. + * return a destination temp node. + */ +static NODE * +builtin_alloca(const struct bitable *bt, NODE *a) +{ + NODE *t, *u; + +#ifdef notyet + if (xnobuiltins) + return NULL; +#endif + + t = tempnode(0, VOID|PTR, 0, 0); + u = tempnode(regno(t), VOID|PTR, 0, 0); + spalloc(t, a, SZCHAR); + return u; +} + +/* + * Determine if a value is known to be constant at compile-time and + * hence that PCC can perform constant-folding on expressions involving + * that value. + */ +static NODE * +builtin_constant_p(const struct bitable *bt, NODE *a) +{ + void putjops(NODE *p, void *arg); + NODE *f; + int isconst; + + walkf(a, putjops, 0); + for (f = a; f->n_op == COMOP; f = f->n_right) + ; + isconst = nncon(f); + tfree(a); + return bcon(isconst); +} + +/* + * Hint to the compiler whether this expression will evaluate true or false. + * Just ignored for now. + */ +static NODE * +builtin_expect(const struct bitable *bt, NODE *a) +{ + NODE *f; + + if (a && a->n_op == CM) { + tfree(a->n_right); + f = a->n_left; + nfree(a); + a = f; + } + + return a; +} + +/* + * Take integer absolute value. + * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1))) + */ +static NODE * +builtin_abs(const struct bitable *bt, NODE *a) +{ + NODE *p, *q, *r, *t, *t2, *t3; + int tmp1, tmp2, shift; + + if (a->n_type != INT) + a = cast(a, INT, 0); + + if (a->n_op == ICON) { + if (getlval(a) < 0) + setlval(a, -getlval(a)); + p = a; + } else { + t = tempnode(0, a->n_type, a->n_df, a->n_ap); + tmp1 = regno(t); + p = buildtree(ASSIGN, t, a); + + t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); + shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1; + q = buildtree(RS, t, bcon(shift)); + + t2 = tempnode(0, a->n_type, a->n_df, a->n_ap); + tmp2 = regno(t2); + q = buildtree(ASSIGN, t2, q); + + t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); + t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); + t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); + r = buildtree(MINUS, buildtree(ER, t, t2), t3); + + p = buildtree(COMOP, p, buildtree(COMOP, q, r)); + } + + return p; +} + +#define cmop(x,y) buildtree(COMOP, x, y) +#define lblnod(l) nlabel(l) + +#ifndef TARGET_CXZ +/* + * Find number of beginning 0's in a word of type t. + * t should be deunsigned. + */ +static NODE * +builtin_cxz(NODE *a, TWORD t, int isclz) +{ + NODE *t101, *t102; + NODE *rn, *p; + int l15, l16, l17; + int sz; + + t = ctype(t); + sz = (int)tsize(t, 0, 0); + + t101 = tempnode(0, INT, 0, 0); + t102 = tempnode(0, t, 0, 0); + l15 = getlab(); + l16 = getlab(); + l17 = getlab(); + rn = buildtree(ASSIGN, ccopy(t102), a); + rn = cmop(rn, buildtree(ASSIGN, ccopy(t101), bcon(0))); + rn = cmop(rn, lblnod(l16)); + + p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15)); + rn = cmop(rn, p); + if (isclz) { + p = buildtree(CBRANCH, + buildtree(GE, ccopy(t102), bcon(0)), bcon(l17)); + } else { + p = buildtree(CBRANCH, + buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), + bcon(0)), bcon(l17)); + } + rn = cmop(rn, p); + + rn = cmop(rn, block(GOTO, bcon(l15), NIL, INT, 0, 0)); + + rn = cmop(rn, lblnod(l17)); + rn = cmop(rn, buildtree(isclz ? LSEQ : RSEQ , t102, bcon(1))); + + rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); + + rn = cmop(rn, block(GOTO, bcon(l16), NIL, INT, 0, 0)); + rn = cmop(rn, lblnod(l15)); + return cmop(rn, t101); +} + +static NODE * +builtin_clz(const struct bitable *bt, NODE *a) +{ + return builtin_cxz(a, INT, 1); +} + +static NODE * +builtin_clzl(const struct bitable *bt, NODE *a) +{ + return builtin_cxz(a, LONG, 1); +} + +static NODE * +builtin_clzll(const struct bitable *bt, NODE *a) +{ + return builtin_cxz(a, LONGLONG, 1); +} + +static NODE * +builtin_ctz(const struct bitable *bt, NODE *a) +{ + return builtin_cxz(a, INT, 0); +} + +static NODE * +builtin_ctzl(const struct bitable *bt, NODE *a) +{ + return builtin_cxz(a, LONG, 0); +} + +static NODE * +builtin_ctzll(const struct bitable *bt, NODE *a) +{ + return builtin_cxz(a, LONGLONG, 0); +} +#endif + +#ifndef TARGET_FFS +/* + * Find number of beginning 0's in a word of type t. + * t should be deunsigned. + */ +static NODE * +builtin_ff(NODE *a, TWORD t) +{ + NODE *t101, *t102; + NODE *rn, *p; + int l15, l16, l17; + int sz; + + t = ctype(t); + sz = (int)tsize(t, 0, 0)+1; + + t101 = tempnode(0, INT, 0, 0); + t102 = tempnode(0, t, 0, 0); + l15 = getlab(); + l16 = getlab(); + l17 = getlab(); + rn = buildtree(ASSIGN, ccopy(t101), bcon(0)); + rn = cmop(rn, buildtree(ASSIGN, ccopy(t102), a)); + + p = buildtree(CBRANCH, buildtree(EQ, ccopy(t102), bcon(0)), bcon(l15)); + rn = cmop(rn, p); + + rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); + + rn = cmop(rn, lblnod(l16)); + + p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15)); + rn = cmop(rn, p); + + p = buildtree(CBRANCH, + buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), + bcon(0)), bcon(l17)); + rn = cmop(rn, p); + + rn = cmop(rn, block(GOTO, bcon(l15), NIL, INT, 0, 0)); + + rn = cmop(rn, lblnod(l17)); + rn = cmop(rn, buildtree(RSEQ, t102, bcon(1))); + + rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); + + rn = cmop(rn, block(GOTO, bcon(l16), NIL, INT, 0, 0)); + rn = cmop(rn, lblnod(l15)); + return cmop(rn, t101); +} + +static NODE * +builtin_ffs(const struct bitable *bt, NODE *a) +{ + return builtin_ff(a, INT); +} + +static NODE * +builtin_ffsl(const struct bitable *bt, NODE *a) +{ + return builtin_ff(a, LONG); +} + +static NODE * +builtin_ffsll(const struct bitable *bt, NODE *a) +{ + return builtin_ff(a, LONGLONG); +} +#endif + +/* + * Get size of object, if possible. + * Currently does nothing, + */ +static NODE * +builtin_object_size(const struct bitable *bt, NODE *a) +{ + CONSZ v = icons(a->n_right); + NODE *f; + + if (v < 0 || v > 3) + uerror("arg2 must be between 0 and 3"); + + f = buildtree(COMOP, a->n_left, xbcon(v < 2 ? -1 : 0, NULL, bt->rt)); + nfree(a); + return f; +} + +#ifndef TARGET_STDARGS +static NODE * +builtin_stdarg_start(const struct bitable *bt, NODE *a) +{ + NODE *p, *q; + int sz; + + /* must first deal with argument size; use int size */ + p = a->n_right; + if (p->n_type < INT) { + sz = (int)(SZINT/tsize(p->n_type, p->n_df, p->n_ap)); + } else + sz = 1; + + /* do the real job */ + p = buildtree(ADDROF, p, NIL); /* address of last arg */ +#ifdef BACKAUTO + p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */ +#else + p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */ +#endif + q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); /* create cast node */ + q = buildtree(CAST, q, p); /* cast to void * (for assignment) */ + p = q->n_right; + nfree(q->n_left); + nfree(q); + p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */ + nfree(a); + return p; +} + +static NODE * +builtin_va_arg(const struct bitable *bt, NODE *a) +{ + NODE *p, *q, *r, *rv; + int sz, nodnum; + + /* create a copy to a temp node of current ap */ + p = ccopy(a->n_left); + q = tempnode(0, p->n_type, p->n_df, p->n_ap); + nodnum = regno(q); + rv = buildtree(ASSIGN, q, p); + + r = a->n_right; + sz = (int)tsize(r->n_type, r->n_df, r->n_ap)/SZCHAR; + /* add one to ap */ +#ifdef BACKAUTO + rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz))); +#else +#error fix wrong eval order in builtin_va_arg + ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz))); +#endif + + nfree(a->n_right); + nfree(a); + r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_ap); + return buildtree(COMOP, rv, buildtree(UMUL, r, NIL)); + +} + +static NODE * +builtin_va_end(const struct bitable *bt, NODE *a) +{ + tfree(a); + return bcon(0); /* nothing */ +} + +static NODE * +builtin_va_copy(const struct bitable *bt, NODE *a) +{ + NODE *f; + + f = buildtree(ASSIGN, a->n_left, a->n_right); + nfree(a); + return f; +} +#endif /* TARGET_STDARGS */ + +/* + * For unimplemented "builtin" functions, try to invoke the + * non-builtin name + */ +static NODE * +binhelp(NODE *a, TWORD rt, char *n) +{ + NODE *f = block(NAME, NIL, NIL, INT, 0, 0); + + f->n_sp = lookup(addname(n), SNORMAL); + if (f->n_sp->sclass == SNULL) { + f->n_sp->sclass = EXTERN; + f->n_sp->stype = INCREF(rt)+(FTN-PTR); + } + f->n_type = f->n_sp->stype; + f = clocal(f); + return buildtree(CALL, f, a); +} + +static NODE * +builtin_unimp(const struct bitable *bt, NODE *a) +{ + return binhelp(a, bt->rt, &bt->name[10]); +} + +#if 0 +static NODE * +builtin_unimp_f(NODE *f, NODE *a, TWORD rt) +{ + return binhelp(f, a, rt, f->n_sp->sname); +} +#endif + +#ifndef TARGET_PREFETCH +static NODE * +builtin_prefetch(const struct bitable *bt, NODE *a) +{ + tfree(a); + return bcon(0); +} +#endif + +#ifndef TARGET_ISMATH +/* + * Handle the builtin macros for the math functions is* + * To get something that is be somewhat generic assume that + * isnan() is a real function and that cast of a NaN type + * to double will still be a NaN. + */ +static NODE * +mtisnan(NODE *p) +{ + + return binhelp(cast(ccopy(p), DOUBLE, 0), INT, "isnan"); +} + +static TWORD +mtcheck(NODE *p) +{ + TWORD t1 = p->n_left->n_type, t2 = p->n_right->n_type; + + if ((t1 >= FLOAT && t1 <= LDOUBLE) || + (t2 >= FLOAT && t2 <= LDOUBLE)) + return MAX(t1, t2); + return 0; +} + +static NODE * +builtin_isunordered(const struct bitable *bt, NODE *a) +{ + NODE *p; + + if (mtcheck(a) == 0) + return bcon(0); + + p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); + tfree(a); + return p; +} +static NODE * +builtin_isany(NODE *a, TWORD rt, int cmpt) +{ + NODE *p, *q; + TWORD t; + + if ((t = mtcheck(a)) == 0) + return bcon(0); + p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); + p = buildtree(NOT, p, NIL); + q = buildtree(cmpt, cast(ccopy(a->n_left), t, 0), + cast(ccopy(a->n_right), t, 0)); + p = buildtree(ANDAND, p, q); + tfree(a); + return p; +} +static NODE * +builtin_isgreater(const struct bitable *bt, NODE *a) +{ + return builtin_isany(a, bt->rt, GT); +} +static NODE * +builtin_isgreaterequal(const struct bitable *bt, NODE *a) +{ + return builtin_isany(a, bt->rt, GE); +} +static NODE * +builtin_isless(const struct bitable *bt, NODE *a) +{ + return builtin_isany(a, bt->rt, LT); +} +static NODE * +builtin_islessequal(const struct bitable *bt, NODE *a) +{ + return builtin_isany(a, bt->rt, LE); +} +static NODE * +builtin_islessgreater(const struct bitable *bt, NODE *a) +{ + NODE *p, *q, *r; + TWORD t; + + if ((t = mtcheck(a)) == 0) + return bcon(0); + p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); + p = buildtree(NOT, p, NIL); + q = buildtree(GT, cast(ccopy(a->n_left), t, 0), + cast(ccopy(a->n_right), t, 0)); + r = buildtree(LT, cast(ccopy(a->n_left), t, 0), + cast(ccopy(a->n_right), t, 0)); + q = buildtree(OROR, q, r); + p = buildtree(ANDAND, p, q); + tfree(a); + return p; +} +#endif + +/* + * Math-specific builtins that expands to constants. + * Versins here is for IEEE FP, vax needs its own versions. + */ +#if TARGET_ENDIAN == TARGET_LE +static const unsigned char vFLOAT[] = { 0, 0, 0x80, 0x7f }; +static const unsigned char vDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }; +#ifdef LDBL_128 +static const unsigned char vLDOUBLE[] = { 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f }; +#else /* LDBL_80 */ +static const unsigned char vLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f }; +#endif +static const unsigned char nFLOAT[] = { 0, 0, 0xc0, 0x7f }; +static const unsigned char nDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f }; +#ifdef LDBL_128 +static const unsigned char nLDOUBLE[] = { 0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f }; +#else /* LDBL_80 */ +static const unsigned char nLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f, 0, 0 }; +#endif +#else +static const unsigned char vFLOAT[] = { 0x7f, 0x80, 0, 0 }; +static const unsigned char vDOUBLE[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }; +#ifdef LDBL_128 +static const unsigned char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 }; +#else /* LDBL_80 */ +static const unsigned char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0 }; +#endif +static const unsigned char nFLOAT[] = { 0x7f, 0xc0, 0, 0 }; +static const unsigned char nDOUBLE[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 }; +#ifdef LDBL_128 +static const unsigned char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 }; +#else /* LDBL_80 */ +static const unsigned char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0 }; +#endif +#endif + +#define VALX(typ,TYP) { \ + typ d; \ + int x; \ + NODE *f; \ + x = MIN(sizeof(n ## TYP), sizeof(d)); \ + memcpy(&d, v ## TYP, x); \ + f = block(FCON, NIL, NIL, TYP, NULL, 0); \ + f->n_dcon = fltallo(); \ + ((FLT *)f->n_dcon)->fp = d; \ + return f; \ +} + +static NODE * +builtin_huge_valf(const struct bitable *bt, NODE *a) VALX(float,FLOAT) +static NODE * +builtin_huge_val(const struct bitable *bt, NODE *a) VALX(double,DOUBLE) +static NODE * +builtin_huge_vall(const struct bitable *bt, NODE *a) VALX(long double,LDOUBLE) + +#define builtin_inff builtin_huge_valf +#define builtin_inf builtin_huge_val +#define builtin_infl builtin_huge_vall + +/* + * Return NANs, if reasonable. + */ +static NODE * +builtin_nanx(const struct bitable *bt, NODE *a) +{ + if (a == NULL || a->n_op == CM) { + uerror("%s bad argument", bt->name); + a = bcon(0); + } else if (a->n_op == STRING && *a->n_name == '\0') { + a->n_op = FCON; + a->n_type = bt->rt; + a->n_dcon = fltallo(); + memcpy(&FCAST(a->n_dcon)->fp, nLDOUBLE, sizeof(long double)); + } else + a = binhelp(eve(a), bt->rt, &bt->name[10]); + return a; +} + +/* + * Target defines, to implement target versions of the generic builtins + */ +#ifndef TARGET_MEMCMP +#define builtin_memcmp builtin_unimp +#endif +#ifndef TARGET_MEMCPY +#define builtin_memcpy builtin_unimp +#endif +#ifndef TARGET_MEMPCPY +#define builtin_mempcpy builtin_unimp +#endif +#ifndef TARGET_MEMSET +#define builtin_memset builtin_unimp +#endif + +/* Reasonable type of size_t */ +#ifndef SIZET +#if SZINT == SZSHORT +#define SIZET UNSIGNED +#elif SZLONG > SZINT +#define SIZET ULONG +#else +#define SIZET UNSIGNED +#endif +#endif + +static TWORD memcpyt[] = { VOID|PTR, VOID|PTR, SIZET, INT }; +static TWORD memsett[] = { VOID|PTR, INT, SIZET, INT }; +static TWORD allocat[] = { SIZET }; +static TWORD expectt[] = { LONG, LONG }; +static TWORD strcmpt[] = { CHAR|PTR, CHAR|PTR }; +static TWORD strcpyt[] = { CHAR|PTR, CHAR|PTR, INT }; +static TWORD strncpyt[] = { CHAR|PTR, CHAR|PTR, SIZET, INT }; +static TWORD strchrt[] = { CHAR|PTR, INT }; +static TWORD strcspnt[] = { CHAR|PTR, CHAR|PTR }; +static TWORD strspnt[] = { CHAR|PTR, CHAR|PTR }; +static TWORD strpbrkt[] = { CHAR|PTR, CHAR|PTR }; +static TWORD nant[] = { CHAR|PTR }; +static TWORD bitt[] = { UNSIGNED }; +static TWORD bitlt[] = { ULONG }; +static TWORD bitllt[] = { ULONGLONG }; +static TWORD abst[] = { INT }; + +static const struct bitable bitable[] = { + { "__builtin___memcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, + { "__builtin___mempcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, + { "__builtin___memmove_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, + { "__builtin___memset_chk", builtin_unimp, 0, 4, memsett, VOID|PTR }, + + { "__builtin___strcat_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR }, + { "__builtin___strcpy_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR }, + { "__builtin___strncat_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR }, + { "__builtin___strncpy_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR }, + + { "__builtin___printf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___fprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___sprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___snprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___vprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___vfprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___vsprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + { "__builtin___vsnprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, + + { "__builtin_alloca", builtin_alloca, 0, 1, allocat, VOID|PTR }, + { "__builtin_abs", builtin_abs, 0, 1, abst, INT }, + { "__builtin_clz", builtin_clz, 0, 1, bitt, INT }, + { "__builtin_clzl", builtin_clzl, 0, 1, bitlt, INT }, + { "__builtin_clzll", builtin_clzll, 0, 1, bitllt, INT }, + { "__builtin_ctz", builtin_ctz, 0, 1, bitt, INT }, + { "__builtin_ctzl", builtin_ctzl, 0, 1, bitlt, INT }, + { "__builtin_ctzll", builtin_ctzll, 0, 1, bitllt, INT }, + { "__builtin_ffs", builtin_ffs, 0, 1, bitt, INT }, + { "__builtin_ffsl", builtin_ffsl, 0, 1, bitlt, INT }, + { "__builtin_ffsll", builtin_ffsll, 0, 1, bitllt, INT }, + { "__builtin_popcount", builtin_unimp, 0, 1, bitt, UNSIGNED }, + { "__builtin_popcountl", builtin_unimp, 0, 1, bitlt, ULONG }, + { "__builtin_popcountll", builtin_unimp, 0, 1, bitllt, ULONGLONG }, + + { "__builtin_constant_p", builtin_constant_p, 0, 1, 0, INT }, + { "__builtin_expect", builtin_expect, 0, 2, expectt, LONG }, + { "__builtin_memcmp", builtin_memcmp, 0, 3, memcpyt, INT }, + { "__builtin_memcpy", builtin_memcpy, 0, 3, memcpyt, VOID|PTR }, + { "__builtin_mempcpy", builtin_mempcpy, 0, 3, memcpyt, VOID|PTR }, + { "__builtin_memset", builtin_memset, 0, 3, memsett, VOID|PTR }, + { "__builtin_huge_valf", builtin_huge_valf, 0, 0, 0, FLOAT }, + { "__builtin_huge_val", builtin_huge_val, 0, 0, 0, DOUBLE }, + { "__builtin_huge_vall", builtin_huge_vall, 0, 0, 0, LDOUBLE }, + { "__builtin_inff", builtin_inff, 0, 0, 0, FLOAT }, + { "__builtin_inf", builtin_inf, 0, 0, 0, DOUBLE }, + { "__builtin_infl", builtin_infl, 0, 0, 0, LDOUBLE }, + { "__builtin_isgreater", builtin_isgreater, 0, 2, NULL, INT }, + { "__builtin_isgreaterequal", builtin_isgreaterequal, 0, 2, NULL, INT }, + { "__builtin_isless", builtin_isless, 0, 2, NULL, INT }, + { "__builtin_islessequal", builtin_islessequal, 0, 2, NULL, INT }, + { "__builtin_islessgreater", builtin_islessgreater, 0, 2, NULL, INT }, + { "__builtin_isunordered", builtin_isunordered, 0, 2, NULL, INT }, + { "__builtin_nanf", builtin_nanx, BTNOEVE, 1, nant, FLOAT }, + { "__builtin_nan", builtin_nanx, BTNOEVE, 1, nant, DOUBLE }, + { "__builtin_nanl", builtin_nanx, BTNOEVE, 1, nant, LDOUBLE }, + { "__builtin_object_size", builtin_object_size, 0, 2, memsett, SIZET }, + { "__builtin_prefetch", builtin_prefetch, 0, 1, memsett, VOID }, + { "__builtin_strcmp", builtin_unimp, 0, 2, strcmpt, INT }, + { "__builtin_strcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR }, + { "__builtin_stpcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR }, + { "__builtin_strchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR }, + { "__builtin_strlen", builtin_unimp, 0, 1, strcmpt, SIZET }, + { "__builtin_strrchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR }, + { "__builtin_strncpy", builtin_unimp, 0, 3, strncpyt, CHAR|PTR }, + { "__builtin_strncat", builtin_unimp, 0, 3, strncpyt, CHAR|PTR }, + { "__builtin_strcspn", builtin_unimp, 0, 2, strcspnt, SIZET }, + { "__builtin_strspn", builtin_unimp, 0, 2, strspnt, SIZET }, + { "__builtin_strstr", builtin_unimp, 0, 2, strcmpt, CHAR|PTR }, + { "__builtin_strpbrk", builtin_unimp, 0, 2, strpbrkt, CHAR|PTR }, +#ifndef TARGET_STDARGS + { "__builtin_stdarg_start", builtin_stdarg_start, 0, 2, 0, VOID }, + { "__builtin_va_start", builtin_stdarg_start, 0, 2, 0, VOID }, + { "__builtin_va_arg", builtin_va_arg, BTNORVAL|BTNOPROTO, 2, 0, 0 }, + { "__builtin_va_end", builtin_va_end, 0, 1, 0, VOID }, + { "__builtin_va_copy", builtin_va_copy, 0, 2, 0, VOID }, +#endif +#ifdef TARGET_BUILTINS + TARGET_BUILTINS +#endif +}; + +/* + * Check and cast arguments for builtins. + */ +static int +acnt(NODE *a, int narg, TWORD *tp) +{ + NODE *q; + TWORD t; + + if (a == NIL) + return narg; + for (; a->n_op == CM; a = a->n_left, narg--) { + if (tp == NULL) + continue; + q = a->n_right; + t = ctype(tp[narg-1]); + if (q->n_type == t) + continue; + a->n_right = ccast(q, t, 0, NULL, 0); + } + + /* Last arg is ugly to deal with */ + if (narg == 1 && tp != NULL && a->n_type != tp[0]) { + q = talloc(); + *q = *a; + q = ccast(q, ctype(tp[0]), 0, NULL, 0); + *a = *q; + nfree(q); + } + return narg != 1; +} + +NODE * +builtin_check(struct symtab *sp, NODE *a) +{ + const struct bitable *bt; + + if (sp->soffset < 0 || + sp->soffset >= (int)(sizeof(bitable)/sizeof(bitable[0]))) + cerror("builtin_check"); + + bt = &bitable[sp->soffset]; + if ((bt->flags & BTNOEVE) == 0) + a = eve(a); + if (((bt->flags & BTNOPROTO) == 0) && acnt(a, bt->narg, bt->tp)) { + uerror("wrong argument count to %s", bt->name); + return bcon(0); + } + return (*bt->fun)(bt, a); +} + +/* + * Put all builtin functions into the global symbol table. + */ +void +builtin_init() +{ + const struct bitable *bt; + NODE *p = block(TYPE, 0, 0, 0, 0, 0); + struct symtab *sp; + int i; + + for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) { + bt = &bitable[i]; + sp = lookup(addname(bt->name), 0); + if (bt->rt == 0 && (bt->flags & BTNORVAL) == 0) + cerror("function '%s' has no return type", bt->name); + p->n_type = INCREF(bt->rt) + (FTN-PTR); + p->n_sp = sp; + defid(p, EXTDEF); + sp->soffset = i; + sp->sflags |= SBUILTIN; + } + nfree(p); +} +#endif diff --git a/lang/pcc/pcc/cc/cxxcom/cgram.y b/lang/pcc/pcc/cc/cxxcom/cgram.y new file mode 100644 index 000000000..9419a610a --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/cgram.y @@ -0,0 +1,2548 @@ +/* $Id: cgram.y,v 1.9 2015/11/24 17:30:20 ragge Exp $ */ + +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 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. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ + +/* + * Comments for this grammar file. Ragge 021123 + * + * ANSI support required rewrite of the function header and declaration + * rules almost totally. + * + * The lex/yacc shared keywords are now split from the keywords used + * in the rest of the compiler, to simplify use of other frontends. + */ + +/* + * At last count, there were 5 shift/reduce and no reduce/reduce conflicts + * Four are accounted for; + * One is "dangling else" + * Two is in attribute parsing + * One is in ({ }) parsing + */ + +/* + * Token used in C lex/yacc communications. + */ +%token C_STRING /* a string constant */ +%token C_ICON /* an integer constant */ +%token C_FCON /* a floating point constant */ +%token C_NAME /* an identifier */ +%token C_TYPENAME /* a typedef'd name */ +%token C_ANDAND /* && */ +%token C_OROR /* || */ +%token C_GOTO /* unconditional goto */ +%token C_RETURN /* return from function */ +%token C_TYPE /* a type */ +%token C_CLASS /* a storage class */ +%token C_ASOP /* assignment ops */ +%token C_RELOP /* <=, <, >=, > */ +%token C_EQUOP /* ==, != */ +%token C_DIVOP /* /, % */ +%token C_SHIFTOP /* <<, >> */ +%token C_INCOP /* ++, -- */ +%token C_UNOP /* !, ~ */ +%token C_STROP /* ., -> */ +%token C_STRUCT +%token C_IF +%token C_ELSE +%token C_SWITCH +%token C_BREAK +%token C_CONTINUE +%token C_WHILE +%token C_DO +%token C_FOR +%token C_DEFAULT +%token C_CASE +%token C_SIZEOF +%token C_ALIGNOF +%token C_ENUM +%token C_ELLIPSIS +%token C_QUALIFIER +%token C_FUNSPEC +%token C_ASM +%token NOMATCH +%token C_TYPEOF /* COMPAT_GCC */ +%token C_ATTRIBUTE /* COMPAT_GCC */ +%token PCC_OFFSETOF +%token GCC_DESIG +%token CXX_NAMESPACE +%token CXX_DUALCC +%token CXX_TEMPLATE +%token CXX_USING +%token CXX_TYPENAME +%token CXX_CASTS +%token CXX_THROW +%token CXX_MORENM +%token CXX_NEW +%token CXX_DELETE +%token CXX_CLASS + +/* + * Precedence + */ +%left ',' +%right '=' C_ASOP +%right '?' ':' +%left C_OROR +%left C_ANDAND +%left '|' +%left '^' +%left '&' +%left C_EQUOP +%left C_RELOP +%left C_SHIFTOP +%left '+' '-' +%left '*' C_DIVOP +%right C_UNOP +%right C_INCOP C_SIZEOF +%left '[' '(' C_STROP +%{ +# include "pass1.h" +# include +# include +# include + +int fun_inline; /* Reading an inline function */ +int oldstyle; /* Current function being defined */ +static struct symtab *xnf; +extern int enummer, tvaloff, inattr; +extern struct rstack *rpole; +static int widestr, alwinl; +NODE *cftnod; +static int attrwarn = 1; + +#define NORETYP SNOCREAT /* no return type, save in unused field in symtab */ + + NODE *bdty(int op, ...); +static void fend(struct symtab *); +static struct symtab *fundef(NODE *tp, NODE *p); +static void olddecl(NODE *p, NODE *a); +static struct symtab *init_declarator(NODE *tn, NODE *p, int assign, NODE *a); +static void resetbc(int mask); +static void swend(void); +static void addcase(NODE *p); +#ifdef GCC_COMPAT +static void gcccase(NODE *p, NODE *); +#endif +static struct attr *gcc_attr_wrapper(NODE *p); +static void adddef(void); +static void savebc(void); +static void swstart(int, TWORD); +static void genswitch(int, TWORD, struct swents **, int); +static char *mkpstr(char *str); +static struct symtab *clbrace(NODE *); +static NODE *cmop(NODE *l, NODE *r); +static NODE *xcmop(NODE *out, NODE *in, NODE *str); +static void mkxasm(char *str, NODE *p); +static NODE *xasmop(char *str, NODE *p); +static int maxstlen(char *str); +static char *stradd(char *old, char *new); +static NODE *biop(int op, NODE *l, NODE *r); +static void flend(void); +static char * simname(char *s); +static NODE *tyof(NODE *); /* COMPAT_GCC */ +static NODE *voidcon(void); /* COMPAT_GCC */ +static NODE *funargs(NODE *p); +static void oldargs(NODE *p); +static void uawarn(NODE *p, char *s); +static int con_e(NODE *p); +static void dainit(NODE *d, NODE *a); +static NODE *tymfix(NODE *p); +static NODE *namekill(NODE *p, int clr); +static NODE *aryfix(NODE *p); + +#define TYMFIX(inp) { \ + NODE *pp = inp; \ + inp = tymerge(pp->n_left, pp->n_right); \ + nfree(pp->n_left); nfree(pp); } +/* + * State for saving current switch state (when nested switches). + */ +struct savbc { + struct savbc *next; + int brklab; + int contlab; + int flostat; + int swx; +} *savbc, *savctx; + +%} + +%union { + int intval; + NODE *nodep; + struct symtab *symp; + struct rstack *rp; + char *strp; +} + + /* define types */ +%start edf + +%type ifelprefix ifprefix whprefix forprefix doprefix switchpart + xbegin +%type e .e term enum_dcl struct_dcl cast_type declarator + elist type_sq cf_spec merge_attribs + parameter_declaration abstract_declarator initializer + parameter_type_list parameter_list addrlbl + declaration_specifiers designation + specifier_qualifier_list merge_specifiers + identifier_list arg_param_list type_qualifier_list + designator_list designator xasm oplist oper cnstr + typeof attribute attribute_specifier /* COMPAT_GCC */ + attribute_list attr_spec_list attr_var /* COMPAT_GCC */ + new_ma new_type_sq new_ds nmrec +%type string C_STRING GCC_DESIG nsname CXX_MORENM +%type str_head +%type xnfdeclarator clbrace enum_head funtype + +%type C_STRUCT C_RELOP C_DIVOP C_SHIFTOP + C_ANDAND C_OROR C_STROP C_INCOP C_UNOP C_ASOP C_EQUOP + +%type C_TYPE C_QUALIFIER C_ICON C_FCON C_CLASS +%type C_NAME C_TYPENAME +%% + +edf: ext_def_list + | { ftnend(); } + ; + +ext_def_list: ext_def_list external_def + | external_def + ; + +external_def: funtype kr_args compoundstmt { fend($1); } + | declaration { blevel = 0; symclear(0); } + | namespace + | extlink + | blockdcl + | ';' + | error { blevel = 0; } + ; + +funtype: /* no type given */ declarator { + $$ = fundef(mkty(INT, 0, 0), $1); + cftnsp->sflags |= NORETYP; + } + | declaration_specifiers declarator { $$ = fundef($1,$2); } + ; + +kr_args: /* empty */ + | arg_dcl_list + ; + +blockdcl: simple_decl + | asmstatement + | ns_alias + | using_x + ; + +using_x: CXX_USING tnopt ccopt nested_name_sp ';' { werror("using"); } + | CXX_USING CXX_NAMESPACE ccopt nested_name_sp ';' { werror("using2"); } + ; + +tnopt: CXX_TYPENAME { } + | { } + ; + +ns_alias: CXX_NAMESPACE C_NAME '=' qual_ns_sp ';' { werror("ns_alias");} + ; + +qual_ns_sp: ccopt nested_name_sp + ; + +nested_name_sp: nmtnm + | nmtnm CXX_DUALCC nested_name_sp + | nmtnm CXX_DUALCC CXX_TEMPLATE nested_name_sp + ; + +nmtnm: C_NAME + | C_TYPENAME + ; + +ccopt: CXX_DUALCC + | { } + ; + +simple_decl: ')' NOMATCH { uerror("simple-declaration"); } + ; + +namespace: CXX_NAMESPACE nsname attr_var nsbeg ns_body '}' { POPSYM(); } + ; + +nsname: C_NAME + | { $$ = NULL; } + ; + +ns_body: ext_def_list + | { } + ; + +nsbeg: '{' { dclns($0, $-1); } + ; + +extlink: C_CLASS C_STRING eb '{' ext_def_list '}' { elnk = LINK_DEF; } + | C_CLASS C_STRING eb '{' '}' { elnk = LINK_DEF; } + | C_CLASS C_STRING eb declaration { elnk = LINK_DEF; } + ; + +eb: { + NODE *p = $-1; + char *s = $0; + if (p->n_type != EXTERN) + uerror("'extern' expected"); + if (strcmp(s, "\"C\"") != 0 && strcmp(s, "\"c\"")) + uerror("unknown linkage %s", s); + nfree(p); + elnk = LINK_C; + } + ; +/* + * Returns a node pointer or NULL, if no types at all given. + * Type trees are checked for correctness and merged into one + * type node in typenode(). + */ +declaration_specifiers: + merge_attribs { $$ = typenode($1); } + ; + +merge_attribs: type_sq { $$ = $1; } + | type_sq merge_attribs { $$ = cmop($2, $1); } + | cf_spec { $$ = $1; } + | cf_spec merge_attribs { $$ = cmop($2, $1); } + ; + +type_sq: C_TYPE { $$ = $1; } + | C_TYPENAME { + struct symtab *sp = lookup($1, 0); + if (sp->stype == ENUMTY) { + sp->stype = strmemb(sp->sap)->stype; + } + $$ = mkty(sp->stype, sp->sdf, sp->sap); + $$->n_sp = sp; + } + | struct_dcl { $$ = $1; } + | enum_dcl { $$ = $1; } + | C_QUALIFIER { $$ = $1; } + | attribute_specifier { $$ = biop(ATTRIB, $1, 0); } + | typeof { $$ = $1; } + ; + +cf_spec: C_CLASS { $$ = $1; } + | C_FUNSPEC { fun_inline = 1; /* XXX - hack */ + $$ = block(QUALIFIER, NIL, NIL, 0, 0, 0); } + ; + +typeof: C_TYPEOF '(' e ')' { $$ = tyof(eve($3)); } + | C_TYPEOF '(' cast_type ')' { TYMFIX($3); $$ = tyof($3); } + ; + +new_ma: new_type_sq + | new_type_sq new_ma { $$ = cmop($2, $1); } + | cf_spec { $$ = $1; } + | cf_spec new_ma { $$ = cmop($2, $1); } + ; + +new_ds: new_ma { $$ = typenode($1); } + ; + +new_type_sq: C_TYPE { $$ = $1; } + | C_TYPENAME { + struct symtab *sp = lookup($1, 0); + if (sp->stype == ENUMTY) { + sp->stype = strmemb(sp->sap)->stype; + } + $$ = mkty(sp->stype, sp->sdf, sp->sap); + $$->n_sp = sp; + } + | struct_dcl { $$ = $1; } + | enum_dcl { $$ = $1; } + | C_QUALIFIER { $$ = $1; } + ; + +attribute_specifier : + C_ATTRIBUTE '(' '(' attribute_list ')' ')' { $$ = $4; } + /*COMPAT_GCC*/ ; + +attribute_list: attribute + | attribute ',' attribute_list { $$ = cmop($3, $1); } + ; + +attribute: { +#ifdef GCC_COMPAT + $$ = voidcon(); +#endif + } + | C_NAME { $$ = bdty(NAME, $1); } + | C_NAME '(' elist ')' { + $$ = bdty($3 == NIL ? UCALL : CALL, bdty(NAME, $1), $3); + } + ; + +/* + * Adds a pointer list to front of the declarators. + */ +declarator: '*' declarator { $$ = bdty(UMUL, $2); } + | '*' type_qualifier_list declarator { + $$ = $2; + $$->n_left = $3; + } + | nmrec C_NAME { $$ = biop(NMLIST, $1, bdty(NAME, $2)); } + | C_NAME { $$ = bdty(NAME, $1); } + | '(' attr_spec_list declarator ')' { + $$ = $3; + $$->n_ap = attr_add($$->n_ap, gcc_attr_wrapper($2)); + } + | '(' declarator ')' { $$ = $2; } + | declarator '[' e ']' { $$ = biop(LB, $1, $3); } + | declarator '[' C_CLASS e ']' { + if ($3->n_type != STATIC) + uerror("bad class keyword"); + tfree($3); /* XXX - handle */ + $$ = biop(LB, $1, $4); + } + | declarator '[' ']' { $$ = biop(LB, $1, bcon(NOOFFSET)); } + | declarator '[' '*' ']' { $$ = biop(LB, $1, bcon(NOOFFSET)); } + | declarator '(' parameter_type_list ')' { + $$ = bdty(CALL, $1, $3); + } + | declarator '(' identifier_list ')' { + $$ = bdty(CALL, $1, $3); + oldstyle = 1; + } + | declarator '(' ')' { $$ = bdty(UCALL, $1); } + ; + +type_qualifier_list: + C_QUALIFIER { $$ = $1; $$->n_op = UMUL; } + | type_qualifier_list C_QUALIFIER { + $$ = $1; + $$->n_qual |= $2->n_qual; + nfree($2); + } + | attribute_specifier { + $$ = block(UMUL, NIL, NIL, 0, 0, gcc_attr_wrapper($1)); + } + | type_qualifier_list attribute_specifier { + $1->n_ap = attr_add($1->n_ap, gcc_attr_wrapper($2)); + } + ; + +identifier_list: C_NAME { $$ = bdty(NAME, $1); oldargs($$); } + | identifier_list ',' C_NAME { + $$ = cmop($1, bdty(NAME, $3)); + oldargs($$->n_right); + } + ; + +/* + * Returns as parameter_list, but can add an additional ELLIPSIS node. + */ +parameter_type_list: + parameter_list { $$ = $1; } + | parameter_list ',' C_ELLIPSIS { + $$ = cmop($1, biop(ELLIPSIS, NIL, NIL)); + } + ; + +/* + * Returns a linked lists of nodes of op CM with parameters on + * its right and additional CM nodes of its left pointer. + * No CM nodes if only one parameter. + */ +parameter_list: parameter_declaration { $$ = $1; } + | parameter_declaration '&' { $$ = $1; } + | parameter_list ',' parameter_declaration { + $$ = cmop($1, $3); + } + ; + +/* + * Returns a node pointer to the declaration. + */ +parameter_declaration: + declaration_specifiers declarator attr_var { + if (glval($1) != SNULL && glval($1) != REGISTER) + uerror("illegal parameter class"); + $$ = block(TYMERGE, $1, $2, INT, 0, gcc_attr_wrapper($3)); + } + | declaration_specifiers abstract_declarator { + $$ = block(TYMERGE, $1, $2, INT, 0, 0); + } + | declaration_specifiers { + $$ = block(TYMERGE, $1, bdty(NAME, NULL), INT, 0, 0); + } + ; + +abstract_declarator: + '*' { $$ = bdty(UMUL, bdty(NAME, NULL)); } + | '*' type_qualifier_list { + $$ = $2; + $$->n_left = bdty(NAME, NULL); + } + | '*' abstract_declarator { $$ = bdty(UMUL, $2); } + | '*' type_qualifier_list abstract_declarator { + $$ = $2; + $$->n_left = $3; + } + | '(' abstract_declarator ')' { $$ = $2; } + | '[' ']' attr_var { + $$ = block(LB, bdty(NAME, NULL), bcon(NOOFFSET), + INT, 0, gcc_attr_wrapper($3)); + } + | '[' e ']' attr_var { + $$ = block(LB, bdty(NAME, NULL), $2, + INT, 0, gcc_attr_wrapper($4)); + } + | abstract_declarator '[' ']' attr_var { + $$ = block(LB, $1, bcon(NOOFFSET), + INT, 0, gcc_attr_wrapper($4)); + } + | abstract_declarator '[' e ']' attr_var { + $$ = block(LB, $1, $3, INT, 0, gcc_attr_wrapper($5)); + } + | '(' ')' { $$ = bdty(UCALL, bdty(NAME, NULL)); } + | '(' ib2 parameter_type_list ')' { + $$ = bdty(CALL, bdty(NAME, NULL), $3); + } + | abstract_declarator '(' ')' { + $$ = bdty(UCALL, $1); + } + | abstract_declarator '(' ib2 parameter_type_list ')' { + $$ = bdty(CALL, $1, $4); + } + ; + +ib2: { } + ; +/* + * K&R arg declaration, between ) and { + */ +arg_dcl_list: arg_declaration + | arg_dcl_list arg_declaration + ; + + +arg_declaration: declaration_specifiers arg_param_list ';' { + nfree($1); + } + ; + +arg_param_list: declarator attr_var { + olddecl(block(TYMERGE, ccopy($0), $1, + INT, 0, 0), $2); + } + | arg_param_list ',' declarator attr_var { + olddecl(block(TYMERGE, ccopy($0), $3, + INT, 0, 0), $4); + } + ; + +/* + * Declarations in beginning of blocks. + */ +block_item_list: block_item + | block_item_list block_item + ; + +block_item: declaration + | statement + ; + +/* + * Here starts the old YACC code. + */ + +/* + * Variables are declared in init_declarator. + */ +declaration: declaration_specifiers ';' { tfree($1); fun_inline = 0; } + | declaration_specifiers init_declarator_list ';' { + tfree($1); + fun_inline = 0; + } + ; + +/* + * Normal declaration of variables. curtype contains the current type node. + * Returns nothing, variables are declared in init_declarator. + */ +init_declarator_list: + init_declarator { symclear(blevel); } + | init_declarator_list ',' attr_var { $$ = $0; } init_declarator { + uawarn($3, "init_declarator"); + symclear(blevel); + } + ; + +enum_dcl: enum_head '{' moe_list optcomma '}' { $$ = enumdcl($1); } + | C_ENUM C_NAME { $$ = enumref($2); } + ; + +enum_head: C_ENUM { $$ = enumhd(NULL); } + | C_ENUM C_NAME { $$ = enumhd($2); } + ; + +moe_list: moe + | moe_list ',' moe + ; + +moe: C_NAME { moedef($1); } + | C_TYPENAME { moedef($1); } + | C_NAME '=' e { enummer = con_e($3); moedef($1); } + | C_TYPENAME '=' e { enummer = con_e($3); moedef($1); } + ; + +struct_dcl: str_head '{' struct_dcl_list '}' { + NODE *p; + + $$ = dclstruct($1); + if (pragma_allpacked) { + p = bdty(CALL, bdty(NAME, "packed"), + bcon(pragma_allpacked)); + $$->n_ap = attr_add($$->n_ap,gcc_attr_wrapper(p)); } + } + | C_STRUCT attr_var C_NAME { + $$ = rstruct($3,$1); + uawarn($2, "struct_dcl"); + } + | C_STRUCT attr_var nmrec C_NAME { + $$ = cxxrstruct($1,$2,$3,$4); + uawarn($2, "struct_dcl"); + } + /*COMPAT_GCC*/ | str_head '{' '}' { $$ = dclstruct($1); } + ; + +attr_var: { + NODE *q, *p; + + p = pragma_aligned ? bdty(CALL, bdty(NAME, "aligned"), + bcon(pragma_aligned)) : NIL; + if (pragma_packed) { + q = bdty(NAME, "packed"); + p = (p == NIL ? q : cmop(p, q)); + } + pragma_aligned = pragma_packed = 0; + $$ = p; + } + /*COMPAT_GCC*/ | attr_spec_list + ; + +attr_spec_list: attribute_specifier + | attr_spec_list attribute_specifier { $$ = cmop($1, $2); } + ; + +str_head: C_STRUCT attr_var { $$ = bstruct(NULL, $1, $2); } + | C_STRUCT attr_var C_NAME { $$ = bstruct($3, $1, $2); } + ; + +struct_dcl_list: struct_declaration + | struct_dcl_list struct_declaration + ; + +struct_declaration: + declaration_specifiers struct_declarator_list optsemi { + tfree($1); + } + | C_NAME ':' { /* cxxaccess($1); */ } + ; + +optsemi: ';' { } + | optsemi ';' { werror("extra ; in struct"); } + ; + +specifier_qualifier_list: + merge_specifiers { $$ = typenode($1); } + ; + +merge_specifiers: type_sq merge_specifiers { $$ = cmop($2, $1); } + | type_sq { $$ = $1; } + ; + +struct_declarator_list: + struct_declarator { symclear(blevel); } + | struct_declarator_list ',' { $$=$0; } + struct_declarator { symclear(blevel); } + ; + +struct_declarator: declarator attr_var { + NODE *p; + + $1 = aryfix($1); + p = tymerge($0, tymfix($1)); + if ($2) + p->n_ap = attr_add(p->n_ap, gcc_attr_wrapper($2)); + soumemb(p, (char *)$1->n_sp, glval($0)); + tfree(p); + } + | ':' e { + int ie = con_e($2); + if (fldchk(ie)) + ie = 1; + falloc(NULL, ie, $0); + } + | declarator ':' e { + int ie = con_e($3); + if (fldchk(ie)) + ie = 1; + if ($1->n_op == NAME) { + /* XXX - tymfix() may alter $1 */ + tymerge($0, tymfix($1)); + soumemb($1, (char *)$1->n_sp, FIELD | ie); + nfree($1); + } else + uerror("illegal declarator"); + } + | declarator ':' e attr_spec_list { + int ie = con_e($3); + if (fldchk(ie)) + ie = 1; + if ($1->n_op == NAME) { + /* XXX - tymfix() may alter $1 */ + tymerge($0, tymfix($1)); + if ($4) + $1->n_ap = attr_add($1->n_ap, + gcc_attr_wrapper($4)); + soumemb($1, (char *)$1->n_sp, FIELD | ie); + nfree($1); + } else + uerror("illegal declarator"); + } + | /* unnamed member */ { + NODE *p = $0; + char *c = permalloc(10); + + if (p->n_type != STRTY && p->n_type != UNIONTY) + uerror("bad unnamed member type"); + snprintf(c, 10, "*%dFAKE", getlab()); + soumemb(p, c, 0); + } + ; + + /* always preceeded by attributes */ +xnfdeclarator: declarator attr_var { + $$ = xnf = init_declarator($0, $1, 1, $2); + } + | declarator C_ASM '(' string ')' { + pragma_renamed = newstring($4, strlen($4)); + $$ = xnf = init_declarator($0, $1, 1, NULL); + } + ; + +/* + * Handles declarations and assignments. + * Returns nothing. + */ +init_declarator: declarator attr_var { init_declarator($0, $1, 0, $2);} + | declarator C_ASM '(' string ')' attr_var { +#ifdef GCC_COMPAT + pragma_renamed = newstring($4, strlen($4)); + init_declarator($0, $1, 0, $6); +#else + werror("gcc extension"); + init_declarator($0, $1, 0, $6); +#endif + } + | xnfdeclarator '=' e { + if ($1->sclass == STATIC || $1->sclass == EXTDEF) + statinit++; + simpleinit($1, eve($3)); + if ($1->sclass == STATIC || $1->sclass == EXTDEF) + statinit--; + xnf = NULL; + } + | xnfdeclarator '=' begbr init_list optcomma '}' { + endinit(0); + xnf = NULL; + } + /*COMPAT_GCC*/ | xnfdeclarator '=' begbr '}' { endinit(0); xnf = NULL; } + | xnfdeclarator '=' addrlbl { simpleinit($1, $3); xnf = NULL; } + ; + +begbr: '{' { beginit($-1); } + ; + +initializer: e %prec ',' { $$ = eve($1); } + | addrlbl { $$ = $1; } + | ibrace init_list optcomma '}' { $$ = NULL; } + | ibrace '}' { asginit(bcon(0)); $$ = NULL; } + ; + +init_list: designation initializer { dainit($1, $2); } + | init_list ',' designation initializer { dainit($3, $4); } + ; + +designation: designator_list '=' { desinit($1); $$ = NIL; } + | GCC_DESIG { desinit(bdty(NAME, $1)); $$ = NIL; } + | '[' e C_ELLIPSIS e ']' '=' { $$ = biop(CM, $2, $4); } + | { $$ = NIL; } + ; + +designator_list: designator { $$ = $1; } + | designator_list designator { $$ = $2; $$->n_left = $1; } + ; + +designator: '[' e ']' { + int ie = con_e($2); + if (ie < 0) { + uerror("designator must be non-negative"); + ie = 0; + } + $$ = biop(LB, NIL, bcon(ie)); + } + | C_STROP C_TYPENAME { + if ($1 != DOT) + uerror("invalid designator"); + $$ = bdty(NAME, $2); + } + | C_STROP C_NAME { + if ($1 != DOT) + uerror("invalid designator"); + $$ = bdty(NAME, $2); + } + ; + +optcomma : /* VOID */ + | ',' + ; + +ibrace: '{' { ilbrace(); } + ; + +/* STATEMENTS */ + +compoundstmt: begin block_item_list '}' { flend(); } + | begin '}' { flend(); } + ; + +begin: '{' { + struct savbc *bc = tmpalloc(sizeof(struct savbc)); + if (blevel == 1) { +#ifdef STABS + if (gflag) + stabs_line(lineno); +#endif + dclargs(); + } +#ifdef STABS + if (gflag && blevel > 1) + stabs_lbrac(blevel+1); +#endif + ++blevel; + oldstyle = 0; + bc->contlab = autooff; + bc->next = savctx; + savctx = bc; + if (!isinlining && sspflag && blevel == 2) + sspstart(); + } + ; + +statement: e ';' { /* fwalk($1, eprint, 0); */ ecomp(eve($1)); symclear(blevel); } + | compoundstmt + | ifprefix statement { plabel($1); reached = 1; } + | ifelprefix statement { + if ($1 != NOLAB) { + plabel( $1); + reached = 1; + } + } + | whprefix statement { + branch(contlab); + plabel( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP)) + reached = 1; + else + reached = 0; + resetbc(0); + } + | doprefix statement C_WHILE '(' e ')' ';' { + plabel(contlab); + if (flostat & FCONT) + reached = 1; + if (reached) + cbranch(buildtree(NE, eve($5), bcon(0)), + bcon($1)); + else + tfree(eve($5)); + plabel( brklab); + reached = 1; + resetbc(0); + } + | forprefix .e ')' statement + { plabel( contlab ); + if( flostat&FCONT ) reached = 1; + if( $2 ) ecomp( $2 ); + branch($1); + plabel( brklab ); + if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1; + else reached = 0; + resetbc(0); + symclear(blevel); /* if declaration inside for() */ + } + | switchpart statement + { if( reached ) branch( brklab ); + plabel( $1 ); + swend(); + plabel( brklab); + if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1; + resetbc(FCONT); + } + | C_BREAK ';' { + if (brklab == NOLAB) + uerror("illegal break"); + else if (reached) + branch(brklab); + flostat |= FBRK; + reached = 0; + } + | C_CONTINUE ';' { + if (contlab == NOLAB) + uerror("illegal continue"); + else + branch(contlab); + flostat |= FCONT; + goto rch; + } + | C_RETURN ';' { + branch(retlab); + if (cftnsp->stype != VOID && + (cftnsp->sflags & NORETYP) == 0 && + cftnsp->stype != VOID+FTN) + uerror("return value required"); + rch: + if (!reached) + warner(Wunreachable_code); + reached = 0; + } + | C_RETURN e ';' { + NODE *p, *q; + + p = nametree(cftnsp); + p->n_type = DECREF(p->n_type); + q = eve($2); +#ifndef NO_COMPLEX + if (ANYCX(q) || ANYCX(p)) + q = cxret(q, p); +#endif + p = buildtree(RETURN, p, q); + if (p->n_type == VOID) { + ecomp(p->n_right); + } else { + if (cftnod == NIL) + cftnod = tempnode(0, p->n_type, + p->n_df, p->n_ap); + ecomp(buildtree(ASSIGN, + ccopy(cftnod), p->n_right)); + } + tfree(p->n_left); + nfree(p); + branch(retlab); + reached = 0; + } + | C_GOTO C_NAME ';' { gotolabel($2); goto rch; } + | C_GOTO '*' e ';' { ecomp(biop(GOTO, eve($3), NIL)); } + | asmstatement ';' + | ';' + | error ';' + | error '}' + | label statement + ; + +asmstatement: C_ASM mvol '(' string ')' { send_passt(IP_ASM, mkpstr($4)); } + | C_ASM mvol '(' string xasm ')' { mkxasm($4, $5); } + ; + +mvol: /* empty */ + | C_QUALIFIER { nfree($1); } + ; + +xasm: ':' oplist { $$ = xcmop($2, NIL, NIL); } + | ':' oplist ':' oplist { $$ = xcmop($2, $4, NIL); } + | ':' oplist ':' oplist ':' cnstr { $$ = xcmop($2, $4, $6); } + ; + +oplist: /* nothing */ { $$ = NIL; } + | oper { $$ = $1; } + ; + +oper: string '(' e ')' { $$ = xasmop($1, eve($3)); } + | oper ',' string '(' e ')' { + $$ = cmop($1, xasmop($3, eve($5))); + } + ; + +cnstr: string { $$ = xasmop($1, bcon(0)); } + | cnstr ',' string { $$ = cmop($1, xasmop($3, bcon(0))); } + ; + +label: C_NAME ':' attr_var { deflabel($1, $3); reached = 1; } + | C_TYPENAME ':' attr_var { deflabel($1, $3); reached = 1; } + | C_CASE e ':' { addcase(eve($2)); reached = 1; } +/* COMPAT_GCC */| C_CASE e C_ELLIPSIS e ':' { +#ifdef GCC_COMPAT + gcccase(eve($2), eve($4)); reached = 1; +#endif + } + | C_DEFAULT ':' { reached = 1; adddef(); flostat |= FDEF; } + ; + +doprefix: C_DO { + savebc(); + brklab = getlab(); + contlab = getlab(); + plabel( $$ = getlab()); + reached = 1; + } + ; +ifprefix: C_IF '(' e ')' { + cbranch(buildtree(NOT, eve($3), NIL), bcon($$ = getlab())); + reached = 1; + } + ; +ifelprefix: ifprefix statement C_ELSE { + if (reached) + branch($$ = getlab()); + else + $$ = NOLAB; + plabel( $1); + reached = 1; + } + ; + +whprefix: C_WHILE '(' e ')' { + savebc(); + $3 = eve($3); + if ($3->n_op == ICON && glval($3) != 0) + flostat = FLOOP; + plabel( contlab = getlab()); + reached = 1; + brklab = getlab(); + if (flostat == FLOOP) + tfree($3); + else + cbranch(buildtree(NOT, $3, NIL), bcon(brklab)); + } + ; +forprefix: C_FOR '(' .e ';' .e ';' { + if ($3) + ecomp($3); + savebc(); + contlab = getlab(); + brklab = getlab(); + plabel( $$ = getlab()); + reached = 1; + if ($5) + cbranch(buildtree(NOT, $5, NIL), bcon(brklab)); + else + flostat |= FLOOP; + } + | C_FOR '(' { ++blevel; } declaration .e ';' { + blevel--; + savebc(); + contlab = getlab(); + brklab = getlab(); + plabel( $$ = getlab()); + reached = 1; + if ($5) + cbranch(buildtree(NOT, $5, NIL), bcon(brklab)); + else + flostat |= FLOOP; + } + ; + +switchpart: C_SWITCH '(' e ')' { + NODE *p; + int num; + TWORD t; + + savebc(); + brklab = getlab(); + $3 = eve($3); + if (!ISINTEGER($3->n_type)) { + uerror("switch expression must have integer " + "type"); + t = INT; + } else { + $3 = intprom($3); + t = $3->n_type; + } + p = tempnode(0, t, 0, 0); + num = regno(p); + ecomp(buildtree(ASSIGN, p, $3)); + branch( $$ = getlab()); + swstart(num, t); + reached = 0; + } + ; +/* EXPRESSIONS */ +.e: e { $$ = eve($1); } + | { $$=0; } + ; + +elist: { $$ = NIL; } + | e %prec ',' + | elist ',' e { $$ = biop(CM, $1, $3); } + | elist ',' cast_type { /* hack for stdarg */ + TYMFIX($3); + $3->n_op = TYPE; + $$ = biop(CM, $1, $3); + } + ; + +/* + * Precedence order of operators. + */ +e: e ',' e { $$ = biop(COMOP, $1, $3); } + | e '=' e { $$ = biop(ASSIGN, $1, $3); } + | e C_ASOP e { $$ = biop($2, $1, $3); } + | e '?' e ':' e { + $$=biop(QUEST, $1, biop(COLON, $3, $5)); + } + | e '?' ':' e { + NODE *p = tempnode(0, $1->n_type, $1->n_df, $1->n_ap); + $$ = biop(COLON, ccopy(p), $4); + $$=biop(QUEST, biop(ASSIGN, p, $1), $$); + } + | e C_OROR e { $$ = biop($2, $1, $3); } + | e C_ANDAND e { $$ = biop($2, $1, $3); } + | e '|' e { $$ = biop(OR, $1, $3); } + | e '^' e { $$ = biop(ER, $1, $3); } + | e '&' e { $$ = biop(AND, $1, $3); } + | e C_EQUOP e { $$ = biop($2, $1, $3); } + | e C_RELOP e { $$ = biop($2, $1, $3); } + | e C_SHIFTOP e { $$ = biop($2, $1, $3); } + | e '+' e { $$ = biop(PLUS, $1, $3); } + | e '-' e { $$ = biop(MINUS, $1, $3); } + | e C_DIVOP e { $$ = biop($2, $1, $3); } + | e '*' e { $$ = biop(MUL, $1, $3); } + | e '=' addrlbl { $$ = biop(ASSIGN, $1, $3); } + | term + ; + +xbegin: begin { + $$ = getlab(); getlab(); getlab(); + branch($$); plabel(($$)+1); } + ; + +addrlbl: C_ANDAND C_NAME { +#ifdef GCC_COMPAT + struct symtab *s = lookup($2, SLBLNAME); + if (s->soffset == 0) + s->soffset = -getlab(); + $$ = buildtree(ADDROF, nametree(s), NIL); +#else + uerror("gcc extension"); +#endif + } + ; + +term: term C_INCOP { $$ = biop($2, $1, bcon(1)); } + | '*' term { $$ = biop(UMUL, $2, NIL); } + | '&' term { $$ = biop(ADDROF, $2, NIL); } + | '-' term { $$ = biop(UMINUS, $2, NIL ); } + | '+' term { $$ = biop(PLUS, $2, bcon(0)); } + | CXX_CASTS C_RELOP cast_type C_RELOP '(' e ')' { + tfree($6); + tfree($3); + $$ = bcon(0); + werror("CXX_CASTS unhandled"); + } + | C_UNOP term { $$ = biop($1, $2, NIL); } + | C_INCOP term { + $$ = biop($1 == INCR ? PLUSEQ : MINUSEQ, $2, bcon(1)); + } + | C_SIZEOF xa term { $$ = biop(SZOF, $3, bcon(0)); inattr = $2; } + | '(' cast_type ')' term %prec C_INCOP { + TYMFIX($2); + $$ = biop(CAST, $2, $4); + } + | C_SIZEOF xa '(' cast_type ')' %prec C_SIZEOF { + $$ = biop(SZOF, $4, bcon(1)); + inattr = $2; + } + | C_ALIGNOF xa '(' cast_type ')' { + int al; + TYMFIX($4); + al = talign($4->n_type, $4->n_ap); + $$ = bcon(al/SZCHAR); + inattr = $2; + tfree($4); + } + | '(' cast_type ')' clbrace init_list optcomma '}' { + endinit(0); + $$ = bdty(NAME, $4); + $$->n_op = CLOP; + } + | '(' cast_type ')' clbrace '}' { + endinit(0); + $$ = bdty(NAME, $4); + $$->n_op = CLOP; + } + | term '[' e ']' { + if ($1->n_op == NEWKW) { + $1->n_left = biop(LB, $1->n_left, $3); + } else + $$ = biop(LB, $1, $3); + } + | C_NAME '(' elist ')' { +#if 0 + if ($3) tfree($3); + $$ = bcon(0); +#else + $$ = biop($3 ? CALL : UCALL, bdty(NAME, $1), $3); +#endif + } + | term '(' elist ')' { $$ = biop($3 ? CALL : UCALL, $1, $3); } + | term C_STROP C_NAME { $$ = biop($2, $1, bdty(NAME, $3)); } + | term C_STROP C_TYPENAME { $$ = biop($2, $1, bdty(NAME, $3));} + | C_NAME %prec C_SIZEOF /* below ( */{ $$ = bdty(NAME, $1); } + | nmrec C_NAME %prec C_SIZEOF { + $$ = biop(NMLIST, $1, bdty(NAME, $2)); + } + | PCC_OFFSETOF '(' cast_type ',' term ')' { + TYMFIX($3); + $3->n_type = INCREF($3->n_type); + $3 = biop(CAST, $3, bcon(0)); + if ($5->n_op == NAME) { + $$ = biop(STREF, $3, $5); + } else { + NODE *p = $5; + while (p->n_left->n_op != NAME) + p = p->n_left; + p->n_left = biop(STREF, $3, p->n_left); + $$ = $5; + } + $$ = biop(ADDROF, $$, NIL); + $3 = block(NAME, NIL, NIL, ENUNSIGN(INTPTR), 0, 0); + $$ = biop(CAST, $3, $$); + } + | C_ICON { $$ = $1; } + | C_FCON { $$ = $1; } + | string { $$ = bdty(STRING, $1, widestr); } + | '(' e ')' { $$=$2; } + | '(' xbegin block_item_list e ';' '}' ')' { + /* XXX - check recursive ({ }) statements */ + branch(($2)+2); + plabel($2); + $$ = buildtree(COMOP, + biop(GOTO, bcon(($2)+1), NIL), eve($4)); + flend(); + } + | '(' xbegin block_item_list '}' ')' { + /* XXX - check recursive ({ }) statements */ + branch(($2)+2); + plabel($2); + $$ = buildtree(COMOP, + biop(GOTO, bcon(($2)+1), NIL), voidcon()); + flend(); + } + | CXX_NEW new_ds { $$ = biop(NEWKW, $2, bcon(0)); } + | CXX_NEW '(' cast_type ')' { $$ = 0; uerror("new cast"); } + | CXX_DELETE term %prec '-' { + $$ = biop(DELETE, $2, bcon(NM_DEL)); + } + | CXX_DELETE '[' ']' term %prec '-' { + $$ = biop(DELETE, $4, bcon(NM_DLA)); + } + ; + +nmrec: CXX_MORENM { $$ = bdty(NAME, $1); } + | CXX_MORENM nmrec { $$ = biop(NMLIST, $2, bdty(NAME, $1)); } + ; + +xa: { $$ = inattr; inattr = 0; } + ; + +clbrace: '{' { NODE *q = $-1; TYMFIX(q); $$ = clbrace(q); } + ; + +string: C_STRING { widestr = 0; $$ = stradd("", $1); } + | string C_STRING { $$ = stradd($1, $2); } + ; + +cast_type: specifier_qualifier_list { + $$ = biop(TYMERGE, $1, bdty(NAME, NULL)); + } + | specifier_qualifier_list abstract_declarator { + $$ = biop(TYMERGE, $1, aryfix($2)); + } + ; + +%% + +NODE * +mkty(TWORD t, union dimfun *d, struct attr *sue) +{ + return block(TYPE, NIL, NIL, t, d, sue); +} + +NODE * +bdty(int op, ...) +{ + va_list ap; + int val; + register NODE *q; + + va_start(ap, op); + q = biop(op, NIL, NIL); + + switch (op) { + case UMUL: + case UCALL: + q->n_left = va_arg(ap, NODE *); + q->n_rval = 0; + break; + + case CALL: + q->n_left = va_arg(ap, NODE *); + q->n_right = va_arg(ap, NODE *); + break; + + case LB: + q->n_left = va_arg(ap, NODE *); + if ((val = va_arg(ap, int)) <= 0) { + uerror("array size must be positive"); + val = 1; + } + q->n_right = bcon(val); + break; + + case NAME: + q->n_sp = va_arg(ap, struct symtab *); /* XXX survive tymerge */ + break; + + case STRING: + q->n_name = va_arg(ap, char *); + val = va_arg(ap, int); + slval(q, val); + break; + + default: + cerror("bad bdty"); + } + va_end(ap); + + return q; +} + +static void +flend(void) +{ + if (!isinlining && sspflag && blevel == 2) + sspend(); +#ifdef STABS + if (gflag && blevel > 2) + stabs_rbrac(blevel); +#endif + --blevel; + if( blevel == 1 ) + blevel = 0; + symclear(blevel); /* Clean ut the symbol table */ + if (autooff > maxautooff) + maxautooff = autooff; + autooff = savctx->contlab; + savctx = savctx->next; +} + +static void +savebc(void) +{ + struct savbc *bc = tmpalloc(sizeof(struct savbc)); + + bc->brklab = brklab; + bc->contlab = contlab; + bc->flostat = flostat; + bc->next = savbc; + savbc = bc; + flostat = 0; +} + +static void +resetbc(int mask) +{ + flostat = savbc->flostat | (flostat&mask); + contlab = savbc->contlab; + brklab = savbc->brklab; + savbc = savbc->next; +} + +struct swdef { + struct swdef *next; /* Next in list */ + int deflbl; /* Label for "default" */ + struct swents *ents; /* Linked sorted list of case entries */ + int nents; /* # of entries in list */ + int num; /* Node value will end up in */ + TWORD type; /* Type of switch expression */ +} *swpole; + +/* + * add case to switch + */ +static void +addcase(NODE *p) +{ + struct swents **put, *w, *sw = tmpalloc(sizeof(struct swents)); + CONSZ val; + + p = optim(rmpconv(p)); /* change enum to ints */ + if (p->n_op != ICON || p->n_sp != NULL) { + uerror( "non-constant case expression"); + return; + } + if (swpole == NULL) { + uerror("case not in switch"); + return; + } + + if (DEUNSIGN(swpole->type) != DEUNSIGN(p->n_type)) { + val = glval(p); + p = makety(p, swpole->type, 0, 0, 0); + if (p->n_op != ICON) + cerror("could not cast case value to type of switch " + "expression"); + if (glval(p) != val) + werror("case expression truncated"); + } + sw->sval = glval(p); + tfree(p); + put = &swpole->ents; + if (ISUNSIGNED(swpole->type)) { + for (w = swpole->ents; + w != NULL && (U_CONSZ)w->sval < (U_CONSZ)sw->sval; + w = w->next) + put = &w->next; + } else { + for (w = swpole->ents; w != NULL && w->sval < sw->sval; + w = w->next) + put = &w->next; + } + if (w != NULL && w->sval == sw->sval) { + uerror("duplicate case in switch"); + return; + } + plabel(sw->slab = getlab()); + *put = sw; + sw->next = w; + swpole->nents++; +} + +#ifdef GCC_COMPAT +void +gcccase(NODE *ln, NODE *hn) +{ + CONSZ i, l, h; + + l = icons(optim(ln)); + h = icons(optim(hn)); + + if (h < l) + i = l, l = h, h = i; + + for (i = l; i <= h; i++) + addcase(xbcon(i, NULL, hn->n_type)); +} +#endif + +/* + * add default case to switch + */ +static void +adddef(void) +{ + if (swpole == NULL) + uerror("default not inside switch"); + else if (swpole->deflbl != 0) + uerror("duplicate default in switch"); + else + plabel( swpole->deflbl = getlab()); +} + +static void +swstart(int num, TWORD type) +{ + struct swdef *sw = tmpalloc(sizeof(struct swdef)); + + sw->deflbl = sw->nents = 0; + sw->ents = NULL; + sw->next = swpole; + sw->num = num; + sw->type = type; + swpole = sw; +} + +/* + * end a switch block + */ +static void +swend(void) +{ + struct swents *sw, **swp; + int i; + + sw = tmpalloc(sizeof(struct swents)); + swp = tmpalloc(sizeof(struct swents *) * (swpole->nents+1)); + + sw->slab = swpole->deflbl; + swp[0] = sw; + + for (i = 1; i <= swpole->nents; i++) { + swp[i] = swpole->ents; + swpole->ents = swpole->ents->next; + } + genswitch(swpole->num, swpole->type, swp, swpole->nents); + + swpole = swpole->next; +} + +/* + * num: tempnode the value of the switch expression is in + * type: type of the switch expression + * + * p points to an array of structures, each consisting + * of a constant value and a label. + * The first is >=0 if there is a default label; + * its value is the label number + * The entries p[1] to p[n] are the nontrivial cases + * n is the number of case statements (length of list) + */ +static void +genswitch(int num, TWORD type, struct swents **p, int n) +{ + NODE *r, *q; + int i; + + if (mygenswitch(num, type, p, n)) + return; + + /* simple switch code */ + for (i = 1; i <= n; ++i) { + /* already in 1 */ + r = tempnode(num, type, 0, 0); + q = xbcon(p[i]->sval, NULL, type); + r = buildtree(NE, r, clocal(q)); + cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab)); + } + if (p[0]->slab > 0) + branch(p[0]->slab); +} + +/* + * Declare a variable or prototype. + */ +static struct symtab * +init_declarator(NODE *tn, NODE *p, int assign, NODE *a) +{ + int class = glval(tn); + struct symtab *sp; + + p = aryfix(p); + if (p->n_op == NMLIST) { + tymerge(tn, p->n_right); + } else + p = tymerge(tn, p); + if (a) { + struct attr *ap = gcc_attr_wrapper(a); + p->n_ap = attr_add(p->n_ap, ap); + } + + sp = cxxdeclvar(p); + + if (fun_inline && ISFTN(p->n_type)) + sp->sflags |= SINLINE; + + if (!ISFTN(p->n_type)) { + if (assign) { + defid(p, class); + sp = p->n_sp; + sp->sflags |= SASG; + if (sp->sflags & SDYNARRAY) + uerror("can't initialize dynamic arrays"); + lcommdel(sp); + } else + nidcl(p, class); + } else { + extern NODE *parlink; + if (assign) + uerror("cannot initialise function"); + defid(p, uclass(class)); + sp = p->n_sp; + if (parlink) { + /* dynamic sized arrays in prototypes */ + tfree(parlink); /* Free delayed tree */ + parlink = NIL; + } + } + tfree(p); + return sp; +} + +/* + * Declare old-stype function arguments. + */ +static void +oldargs(NODE *p) +{ + blevel++; + p->n_op = TYPE; + p->n_type = FARG; + p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */ + defid(p, PARAM); + blevel--; +} + +/* + * Set NAME nodes to a null name and index of LB nodes to NOOFFSET + * unless clr is one, in that case preserve variable name. + */ +static NODE * +namekill(NODE *p, int clr) +{ + NODE *q; + int o = p->n_op; + + switch (coptype(o)) { + case LTYPE: + if (o == NAME) { + if (clr) + p->n_sp = NULL; + else + p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */ + } + break; + + case UTYPE: + p->n_left = namekill(p->n_left, clr); + break; + + case BITYPE: + p->n_left = namekill(p->n_left, clr); + if (o == LB) { + if (clr) { + tfree(p->n_right); + p->n_right = bcon(NOOFFSET); + } else + p->n_right = eve(p->n_right); + } else if (o == CALL) + p->n_right = namekill(p->n_right, 1); + else + p->n_right = namekill(p->n_right, clr); + if (o == TYMERGE) { + q = tymerge(p->n_left, p->n_right); + q->n_ap = attr_add(q->n_ap, p->n_ap); + tfree(p->n_left); + nfree(p); + p = q; + } + break; + } + return p; +} + +/* + * Declare function arguments. + */ +static NODE * +funargs(NODE *p) +{ + extern NODE *arrstk[10]; + + if (p->n_op == ELLIPSIS) + return p; + + p = namekill(p, 0); + if (ISFTN(p->n_type)) + p->n_type = INCREF(p->n_type); + if (ISARY(p->n_type)) { + p->n_type += (PTR-ARY); + if (p->n_df->ddim == -1) + tfree(arrstk[0]), arrstk[0] = NIL; + p->n_df++; + } + if (p->n_type == VOID && p->n_sp->sname == NULL) + return p; /* sanitycheck later */ + else if (p->n_sp->sname == NULL) + ; /* uerror("argument missing"); */ + else + defid(p, PARAM); + return p; +} + +static NODE * +listfw(NODE *p, NODE * (*f)(NODE *)) +{ + if (p->n_op == CM) { + p->n_left = listfw(p->n_left, f); + p->n_right = (*f)(p->n_right); + } else + p = (*f)(p); + return p; +} + + +/* + * Declare a function. + */ +static struct symtab * +fundef(NODE *tp, NODE *p) +{ + extern int prolab; + struct symtab *s, *nsthis; + NODE *q, *typ; + int class = glval(tp), oclass, ctval; + char *c; + + /* + * We discard all names except for those needed for + * parameter declaration. While doing that, also change + * non-constant array sizes to unknown. + */ + ctval = tvaloff; + for (q = p; coptype(q->n_op) != LTYPE && + q->n_left->n_op != NAME && + q->n_left->n_op != NMLIST; q = q->n_left) { + if (q->n_op == CALL) + q->n_right = namekill(q->n_right, 1); + } + if (q->n_op != CALL && q->n_op != UCALL) { + uerror("invalid function definition"); + p = bdty(UCALL, p); + } else if (q->n_op == CALL) { + blevel = 1; + argoff = ARGINIT; + if (oldstyle == 0) + q->n_right = listfw(q->n_right, funargs); + ftnarg(q); + blevel = 0; + } + + if (p->n_op == CALL && p->n_left->n_op == NMLIST) { + NODE *r = p->n_left; + p->n_left = r->n_right; + r->n_right = typ = tymerge(tp, p); + p = r; + } else + typ = tymerge(tp, p); + +#ifdef GCC_COMPAT + /* gcc seems to discard __builtin_ when declaring functions */ + if (strncmp("__builtin_", (char *)typ->n_sp, 10) == 0) + typ->n_sp = (struct symtab *)((char *)typ->n_sp + 10); +#endif + + s = cxxftnfind(p, SNORMAL); + nsthis = nscur; + nscur = s->sdown; /* XXX fun in fun? */ + + oclass = s->sclass; + if (class == STATIC && oclass == EXTERN) + werror("%s was first declared extern, then static", s->sname); + + if (fun_inline) { + /* special syntax for inline functions */ + if (! strcmp(s->sname,"main")) + uerror("cannot inline main()"); + + s->sflags |= SINLINE; + inline_start(s); + if (class == EXTERN) + class = EXTDEF; + } else if (class == EXTERN) + class = SNULL; /* same result */ + + cftnsp = s; +#if 0 + defid(p, class); +#endif + +#ifdef GCC_COMPAT + if (attr_find(p->n_ap, GCC_ATYP_ALW_INL)) { + /* Temporary turn on temps to make always_inline work */ + alwinl = 1; + if (xtemps == 0) alwinl |= 2; + xtemps = 1; + } +#endif + prolab = getlab(); + if ((c = cftnsp->soname) == NULL) + c = addname(exname(cftnsp->sname)); + send_passt(IP_PROLOG, -1, c, cftnsp->stype, + cftnsp->sclass == EXTDEF, prolab, ctval); + blevel++; +#ifdef STABS + if (gflag) + stabs_func(s); +#endif + tfree(tp); + tfree(p); + return nsthis; +} + +static void +fend(struct symtab *ns) +{ + if (blevel) + cerror("function level error"); + ftnend(); + fun_inline = 0; + if (alwinl & 2) xtemps = 0; + alwinl = 0; + cftnsp = NULL; + nscur = ns; +} + +NODE * +structref(NODE *p, int f, char *name) +{ + NODE *r; + + if (f == DOT) + p = buildtree(ADDROF, p, NIL); + r = biop(NAME, NIL, NIL); + r->n_name = name; + r = buildtree(STREF, p, r); + return r; +} + +static void +olddecl(NODE *p, NODE *a) +{ + struct symtab *s; + + p = namekill(p, 0); + s = p->n_sp; + if (s->slevel != 1 || s->stype == UNDEF) + uerror("parameter '%s' not defined", s->sname); + else if (s->stype != FARG) + uerror("parameter '%s' redefined", s->sname); + + s->stype = p->n_type; + s->sdf = p->n_df; + s->sap = p->n_ap; + if (ISARY(s->stype)) { + s->stype += (PTR-ARY); + s->sdf++; + } else if (s->stype == FLOAT) + s->stype = DOUBLE; + if (a) + attr_add(s->sap, gcc_attr_wrapper(a)); + nfree(p); +} + +void +branch(int lbl) +{ + int r = reached++; + ecomp(biop(GOTO, bcon(lbl), NIL)); + reached = r; +} + +/* + * Create a printable string based on an encoded string. + */ +static char * +mkpstr(char *str) +{ + char *s, *os; + int v, l = strlen(str)+3; /* \t + \n + \0 */ + + os = s = inlalloc(l); + *s++ = '\t'; + for (; *str; ) { + if (*str++ == '\\') + v = esccon(&str); + else + v = str[-1]; + *s++ = v; + } + *s++ = '\n'; + *s = 0; + return os; +} + +/* + * Estimate the max length a string will have in its internal + * representation based on number of \ characters. + */ +static int +maxstlen(char *str) +{ + int i; + + for (i = 0; *str; str++, i++) + if (*str == '\\' || *str < 32 || *str > 0176) + i += 3; + return i; +} + +static char * +voct(char *d, unsigned int v) +{ + v &= (1 << SZCHAR) - 1; + *d++ = '\\'; + *d++ = v/64 + '0'; v &= 077; + *d++ = v/8 + '0'; v &= 7; + *d++ = v + '0'; + return d; +} + + +/* + * Convert a string to internal format. The resulting string may be no + * more than len characters long. + */ +static void +fixstr(char *d, char *s, int len) +{ + unsigned int v; + + while (*s) { + if (len <= 0) + cerror("fixstr"); + if (*s == '\\') { + s++; + v = esccon(&s); + d = voct(d, v); + len -= 4; + } else if (*s < ' ' || *s > 0176) { + d = voct(d, *s++); + len -= 4; + } else + *d++ = *s++, len--; + } + *d = 0; +} + +/* + * Add "raw" string new to cleaned string old. + */ +static char * +stradd(char *old, char *new) +{ + char *rv; + int len; + + if (*new == 'L' && new[1] == '\"') + widestr = 1, new++; + if (*new == '\"') { + new++; /* remove first " */ + new[strlen(new) - 1] = 0;/* remove last " */ + } + len = strlen(old) + maxstlen(new) + 1; + rv = tmpalloc(len); + strlcpy(rv, old, len); + fixstr(rv + strlen(old), new, maxstlen(new) + 1); + return rv; +} + +/* + * Fake a symtab entry for compound literals. + */ +static struct symtab * +clbrace(NODE *p) +{ + struct symtab *sp; + + sp = getsymtab(simname("cl"), STEMP); + sp->stype = p->n_type; + sp->squal = p->n_qual; + sp->sdf = p->n_df; + sp->sap = p->n_ap; + tfree(p); + if (blevel == 0 && xnf != NULL) { + sp->sclass = STATIC; + sp->slevel = 2; + sp->soffset = getlab(); + } else { + sp->sclass = blevel ? AUTO : STATIC; + if (!ISARY(sp->stype) || sp->sdf->ddim != NOOFFSET) { + sp->soffset = NOOFFSET; + oalloc(sp, &autooff); + } + } + beginit(sp); + return sp; +} + +char * +simname(char *s) +{ + int len = strlen(s) + 10 + 1; + char *w = tmpalloc(len); + + snprintf(w, len, "%s%d", s, getlab()); + return w; +} + +NODE * +biop(int op, NODE *l, NODE *r) +{ + return block(op, l, r, INT, 0, 0); +} + +static NODE * +cmop(NODE *l, NODE *r) +{ + return biop(CM, l, r); +} + +static NODE * +voidcon(void) +{ + return block(ICON, NIL, NIL, STRTY, 0, 0); +} + +/* Support for extended assembler a' la' gcc style follows below */ + +static NODE * +xmrg(NODE *out, NODE *in) +{ + NODE *p = in; + + if (p->n_op == XARG) { + in = cmop(out, p); + } else { + while (p->n_left->n_op == CM) + p = p->n_left; + p->n_left = cmop(out, p->n_left); + } + return in; +} + +/* + * Put together in and out node lists in one list, and balance it with + * the constraints on the right side of a CM node. + */ +static NODE * +xcmop(NODE *out, NODE *in, NODE *str) +{ + NODE *p, *q; + + if (out) { + /* D out-list sanity check */ + for (p = out; p->n_op == CM; p = p->n_left) { + q = p->n_right; + if (q->n_name[0] != '=' && q->n_name[0] != '+') + uerror("output missing ="); + } + if (p->n_name[0] != '=' && p->n_name[0] != '+') + uerror("output missing ="); + if (in == NIL) + p = out; + else + p = xmrg(out, in); + } else if (in) { + p = in; + } else + p = voidcon(); + + if (str == NIL) + str = voidcon(); + return cmop(p, str); +} + +/* + * Generate a XARG node based on a string and an expression. + */ +static NODE * +xasmop(char *str, NODE *p) +{ + + p = biop(XARG, p, NIL); + p->n_name = isinlining ? newstring(str, strlen(str)) : str; + return p; +} + +/* + * Generate a XASM node based on a string and an expression. + */ +static void +mkxasm(char *str, NODE *p) +{ + NODE *q; + + q = biop(XASM, p->n_left, p->n_right); + q->n_name = isinlining ? newstring(str, strlen(str)) : str; + nfree(p); + ecomp(q); +} + +static struct attr * +gcc_attr_wrapper(NODE *p) +{ +#ifdef GCC_COMPAT + return gcc_attr_parse(p); +#else + uerror("gcc attribute used"); + return NULL; +#endif +} + + +#ifdef GCC_COMPAT +static NODE * +tyof(NODE *p) +{ + static struct symtab spp; + NODE *q = block(TYPE, NIL, NIL, p->n_type, p->n_df, p->n_ap); + q->n_qual = p->n_qual; + q->n_sp = &spp; /* for typenode */ + tfree(p); + return q; +} +#else +static NODE * +tyof(NODE *p) +{ + uerror("typeof gcc extension"); + return bcon(0); +} +#endif + +/* + * Rewrite ++/-- to (t=p, p++, t) ops on types that do not act act as usual. + */ +static NODE * +rewincop(NODE *p1, NODE *p2, int op) +{ + NODE *t, *r; + + t = cstknode(p1->n_type, 0, 0); + r = buildtree(ASSIGN, ccopy(t), ccopy(p1)); + r = buildtree(COMOP, r, buildtree(op, p1, eve(p2))); + return buildtree(COMOP, r, t); +} + +/* + * Traverse an unhandled expression tree bottom-up and call buildtree() + * or equivalent as needed. + */ +NODE * +eve(NODE *p) +{ + struct symtab *sp; + NODE *r, *p1, *p2; + int x; + + p1 = p->n_left; + p2 = p->n_right; + switch (p->n_op) { + case NMLIST: + case NAME: + sp = cxxlookup(p, SNORMAL|SNOCREAT); + if (sp->sflags & SINLINE) + inline_ref(sp); + r = nametree(sp); + if (sp->sflags & SDYNARRAY) + r = buildtree(UMUL, r, NIL); +#ifdef GCC_COMPAT + if (attr_find(sp->sap, GCC_ATYP_DEPRECATED)) + warner(Wdeprecated_declarations, sp->sname); +#endif + break; + + case DOT: + case STREF: + r = cxxstructref(eve(p1), p->n_op, (char *)p2->n_sp); + nfree(p2); + break; + + case CAST: + p1 = buildtree(CAST, p1, eve(p2)); + nfree(p1->n_left); + r = p1->n_right; + nfree(p1); + break; + + + case SZOF: + x = xinline; xinline = 0; /* XXX hack */ + if (glval(p2) == 0) + p1 = eve(p1); + else + TYMFIX(p1); + nfree(p2); + r = doszof(p1); + xinline = x; + break; + + case LB: + p1 = eve(p->n_left); + r = buildtree(UMUL, buildtree(PLUS, p1, eve(p2)), NIL); + break; + + case COMPL: +#ifndef NO_COMPLEX + p1 = eve(p1); + if (ANYCX(p1)) + r = cxconj(p1); + else + r = buildtree(COMPL, p1, NIL); + break; +#endif + case UMINUS: + case NOT: + case UMUL: + r = buildtree(p->n_op, eve(p->n_left), NIL); + break; + + case ADDROF: + r = eve(p1); + if (ISFTN(p->n_type)/* || ISARY(p->n_type) */){ +#ifdef notdef + werror( "& before array or function: ignored" ); +#endif + } else + r = buildtree(ADDROF, r, NIL); + break; + + case CALL: + case UCALL: + if (p1->n_op == NAME || p1->n_op == NMLIST) { + sp = cxxlookup(p1, SNORMAL); +#ifndef NO_C_BUILTINS + if (sp->sflags & SBUILTIN) { + nfree(p1); + r = builtin_check(sp, p2); + break; + } +#endif + if (sp->stype == UNDEF) { + p1->n_type = FTN|INT; + p1->n_sp = sp; + p1->n_ap = NULL; + defid(p1, EXTERN); + } + nfree(p1); +#ifdef GCC_COMPAT + if (attr_find(sp->sap, GCC_ATYP_DEPRECATED)) + warner(Wdeprecated_declarations, sp->sname); +#endif + p2 = p->n_op == CALL ? eve(p2) : NIL; + r = doacall(sp, nametree(sp), p2, 0); + } else if (p1->n_op == DOT || p1->n_op == STREF) { + /* + * function as member of a struct. + * - check args for correct overloaded function + * - add hidden arg0 as pointer to this struct + */ + + p2 = p->n_op == CALL ? eve(p2) : NIL; + p1->n_left = eve(p1->n_left); /* eval rest */ + r = cxxmatchftn(p1, p2); + if (p1->n_op == DOT) + p1->n_left = buildtree(ADDROF, p1->n_left, NIL); + nfree(p1->n_right); + p1 = nfree(p1); + p2 = cxxaddhidden(p2, p1); + r = doacall(NULL, r, p2, 1); + } else { + p2 = p->n_op == CALL ? eve(p2) : NIL; + r = doacall(NULL, eve(p1), p2, 0); + } + break; + +#ifndef NO_COMPLEX + case XREAL: + case XIMAG: + p1 = eve(p1); + r = cxelem(p->n_op, p1); + break; +#endif + + case MUL: + case DIV: + case PLUS: + case MINUS: + case ASSIGN: + case EQ: + case NE: +#ifndef NO_COMPLEX + p1 = eve(p1); + p2 = eve(p2); + if (ANYCX(p1) || ANYCX(p2)) { + r = cxop(p->n_op, p1, p2); + } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) { + r = imop(p->n_op, p1, p2); + } else + r = buildtree(p->n_op, p1, p2); + break; +#endif + case MOD: + case CM: + case GT: + case GE: + case LT: + case LE: + case RS: + case LS: + case RSEQ: + case LSEQ: + case AND: + case OR: + case ER: + case OROR: + case ANDAND: + case EREQ: + case OREQ: + case ANDEQ: + case QUEST: + case COLON: + p1 = eve(p1); +eve2: r = buildtree(p->n_op, p1, eve(p2)); + break; + + case INCR: + case DECR: + p1 = eve(p1); + if (p1->n_type >= FLOAT && p1->n_type <= LDOUBLE) { + /* ++/-- on floats isn't ((d+=1)-1) */ + /* rewrite to (t=d,d++,t) */ + /* XXX - side effects */ + r = rewincop(p1, p2, p->n_op); + break; + } + if (p1->n_type != BOOL) + goto eve2; + /* Hey, fun. ++ will always be 1, and -- will toggle result */ + if (p->n_op == INCR) { + /* (t=d,d=1,t) */ + r = rewincop(p1, p2, ASSIGN); + } else { + /* (t=d,d^=1,t) */ + r = rewincop(p1, p2, EREQ); + } + break; + + case MODEQ: + case MINUSEQ: + case PLUSEQ: + case MULEQ: + case DIVEQ: + p1 = eve(p1); + p2 = eve(p2); +#ifndef NO_COMPLEX + if (ANYCX(p1) || ANYCX(p2)) { + r = cxop(UNASG p->n_op, ccopy(p1), p2); + r = cxop(ASSIGN, p1, r); + break; + } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) { + r = imop(UNASG p->n_op, ccopy(p1), p2); + r = cxop(ASSIGN, p1, r); + break; + } + /* FALLTHROUGH */ +#endif + if (p1->n_type == BOOL) { + r = buildtree(UNASG p->n_op, ccopy(p1), p2); + r = buildtree(ASSIGN, p1, r); + } else { + r = buildtree(p->n_op, p1, p2); + } + break; + + case STRING: + r = strend(glval(p), p->n_name); + break; + + case COMOP: + if (p1->n_op == GOTO) { + /* inside ({ }), eve already called */ + r = buildtree(p->n_op, p1, p2); + } else { + p1 = eve(p1); + r = buildtree(p->n_op, p1, eve(p2)); + } + break; + + case TYPE: + case ICON: + case FCON: + case TEMP: + return p; + + case CLOP: + r = nametree(p->n_sp); + break; + + case DELETE: + p1 = eve(p1); + r = cxx_delete(p1, glval(p2)); + nfree(p2); + break; + + case NEWKW: + r = cxx_new(p1); + nfree(p2); + break; + + default: +#ifdef PCC_DEBUG + fwalk(p, eprint, 0); +#endif + cerror("eve"); + r = NIL; + } + nfree(p); + return r; +} + +int +con_e(NODE *p) +{ +#ifdef WORD_ADDRESSED + return icons(optim(eve(p))); +#else + return icons(optim(rmpconv(eve(p)))); +#endif +} + +void +uawarn(NODE *p, char *s) +{ + if (p == 0) + return; + if (attrwarn) + werror("unhandled %s attribute", s); + tfree(p); +} + +static void +dainit(NODE *d, NODE *a) +{ + if (d == NULL) { + asginit(a); + } else if (d->n_op == CM) { + int is = con_e(d->n_left); + int ie = con_e(d->n_right); + int i; + + nfree(d); + if (ie < is) + uerror("negative initializer range"); + desinit(biop(LB, NIL, bcon(is))); + for (i = is; i < ie; i++) + asginit(ccopy(a)); + asginit(a); + } else { + cerror("dainit"); + } +} + +/* + * Traverse down and tymerge() where appropriate. + */ +static NODE * +tymfix(NODE *p) +{ + NODE *q; + int o = coptype(p->n_op); + + switch (o) { + case LTYPE: + break; + case UTYPE: + p->n_left = tymfix(p->n_left); + break; + case BITYPE: + p->n_left = tymfix(p->n_left); + p->n_right = tymfix(p->n_right); + if (p->n_op == TYMERGE) { + q = tymerge(p->n_left, p->n_right); + q->n_ap = attr_add(q->n_ap, p->n_ap); + tfree(p->n_left); + nfree(p); + p = q; + } + break; + } + return p; +} + +static NODE * +aryfix(NODE *p) +{ + NODE *q; + + for (q = p; q->n_op != NAME; q = q->n_left) { + if (q->n_op == LB) { + q->n_right = optim(rmpconv(eve(q->n_right))); + if ((blevel == 0 || rpole != NULL) && + !nncon(q->n_right)) + uerror("array size not constant"); + /* + * Checks according to 6.7.5.2 clause 1: + * "...the expression shall have an integer type." + * "If the expression is a constant expression, + * it shall have a value greater than zero." + */ + if (!ISINTEGER(q->n_right->n_type)) + werror("array size is not an integer"); + else if (q->n_right->n_op == ICON && + glval(q->n_right) < 0 && + glval(q->n_right) != NOOFFSET) { + uerror("array size cannot be negative"); + slval(q->n_right, 1); + } + } else if (q->n_op == CALL) + q->n_right = namekill(q->n_right, 1); + } + return p; +} diff --git a/lang/pcc/pcc/cc/cxxcom/cxxcode.c b/lang/pcc/pcc/cc/cxxcom/cxxcode.c new file mode 100644 index 000000000..2f998dead --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/cxxcode.c @@ -0,0 +1,830 @@ +/* $Id: cxxcode.c,v 1.6 2014/05/03 09:57:57 ragge Exp $ */ +/* + * Copyright (c) 2011 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + + +struct symtab spole0 = { 0, 0, 0, 0, 0, 0, 0, "base", "base", }; +struct symtab *spole = &spole0; +struct symtab *nscur = &spole0; +int elnk, nsptr; + +static struct symtab *sfind(char *n, struct symtab *sp); +/* + * Declare a namespace. + */ +void +dclns(NODE *attr, char *n) +{ + struct symtab *sp; +#ifdef GCC_COMPAT + struct attr *ap = gcc_attr_parse(attr); +#else + struct attr *ap = NULL; +#endif + + if (cppdebug)printf("declaring namespace %s\n", n); + n = addname(n); + + sp = sfind(n, nscur->sup); + while (sp != NULL) { + if (sp->sname == n && sp->sclass == NSPACE) + break; + sp = sfind(n, sp->snext); + } + if (sp == NULL) { + /* New namespace */ + sp = getsymtab(n, 0); + sp->sclass = NSPACE; + INSSYM(sp); + } + nscur = sp; + if (cppdebug)printf("declaring namespace2 %s\n", nscur->sname); + sp->sap = attr_add(sp->sap, ap); /* XXX check attributes */ +} + +/* + * Generate a call tree to function named n. + */ +static NODE * +callftn(char *n, ...) +{ + struct symtab *sp = getsymtab(n, 0); + NODE *p, *a, *b; + va_list ap; + + sp->stype = (FTN|VOID) | (PTR << TSHIFT); + va_start(ap, n); + + a = va_arg(ap, NODE *); + if (a != NULL) { + do { + b = va_arg(ap, NODE *); + if (b != NULL) + a = buildtree(CM, a, b); + } while (b != NULL); + } + + p = doacall(sp, nametree(sp), a, 0); + va_end(ap); + return p; +} + +/* + * Sanitycheck "new" keyword. + */ +NODE * +cxx_new(NODE *p) +{ + NODE *q = p; + NODE *t1 = bcon(1); + int nw = NM_NEW; + + while (p->n_op == LB) { + nw = NM_NWA; + t1 = buildtree(MUL, t1, eve(p->n_right)); + p->n_right = bcon(0); + p = p->n_left; + } + if (p->n_op != TYPE) + uerror("new used illegally"); + t1 = buildtree(MUL, t1, + xbcon(tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR)); + tfree(q); + return callftn(decoratename(NULL, nw), t1, NULL); +} + +/* + * Handle "delete" keyword. + */ +NODE * +cxx_delete(NODE *p, int del) +{ + return callftn(decoratename(NULL, del), p, NULL); +} + +/* + ::= nw # new + ::= na # new[] + ::= dl # delete + ::= da # delete[] + ::= ps # + (unary) + ::= ng # - (unary) + ::= ad # & (unary) + ::= de # * (unary) + ::= co # ~ + ::= pl # + + ::= mi # - + ::= ml # * + ::= dv # / + ::= rm # % + ::= an # & + ::= or # | + ::= eo # ^ + ::= aS # = + ::= pL # += + ::= mI # -= + ::= mL # *= + ::= dV # /= + ::= rM # %= + ::= aN # &= + ::= oR # |= + ::= eO # ^= + ::= ls # << + ::= rs # >> + ::= lS # <<= + ::= rS # >>= + ::= eq # == + ::= ne # != + ::= lt # < + ::= gt # > + ::= le # <= + ::= ge # >= + ::= nt # ! + ::= aa # && + ::= oo # || + ::= pp # ++ (postfix in context) + ::= mm # -- (postfix in context) + ::= cm # , + ::= pm # ->* + ::= pt # -> + ::= cl # () + ::= ix # [] + ::= qu # ? + ::= st # sizeof (a type) + ::= sz # sizeof (an expression) + ::= at # alignof (a type) + ::= az # alignof (an expression) + ::= cv # (cast) + ::= v # vendor extended operator +*/ + +/* + ::= v # void + ::= w # wchar_t + ::= b # bool + ::= c # char + ::= a # signed char + ::= h # unsigned char + ::= s # short + ::= t # unsigned short + ::= i # int + ::= j # unsigned int + ::= l # long + ::= m # unsigned long + ::= x # long long, __int64 + ::= y # unsigned long long, __int64 + ::= n # __int128 + ::= o # unsigned __int128 + ::= f # float + ::= d # double + ::= e # long double, __float80 + ::= g # __float128 + ::= z # ellipsis + ::= Dd # IEEE 754r decimal floating point (64 bits) + ::= De # IEEE 754r decimal floating point (128 bits) + ::= Df # IEEE 754r decimal floating point (32 bits) + ::= Dh # IEEE 754r half-precision floating point (16 bits) + ::= Di # char32_t + ::= Ds # char16_t + ::= Da # auto (in dependent new-expressions) + ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) + ::= u # vendor extended type +*/ + +/* matches type numbering in manifest.h */ +static char chmap[] = { 'v', 'b', 'c', 'h', 's', 't', 'i', 'j', 'l', 'm', + 'x', 'y', 'f', 'd', 'e' }; + +static int +typch(int typ) +{ + int c = BTYPE(typ); + if (c == VOID) + c = 0; + return chmap[c]; +} + +#define MAXNM 255 /* max length of mangled name */ +static char nmblk[MAXNM]; +static int nmptr, subptr; + +/* push character */ +static void +nmch(int c) +{ + if (nmptr >= MAXNM) + cerror("Too long mangled name"); + nmblk[nmptr++] = c; +} + +/* Push length and string */ +static void +pshsln(char *c) +{ + int i, j, ln = strlen(c); + +#define cnt(v,n) for (v = 0; ln >= n; v++, ln -= n) + cnt(i,100); + cnt(j,10); + if (i) nmch(i+'0'); + if (j || i) nmch(j+'0'); + nmch(ln+'0'); + for (; *c; c++) + nmch(*c); +} + +/* Recurse to push namespace names */ +static void +recnpsh(struct symtab *sp) +{ + if (sp == spole) + return; + if (sp == sp->sdown) + cerror("sp == sp->sdown"); + if (sp->sdown) + recnpsh(sp->sdown); + pshsln(sp->sname); +} + +static void +pshargs(union arglist *al) +{ + TWORD t; + + + for (; al->type != TNULL; al++) { + t = al->type; + if (t == TELLIPSIS) { + nmch('z'); + continue; + } + while (t > BTMASK) { + if (ISPTR(t)) + nmch('P'); + else + uerror("pshargs2: %lx\n", t); + t = DECREF(t); + } + if (t > LDOUBLE) + uerror("pshargs: %lx\n", t); + /* XXX - cannot emit const/volatile */ + nmch(typch(t)); + } +} + +/* + * Do name mangling of a symbol table entry. + * The resulting name is saved in soname. + */ +char * +decoratename(struct symtab *sp, int type) +{ + char *n; + +#define QNM(m,s) case m: n = s; break + switch (type) { + QNM(NM_NEW,"_Znwm"); + QNM(NM_NWA,"_Znam"); + QNM(NM_DEL,"_ZdlPv"); + QNM(NM_DLA,"_ZdaPv"); + case NM_NORMAL: /* Defined in defid() */ + break; + default: + uerror("missed mangling %d\n", type); + return ""; + } + if (type != NM_NORMAL) + return addname(n); + + /* special non-mangled cases: + * "C" linkage + * main() function + * variables outside namespaces and classes + */ + if (elnk == LINK_C || strcmp(sp->sname, "main") == 0 || + (sp->sdown == spole && !ISFTN(sp->stype))) { + n = exname(sp->sname); + return addname(n); + } + /* Compute the mangled name for other symbols */ + nmptr = 0; + subptr = 0; + nmch('_'); nmch('Z'); + if (sp->sdown != NULL) { + nmch('N'); + recnpsh(sp->sdown); + } + pshsln(sp->sname); + if (sp->sdown != NULL) + nmch('E'); + if (ISFTN(sp->stype) && sp->sdf->dfun) + pshargs(sp->sdf->dfun); + nmch(0); + return addname(nmblk); +} + +/* + * find a symtab entry in the given link. + */ +static struct symtab * +sfind(char *n, struct symtab *sp) +{ + while (sp) { + if (cppdebug)printf("sfind: checking %s against %s\n", n, sp->sname); + if (sp->sname == n) + return sp; + sp = sp->snext; + } + return NULL; +} + +/* class or namespace? */ +#define CLORNS(sp) (sp->sclass == STNAME || sp->sclass == CLNAME || \ + sp->sclass == UNAME || sp->sclass == NSPACE) + +/* + * find a symtab path entry in the given path. + * p is expected to be a link of NMNAMEs. + * It is supposed to return a sup value of the last found class. + */ +static struct symtab * +pfind(NODE *p, struct symtab *sp) +{ + char *n; + + if (cppdebug)printf("pfind: op %d searching %s\n", p->n_op, p->n_op == NAME ? +(char *)p->n_sp:(char *)p->n_right->n_sp); + + if (p->n_op == NAME) { + n = (char *)p->n_sp; + if ((sp = sfind(n, sp)) == NULL) + return NULL; + if (cppdebug)printf("pfind: NAME class %d name %s\n", sp->sclass, sp->sname); + while (!CLORNS(sp)) { + if ((sp = sfind(n, sp->snext)) == NULL) + return NULL; + } + if (cppdebug)printf("pfind: FOUND %s\n", sp->sname); + sp = sp->sup; + } else { + n = (char *)p->n_right->n_sp; + if ((sp = sfind(n, sp)) == NULL) + return NULL; + if (cppdebug)printf("pfind: NMLIST class %d name %s\n", sp->sclass, sp->sname); + while (!CLORNS(sp)) { + if ((sp = sfind(n, sp->snext)) == NULL) + return NULL; + } + sp = pfind(p->n_left, sp->sup); + } + return sp; +} + +/* + * Declare a variable. + */ +struct symtab * +cxxdeclvar(NODE *p) +{ + struct symtab *sp; + + if (blevel && p->n_op == NAME) { + sp = p->n_sp = lookup((char *)p->n_sp, 0); + } else { + sp = cxxlookup(p, SNORMAL); + } + return sp; +} + +/* + * class is MOS if variable is member of a CLASS, NORMAL otherwise. + * A CLASS as member of a class has symbol type CLASS. + */ +char *symclass[] = { "NORMAL", "CLASS", "LABEL", "MOS", "STRING" }; + +/* + * Do a name lookup. p can be either just a NAME or NMLIST. + * The first symbol instance on its level is returned, which may or + * may not be correct. + * If no symbol is found, return a new symtab entry. + * p should be a NAME after this with n_sp filled in accordingly. + * It's the responsibility of the declaration routine to add it to + * the symbol table. + * nfree() will be called on p after this function. + */ +struct symtab * +cxxlookup(NODE *p, int flags) +{ + struct symtab *sp, *ns; + int ftyp = flags & SMASK; + NODE *q; + char *n, *s; + +#define SPNAME(p) ((char *)(p->n_op == NAME ? p->n_sp : p->n_right->n_sp)) +#ifdef PCC_DEBUG + if (cppdebug){ printf("cxxlookup %s\n", SPNAME(p)); symtree(); } +#endif + + q = p; + if (p->n_op == NAME) { + s = (char *)p->n_sp; + if (blevel) { + sp = lookup(s, SNOCREAT); /* check if auto var */ + if (sp == NULL) { + /* check if in classes */ + for (ns = nscur; ns != spole; ns = ns->sdown) + if ((sp = sfind(s, ns->sup))) + break; + if (sp == NULL) + sp = sfind(s, spole->sup); + } + if (sp == NULL) + sp = lookup(s, 0); /* fallback */ + } else { + ns = nscur; + sp = sfind(s, ns); + while (sp != NULL) { + if ((sp->sflags & SMASK) == ftyp) + break; + sp = sfind(s, sp->snext); + } + if (sp == NULL) { + sp = getsymtab(s, ftyp); + if ((flags & SNOCREAT) == 0) { +#ifdef PCC_DEBUG + if (cppdebug)printf("cxxlookup: adding %s %s %s at %s\n", symclass[ftyp], s, sp->soname, nscur ? nscur->sname : "base"); +#endif + INSSYM(sp); + cxxsetname(sp); + } + } + } + } else { + /* Search through namespaces/classes for it */ + n = SPNAME(p); + ns = pfind(p->n_left, spole->sup); + if (ns == NULL) { + uerror("undeclared class in chain"); + return getsymtab(n, ftyp); + } + if ((sp = sfind(n, ns)) == NULL) { + sp = getsymtab(n, ftyp); + if ((flags & SNOCREAT) == 0) { + sp->snext = ns->snext; + ns->snext = sp; + } + } + } + + /* make top node a NAME */ + if (q->n_op != NAME) { + tfree(q->n_left); + p = q->n_right; + *q = *q->n_right; + nfree(p); + } + q->n_sp = sp; + return sp; +} + +void +cxxsetname(struct symtab *sp) +{ + if (elnk == LINK_C) + return; /* leave to target */ + sp->soname = decoratename(sp, NM_NORMAL); +} + +/* + * Create a symbol out of a struct. + * We call the symbol "__%THIS" to avoid interference. + */ +struct symtab * +cxxstrvar(struct symtab *so) +{ + struct symtab *sp; + NODE *p; + + sp = lookup("__%THIS", 0); + p = block(NAME, 0, 0, INCREF(so->stype), so->sdf, so->sap); + p->n_sp = sp; + defid(p, PARAM); + nfree(p); + return sp; +} + +/* + * Declare a struct (class) based on its name n. + * Assumed that nmcur is correctly pointing to either: + * - nothing (class at level 0) + * - current namespace + * - parent class + */ +struct symtab * +cxxdclstr(char *n) +{ + struct symtab *sp; + + sp = sfind(n, nscur->sup); + while (sp && !CLORNS(sp)) + sp = sfind(n, sp->snext); + if (sp == 0) + sp = getsymtab(n, STAGNAME); +// else +// uerror("class/namespace redefined"); +// INSSYM(sp); +// nscur = sp; + +if (cppdebug)printf("declaring2 struct %s %p nscur %s\n", n, sp, nscur->sname); + return sp; +} + +#ifdef PCC_DEBUG +static void +symwalk(struct symtab *sp, int indent) +{ + int i; + + while (sp) { + for (i = 0; i < indent; i++) + printf(" "); + printf("%s (%p) %s\n", sp->sname, sp, scnames(sp->sclass)); + if (sp->sup) + symwalk(sp->sup, indent+1); + sp = sp->snext; + } +} + +void +symtree(void) +{ + symwalk(spole, 0); +} +#endif + +/* + * Compare a matching prototype for a function. + */ +static int +cxxpcmp(struct symtab *sp, NODE *p) +{ + union arglist *a1, *a2; + int i; + + if (!ISFTN(sp->stype) || p->n_df == NULL || sp->sdf == NULL) + return 0; /* no dimfun */ + if ((a1 = sp->sdf->dfun) == NULL || (a2 = p->n_df->dfun) == NULL) + return 0; /* no argument */ + + for (i = 0; ; i++) { + if (a1[i].type == TNULL && a2[i].type == TNULL) + return 1; /* equal prototypes */ + if (a1[i].type != a2[i].type) + return 1; /* unequal prototypes */ + } +} + +struct ckstr { + int rv; + union arglist *al; +}; + +static void +cxxckproto(NODE *p, void *arg) +{ + struct ckstr *cp = arg; + + if (cp->rv == -1) + return; + + if (cp->al[0].type != p->n_type) + goto fail; + if (BTYPE(cp->al[0].type) > LDOUBLE) + uerror("cxxckproto"); + cp->al++; + return; +fail: + cp->rv = -1; +} + +/* + * Compare a matching prototype for an argument tree. + * Here we can expand to also do inexact matches. + * Return 0 if equal, -1 if failed. + */ +static int +cxxptreecmp(struct symtab *sp, NODE *p) +{ + struct ckstr ckstr; + union arglist *a1; + + if (!ISFTN(sp->stype) || sp->sdf == NULL || + (a1 = sp->sdf->dfun) == NULL) + return 0; /* no dimfun */ + + if (p == NULL && a1[0].type == TNULL) + return 1; /* arg-less */ + + ckstr.rv = 0; + ckstr.al = a1; + flist(p, cxxckproto, &ckstr); + + if (ckstr.al[0].type != TNULL) + return -1; /* arg number error */ + return ckstr.rv; +} + +/* + * Search for (and declare) a function. + */ +struct symtab * +cxxftnfind(NODE *p, int flags) +{ + struct symtab *sp, *ns; + char *s; + + if (p->n_op == NAME) { + s = (char *)p->n_sp; + /* Search for equally named functions */ + sp = sfind(s, nscur->sup); + while (sp != NULL) { + if (cxxpcmp(sp, p)) { + if (sp->sclass != NSPACE || + sp->sclass == EXTDEF) { + uerror("%s redefined", s); + return sp; + } else + break; + } + sp = sfind(s, sp->snext); + } + if (sp == NULL) { + sp = getsymtab(s, SNORMAL); + sp->stype = p->n_type; + sp->squal = p->n_qual; + sp->sdf = p->n_df; + sp->sap = p->n_ap; + INSSYM(sp); + if (nscur->sclass != NSPACE && nscur != &spole0) + uerror("inside struct"); + } + sp->sclass = EXTDEF; + if (sp->soname == 0) + sp->soname = decoratename(sp, NM_NORMAL); + } else { + /* + * declared outside class, tree-style reference + * Must have been defined already + * This will be an external declaration (not spooled). + */ + s = SPNAME(p); + if ((ns = pfind(p->n_left, spole->sup)) == NULL) { + uerror("undeclared class in chain"); + goto undecl; + } + /* Search for an EXTERN or EXTDEF declaration within */ + /* EXTDEF causes redeclaration. */ + sp = sfind(s, ns); + while (sp != NULL) { + if (sp->sclass == EXTERN || sp->sclass == EXTDEF) { + if (cxxpcmp(sp, p->n_right)) { + if (sp->sclass == EXTDEF) + uerror("%s redefined", s); + break; + } + } + sp = sfind(s, sp->snext); + } + if (sp == NULL) { + uerror("%s undeclared", s); + goto undecl; + } + sp->sclass = EXTDEF; + } + return sp; + +undecl: + return getsymtab(s, SNORMAL); +} + +/* + * Reference to a struct as a :: name. + */ +NODE * +cxxrstruct(int soru, NODE *attr, NODE *t, char *n) +{ + struct symtab *ns, *sp; + + ns = pfind(t, spole->sup); + if (ns == NULL) + goto undecl; + + tfree(t); + sp = sfind(n, ns); + while (sp != NULL) { + if (sp->sclass == soru) + return mkty(sp->stype, 0, sp->sap); + sp = sfind(n, sp->snext); + } +undecl: + uerror("%s undeclared", n); + return mkty(INT, 0, 0); +} + +/* + * Search for correct matching function in a struct depending on + * argument list a. Return a call node for this function. + * Do not touch neither f nor a. + * return a name tree suitable for a function call. + * We know here that f is a struct reference. + */ +NODE * +cxxmatchftn(NODE *f, NODE *a) +{ + struct attr *ap; + struct symtab *sp; + char *n = (char *)f->n_right->n_sp; + + f = f->n_left; + + if ((ap = attr_find(f->n_ap, ATTR_STRUCT)) == NULL) { + uerror("undefined class"); + sp = getsymtab(n, 0); + } else + sp = ap->amlist; + sp = sfind(n, sp); + while (sp != NULL) { + if (ISFTN(sp->stype) && cxxptreecmp(sp, a) == 0) + break; + sp = sfind(n, sp->snext); + } + if (sp == NULL) + uerror("undefined class member"); + return nametree(sp); +} + +/* + * Add hidden argument f first in node list a. Return resulting a. + */ +NODE * +cxxaddhidden(NODE *a, NODE *f) +{ + NODE *q; + + if (a == NULL) + return f; + if (a->n_op != CM) + return block(CM, f, a, INT, 0, 0); + for (q = a; q->n_left->n_op == CM; q = q->n_left) + ; + q->n_left = block(CM, f, q->n_left, INT, 0, 0); + return a; +} + +/* + * Watch out for references to static members. + */ +NODE * +cxxstructref(NODE *p, int f, char *n) +{ + struct symtab *sp = strmemb(p->n_ap); + + if (sp == NULL) + cerror("ref to unknown struct"); + sp = sfind(n, sp); + while (sp != NULL) { + if (!ISFTN(sp->stype)) { + if (sp->sclass == STATIC || sp->sclass == USTATIC) { + tfree(p); + return nametree(sp); + } + break; + } + sp = sfind(n, sp->snext); + } + return structref(p, f, n); +} diff --git a/lang/pcc/pcc/cc/cxxcom/cxxdefs.h b/lang/pcc/pcc/cc/cxxcom/cxxdefs.h new file mode 100644 index 000000000..daca34ed8 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/cxxdefs.h @@ -0,0 +1,46 @@ + + +enum { NM_NEW, NM_NWA, NM_DEL, NM_DLA, NM_NORMAL, }; + +enum { LINK_DEF, LINK_C }; /* linkage definitions */ +extern int elnk; +#define SCLINK 00020 /* for symtab */ + +extern int cppdebug; + +/* spole is symbol at base, nscur is where we are in the stack. */ +extern struct symtab *spole, *nscur; + +/* insert a symbol into this something */ +#define INSSYM(sp) (sp->snext = nscur->sup, nscur->sup = sp, sp->sdown = nscur) +#define POPSYM() (nscur = nscur->sdown) + +/* C++-specific node types */ +#define CONST_CAST (MAXOP+35) +#define DYN_CAST (MAXOP+36) +#define REINT_CAST (MAXOP+37) +#define STATIC_CAST (MAXOP+38) +#define NEWKW (MAXOP+39) +#define DELETE (MAXOP+40) +#define NMLIST (MAXOP+41) + +/* C++-specific symtab types */ +#define CLNAME (MAXSTCL+1) /* symtab entry is class */ +#define NSPACE (MAXSTCL+2) /* symtab entry is namespace */ + +char *decoratename(struct symtab *sp, int type); +NODE *cxx_new(NODE *p); +NODE *cxx_delete(NODE *p, int del); +void dclns(NODE *attr, char *n); +struct symtab *cxxlookup(NODE *p, int declare); +void cxxsetname(struct symtab *sp); +void cxxmember(struct symtab *sp); +struct symtab *cxxstrvar(struct symtab *so); +struct symtab *cxxdclstr(char *n); +struct symtab *cxxftnfind(NODE *p, int flags); +struct symtab *cxxdeclvar(NODE *p); +void symtree(void); +NODE *cxxrstruct(int soru, NODE *attr, NODE *t, char *tag); +NODE *cxxmatchftn(NODE *, NODE *); +NODE *cxxaddhidden(NODE *, NODE *); +NODE *cxxstructref(NODE *p, int f, char *name); diff --git a/lang/pcc/pcc/cc/cxxcom/gcc_compat.c b/lang/pcc/pcc/cc/cxxcom/gcc_compat.c new file mode 100644 index 000000000..7c5283119 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/gcc_compat.c @@ -0,0 +1,573 @@ +/* $Id: gcc_compat.c,v 1.10 2015/01/05 21:31:01 plunky Exp $ */ +/* + * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Routines to support some of the gcc extensions to C. + */ +#ifdef GCC_COMPAT + +#include "pass1.h" +#include "cgram.h" + +#include + +static struct kw { + char *name, *ptr; + int rv; +} kw[] = { +/* + * Do NOT change the order of these entries unless you know + * what you're doing! + */ +/* 0 */ { "__asm", NULL, C_ASM }, +/* 1 */ { "__signed", NULL, 0 }, +/* 2 */ { "__inline", NULL, C_FUNSPEC }, +/* 3 */ { "__const", NULL, 0 }, +/* 4 */ { "__asm__", NULL, C_ASM }, +/* 5 */ { "__inline__", NULL, C_FUNSPEC }, +/* 6 */ { "__thread", NULL, 0 }, +/* 7 */ { "__FUNCTION__", NULL, 0 }, +/* 8 */ { "__volatile", NULL, 0 }, +/* 9 */ { "__volatile__", NULL, 0 }, +/* 10 */{ "__restrict", NULL, -1 }, +/* 11 */{ "__typeof__", NULL, C_TYPEOF }, +/* 12 */{ "typeof", NULL, C_TYPEOF }, +/* 13 */{ "__extension__", NULL, -1 }, +/* 14 */{ "__signed__", NULL, 0 }, +/* 15 */{ "__attribute__", NULL, 0 }, +/* 16 */{ "__attribute", NULL, 0 }, +/* 17 */{ "__real__", NULL, 0 }, +/* 18 */{ "__imag__", NULL, 0 }, +/* 19 */{ "__builtin_offsetof", NULL, PCC_OFFSETOF }, +/* 20 */{ "__PRETTY_FUNCTION__", NULL, 0 }, +/* 21 */{ "__alignof__", NULL, C_ALIGNOF }, +/* 22 */{ "__typeof", NULL, C_TYPEOF }, +/* 23 */{ "__alignof", NULL, C_ALIGNOF }, +/* 24 */{ "__restrict__", NULL, -1 }, + { NULL, NULL, 0 }, +}; + +/* g77 stuff */ +#if SZFLOAT == SZLONG +#define G77_INTEGER LONG +#define G77_UINTEGER ULONG +#elif SZFLOAT == SZINT +#define G77_INTEGER INT +#define G77_UINTEGER UNSIGNED +#else +#error fix g77 stuff +#endif +#if SZFLOAT*2 == SZLONG +#define G77_LONGINT LONG +#define G77_ULONGINT ULONG +#elif SZFLOAT*2 == SZLONGLONG +#define G77_LONGINT LONGLONG +#define G77_ULONGINT ULONGLONG +#else +#error fix g77 long stuff +#endif + +static TWORD g77t[] = { G77_INTEGER, G77_UINTEGER, G77_LONGINT, G77_ULONGINT }; +static char *g77n[] = { "__g77_integer", "__g77_uinteger", + "__g77_longint", "__g77_ulongint" }; + +void +gcc_init(void) +{ + struct kw *kwp; + NODE *p; + TWORD t; + int i; + + for (kwp = kw; kwp->name; kwp++) + kwp->ptr = addname(kwp->name); + + for (i = 0; i < 4; i++) { + struct symtab *sp; + t = ctype(g77t[i]); + p = block(NAME, NIL, NIL, t, NULL, 0); + sp = lookup(addname(g77n[i]), 0); + p->n_sp = sp; + defid(p, TYPEDEF); + nfree(p); + } +} + +#define TS "\n#pragma tls\n# %d\n" +#define TLLEN sizeof(TS)+10 +/* + * See if a string matches a gcc keyword. + */ +int +gcc_keyword(char *str, NODE **n) +{ + extern int inattr, parlvl, parbal; + YYSTYPE *yyl = (YYSTYPE *)n; /* XXX should pass yylval */ + char tlbuf[TLLEN], *tw; + struct kw *kwp; + int i; + + /* XXX hack, should pass everything in expressions */ + if (str == kw[21].ptr) + return kw[21].rv; + + if (inattr) + return 0; + + for (i = 0, kwp = kw; kwp->name; kwp++, i++) + if (str == kwp->ptr) + break; + if (kwp->name == NULL) + return 0; + if (kwp->rv) + return kwp->rv; + switch (i) { + case 1: /* __signed */ + case 14: /* __signed__ */ + *n = mkty((TWORD)SIGNED, 0, 0); + return C_TYPE; + case 3: /* __const */ + *n = block(QUALIFIER, NIL, NIL, CON, 0, 0); + (*n)->n_qual = CON; + return C_QUALIFIER; + case 6: /* __thread */ + snprintf(tlbuf, TLLEN, TS, lineno); + tw = &tlbuf[strlen(tlbuf)]; + while (tw > tlbuf) + cunput(*--tw); + return -1; + case 7: /* __FUNCTION__ */ + case 20: /* __PRETTY_FUNCTION__ */ + if (cftnsp == NULL) { + uerror("%s outside function", kwp->name); + yylval.strp = ""; + } else + yylval.strp = cftnsp->sname; /* XXX - not C99 */ + return C_STRING; + case 8: /* __volatile */ + case 9: /* __volatile__ */ + *n = block(QUALIFIER, NIL, NIL, VOL, 0, 0); + (*n)->n_qual = VOL; + return C_QUALIFIER; + case 15: /* __attribute__ */ + case 16: /* __attribute */ + inattr = 1; + parlvl = parbal; + return C_ATTRIBUTE; + case 17: /* __real__ */ + yyl->intval = XREAL; + return C_UNOP; + case 18: /* __imag__ */ + yyl->intval = XIMAG; + return C_UNOP; + } + cerror("gcc_keyword"); + return 0; +} + +#ifndef TARGET_ATTR +#define TARGET_ATTR(p, sue) 0 +#endif +#ifndef ALMAX +#define ALMAX (ALLDOUBLE > ALLONGLONG ? ALLDOUBLE : ALLONGLONG) +#endif + +/* allowed number of args */ +#define A_0ARG 0x01 +#define A_1ARG 0x02 +#define A_2ARG 0x04 +#define A_3ARG 0x08 +/* arg # is a name */ +#define A1_NAME 0x10 +#define A2_NAME 0x20 +#define A3_NAME 0x40 +#define A_MANY 0x80 +/* arg # is "string" */ +#define A1_STR 0x100 +#define A2_STR 0x200 +#define A3_STR 0x400 + +#ifdef __MSC__ +#define CS(x) +#else +#define CS(x) [x] = +#endif + +struct atax { + int typ; + char *name; +} atax[GCC_ATYP_MAX] = { + CS(ATTR_NONE) { 0, NULL }, + CS(ATTR_COMPLEX) { 0, NULL }, + CS(xxxATTR_BASETYP) { 0, NULL }, + CS(ATTR_QUALTYP) { 0, NULL }, + CS(ATTR_STRUCT) { 0, NULL }, + CS(ATTR_ALIGNED) { A_0ARG|A_1ARG, "aligned" }, + CS(GCC_ATYP_PACKED) { A_0ARG|A_1ARG, "packed" }, + CS(GCC_ATYP_SECTION) { A_1ARG|A1_STR, "section" }, + CS(GCC_ATYP_TRANSP_UNION) { A_0ARG, "transparent_union" }, + CS(GCC_ATYP_UNUSED) { A_0ARG, "unused" }, + CS(GCC_ATYP_DEPRECATED) { A_0ARG, "deprecated" }, + CS(GCC_ATYP_MAYALIAS) { A_0ARG, "may_alias" }, + CS(GCC_ATYP_MODE) { A_1ARG|A1_NAME, "mode" }, + CS(GCC_ATYP_NORETURN) { A_0ARG, "noreturn" }, + CS(GCC_ATYP_FORMAT) { A_3ARG|A1_NAME, "format" }, + CS(GCC_ATYP_NONNULL) { A_MANY, "nonnull" }, + CS(GCC_ATYP_SENTINEL) { A_0ARG|A_1ARG, "sentinel" }, + CS(GCC_ATYP_WEAK) { A_0ARG, "weak" }, + CS(GCC_ATYP_FORMATARG) { A_1ARG, "format_arg" }, + CS(GCC_ATYP_GNU_INLINE) { A_0ARG, "gnu_inline" }, + CS(GCC_ATYP_MALLOC) { A_0ARG, "malloc" }, + CS(GCC_ATYP_NOTHROW) { A_0ARG, "nothrow" }, + CS(GCC_ATYP_CONST) { A_0ARG, "const" }, + CS(GCC_ATYP_PURE) { A_0ARG, "pure" }, + CS(GCC_ATYP_CONSTRUCTOR) { A_0ARG, "constructor" }, + CS(GCC_ATYP_DESTRUCTOR) { A_0ARG, "destructor" }, + CS(GCC_ATYP_VISIBILITY) { A_1ARG|A1_STR, "visibility" }, + CS(GCC_ATYP_STDCALL) { A_0ARG, "stdcall" }, + CS(GCC_ATYP_CDECL) { A_0ARG, "cdecl" }, + CS(GCC_ATYP_WARN_UNUSED_RESULT) { A_0ARG, "warn_unused_result" }, + CS(GCC_ATYP_USED) { A_0ARG, "used" }, + CS(GCC_ATYP_NO_INSTR_FUN) { A_0ARG, "no_instrument_function" }, + CS(GCC_ATYP_NOINLINE) { A_0ARG, "noinline" }, + CS(GCC_ATYP_ALIAS) { A_1ARG|A1_STR, "alias" }, + CS(GCC_ATYP_WEAKREF) { A_0ARG|A_1ARG|A1_STR, "weakref" }, + CS(GCC_ATYP_ALLOCSZ) { A_1ARG|A_2ARG, "alloc_size" }, + CS(GCC_ATYP_ALW_INL) { A_0ARG, "always_inline" }, + CS(GCC_ATYP_TLSMODEL) { A_1ARG|A1_STR, "tls_model" }, + CS(GCC_ATYP_ALIASWEAK) { A_1ARG|A1_STR, "aliasweak" }, + CS(GCC_ATYP_REGPARM) { A_1ARG, "regparm" }, + CS(GCC_ATYP_FASTCALL) { A_0ARG, "fastcall" }, + + CS(GCC_ATYP_BOUNDED) { A_3ARG|A_MANY|A1_NAME, "bounded" }, +}; + +#if SZPOINT(CHAR) == SZLONGLONG +#define GPT LONGLONG +#else +#define GPT INT +#endif + +struct atax mods[] = { + { 0, NULL }, + { INT, "SI" }, + { INT, "word" }, + { GPT, "pointer" }, + { CHAR, "byte" }, + { CHAR, "QI" }, + { SHORT, "HI" }, + { LONGLONG, "DI" }, + { FLOAT, "SF" }, + { DOUBLE, "DF" }, + { LDOUBLE, "XF" }, + { FCOMPLEX, "SC" }, + { COMPLEX, "DC" }, + { LCOMPLEX, "XC" }, +#ifdef TARGET_MODS + TARGET_MODS +#endif +}; +#define ATSZ (sizeof(mods)/sizeof(mods[0])) + +static int +amatch(char *s, struct atax *at, int mx) +{ + int i, len; + + if (s[0] == '_' && s[1] == '_') + s += 2; + len = strlen(s); + if (len > 2 && s[len-1] == '_' && s[len-2] == '_') + len -= 2; + for (i = 0; i < mx; i++) { + char *t = at[i].name; + if (t != NULL && strncmp(s, t, len) == 0 && t[len] == 0) + return i; + } + return 0; +} + +static void +setaarg(int str, union aarg *aa, NODE *p) +{ + if (str) { + if (((str & (A1_STR|A2_STR|A3_STR)) && p->n_op != STRING) || + ((str & (A1_NAME|A2_NAME|A3_NAME)) && p->n_op != NAME)) + uerror("bad arg to attribute"); + if (p->n_op == STRING) { + aa->sarg = newstring(p->n_name, strlen(p->n_name)); + } else + aa->sarg = (char *)p->n_sp; + nfree(p); + } else + aa->iarg = (int)icons(eve(p)); +} + +/* + * Parse attributes from an argument list. + */ +static struct attr * +gcc_attribs(NODE *p) +{ + NODE *q, *r; + struct attr *ap; + char *name = NULL, *c; + int cw, attr, narg, i; + + if (p->n_op == NAME) { + name = (char *)p->n_sp; + } else if (p->n_op == CALL || p->n_op == UCALL) { + name = (char *)p->n_left->n_sp; + } else if (p->n_op == ICON && p->n_type == STRTY) { + return NULL; + } else + cerror("bad variable attribute"); + + if ((attr = amatch(name, atax, GCC_ATYP_MAX)) == 0) { + warner(Wattributes, name); + ap = NULL; + goto out; + } + narg = 0; + if (p->n_op == CALL) + for (narg = 1, q = p->n_right; q->n_op == CM; q = q->n_left) + narg++; + + cw = atax[attr].typ; + if (!(cw & A_MANY) && ((narg > 3) || ((cw & (1 << narg)) == 0))) { + uerror("wrong attribute arg count"); + return NULL; + } + ap = attr_new(attr, 3); /* XXX should be narg */ + q = p->n_right; + + switch (narg) { + default: + /* XXX */ + while (narg-- > 3) { + r = q; + q = q->n_left; + tfree(r->n_right); + nfree(r); + } + /* FALLTHROUGH */ + case 3: + setaarg(cw & (A3_NAME|A3_STR), &ap->aa[2], q->n_right); + r = q; + q = q->n_left; + nfree(r); + /* FALLTHROUGH */ + case 2: + setaarg(cw & (A2_NAME|A2_STR), &ap->aa[1], q->n_right); + r = q; + q = q->n_left; + nfree(r); + /* FALLTHROUGH */ + case 1: + setaarg(cw & (A1_NAME|A1_STR), &ap->aa[0], q); + p->n_op = UCALL; + /* FALLTHROUGH */ + case 0: + break; + } + + /* some attributes must be massaged special */ + switch (attr) { + case ATTR_ALIGNED: + if (narg == 0) + ap->aa[0].iarg = ALMAX; + else + ap->aa[0].iarg *= SZCHAR; + break; + case GCC_ATYP_PACKED: + if (narg == 0) + ap->aa[0].iarg = 1; /* bitwise align */ + else + ap->aa[0].iarg *= SZCHAR; + break; + + case GCC_ATYP_MODE: + if ((i = amatch(ap->aa[0].sarg, mods, ATSZ)) == 0) + werror("unknown mode arg %s", ap->aa[0].sarg); + ap->aa[0].iarg = ctype(mods[i].typ); + break; + + case GCC_ATYP_VISIBILITY: + c = ap->aa[0].sarg; + if (strcmp(c, "default") && strcmp(c, "hidden") && + strcmp(c, "internal") && strcmp(c, "protected")) + werror("unknown visibility %s", c); + break; + + case GCC_ATYP_TLSMODEL: + c = ap->aa[0].sarg; + if (strcmp(c, "global-dynamic") && strcmp(c, "local-dynamic") && + strcmp(c, "initial-exec") && strcmp(c, "local-exec")) + werror("unknown tls model %s", c); + break; + + default: + break; + } +out: + return ap; +} + +/* + * Extract attributes from a node tree and return attribute entries + * based on its contents. + */ +struct attr * +gcc_attr_parse(NODE *p) +{ + struct attr *b, *c; + + if (p == NIL) + return NULL; + + if (p->n_op != CM) { + b = gcc_attribs(p); + tfree(p); + } else { + b = gcc_attr_parse(p->n_left); + c = gcc_attr_parse(p->n_right); + nfree(p); + b = b ? attr_add(b, c) : c; + } + return b; +} + +/* + * Fixup struct/unions depending on attributes. + */ +void +gcc_tcattrfix(NODE *p) +{ + struct symtab *sp; + struct attr *ap; + int sz, coff, csz, al, oal, mxal; + + if ((ap = attr_find(p->n_ap, GCC_ATYP_PACKED)) == NULL) + return; /* nothing to fix */ + + al = ap->iarg(0); + mxal = 0; + + /* Must repack struct */ + coff = csz = 0; + for (sp = strmemb(ap); sp; sp = sp->snext) { + oal = talign(sp->stype, sp->sap); + if (oal > al) + oal = al; + if (mxal < oal) + mxal = oal; + if (sp->sclass & FIELD) + sz = sp->sclass&FLDSIZ; + else + sz = (int)tsize(sp->stype, sp->sdf, sp->sap); + sp->soffset = upoff(sz, oal, &coff); + if (coff > csz) + csz = coff; + if (p->n_type == UNIONTY) + coff = 0; + } + if (mxal < ALCHAR) + mxal = ALCHAR; /* for bitfields */ + SETOFF(csz, mxal); /* Roundup to whatever */ + + ap = attr_find(p->n_ap, ATTR_STRUCT); + ap->amsize = csz; + ap = attr_find(p->n_ap, ATTR_ALIGNED); + ap->iarg(0) = mxal; + +} + +/* + * gcc-specific pragmas. + */ +int +pragmas_gcc(char *t) +{ + char u; + extern char *pragstore; + + if (strcmp((t = pragtok(NULL)), "diagnostic") == 0) { + int warn, err; + + if (strcmp((t = pragtok(NULL)), "ignored") == 0) + warn = 0, err = 0; + else if (strcmp(t, "warning") == 0) + warn = 1, err = 0; + else if (strcmp(t, "error") == 0) + warn = 1, err = 1; + else + return 1; + + if (eat('\"') || eat('-')) + return 1; + + for (t = pragstore; *t && *t != '\"'; t++) + ; + + u = *t; + *t = 0; + Wset(pragstore + 1, warn, err); + *t = u; + } else if (strcmp(t, "poison") == 0) { + /* currently ignore */; + } else if (strcmp(t, "visibility") == 0) { + /* currently ignore */; + } else if (strcmp(t, "system_header") == 0) { + /* currently ignore */; + } else + werror("gcc pragma unsupported"); + return 0; +} + +#ifdef PCC_DEBUG +void +dump_attr(struct attr *ap) +{ + printf("attributes; "); + for (; ap; ap = ap->next) { + if (ap->atype >= GCC_ATYP_MAX) { + printf("bad type %d, ", ap->atype); + } else if (atax[ap->atype].name == 0) { + char *c = ap->atype == ATTR_COMPLEX ? "complex" : + ap->atype == ATTR_STRUCT ? "struct" : "badtype"; + printf("%s, ", c); + } else { + printf("%s: ", atax[ap->atype].name); + printf("%d %d %d, ", ap->iarg(0), + ap->iarg(1), ap->iarg(2)); + } + } + printf("\n"); +} +#endif +#endif diff --git a/lang/pcc/pcc/cc/cxxcom/init.c b/lang/pcc/pcc/cc/cxxcom/init.c new file mode 100644 index 000000000..957e70a38 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/init.c @@ -0,0 +1,1224 @@ +/* $Id: init.c,v 1.6 2015/11/24 17:30:20 ragge Exp $ */ + +/* + * Copyright (c) 2004, 2007 Anders Magnusson (ragge@ludd.ltu.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 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. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "pass1.h" +#include + +/* + * The following machine-dependent routines may be called during + * initialization: + * + * zbits(OFFSZ, int) - sets int bits of zero at position OFFSZ. + * infld(CONSZ off, int fsz, CONSZ val) + * - sets the bitfield val starting at off and size fsz. + * ninval(CONSZ off, int fsz, NODE *) + * - prints an integer constant which may have + * a label associated with it, located at off and + * size fsz. + * + * Initialization may be of different kind: + * - Initialization at compile-time, all values are constants and laid + * out in memory. Static or extern variables outside functions. + * - Initialization at run-time, written to their values as code. + * + * Currently run-time-initialized variables are only initialized by using + * move instructions. An optimization might be to detect that it is + * initialized with constants and therefore copied from readonly memory. + */ + +/* + * The base element(s) of an initialized variable is kept in a linked + * list, allocated while initialized. + * + * When a scalar is found, entries are popped of the instk until it's + * possible to find an entry for a new scalar; then onstk() is called + * to get the correct type and size of that scalar. + * + * If a right brace is found, pop the stack until a matching left brace + * were found while filling the elements with zeros. This left brace is + * also marking where the current level is for designated initializations. + * + * Position entries are increased when traversing back down into the stack. + */ + +/* + * Good-to-know entries from symtab: + * soffset - # of bits from beginning of this structure. + */ + +/* + * TO FIX: + * - Alignment of structs on like i386 char members. + */ + +/* + * Struct used in array initialisation. + */ +static struct instk { + struct instk *in_prev; /* linked list */ + struct symtab *in_lnk; /* member in structure initializations */ + struct symtab *in_sym; /* symtab index */ + union dimfun *in_df; /* dimenston of array */ + TWORD in_t; /* type for this level */ + int in_n; /* number of arrays seen so far */ + int in_fl; /* flag which says if this level is controlled by {} */ +} *pstk, pbase; + +int doing_init, statinit; +static struct symtab *csym; + +#ifdef PCC_DEBUG +static void prtstk(struct instk *in); +#endif + +/* + * Linked lists for initializations. + */ +struct ilist { + struct ilist *next; + CONSZ off; /* bit offset of this entry */ + int fsz; /* bit size of this entry */ + NODE *n; /* node containing this data info */ +}; + +struct llist { + SLIST_ENTRY(llist) next; + CONSZ begsz; /* bit offset of this entry */ + struct ilist *il; +}; +static SLIST_HEAD(llh, llist) lpole; +static CONSZ basesz; +static int numents; /* # of array entries allocated */ + +static struct initctx { + struct initctx *prev; + struct instk *pstk; + struct symtab *psym; + struct llh lpole; + CONSZ basesz; + int numents; +} *inilnk; + +static struct ilist * +getil(struct ilist *next, CONSZ b, int sz, NODE *n) +{ + struct ilist *il = tmpalloc(sizeof(struct ilist)); + + il->off = b; + il->fsz = sz; + il->n = n; + il->next = next; + return il; +} + +/* + * Allocate a new struct defining a block of initializers appended to the + * end of the llist. Return that entry. + */ +static struct llist * +getll(void) +{ + struct llist *ll; + + ll = tmpalloc(sizeof(struct llist)); + ll->begsz = numents * basesz; + ll->il = NULL; + SLIST_INSERT_LAST(&lpole, ll, next); + numents++; + return ll; +} + +/* + * Return structure containing off bitnumber. + * Allocate more entries, if needed. + */ +static struct llist * +setll(OFFSZ off) +{ + struct llist *ll = NULL; + + /* Ensure that we have enough entries */ + while (off >= basesz * numents) + ll = getll(); + + if (ll != NULL && ll->begsz <= off && ll->begsz + basesz > off) + return ll; + + SLIST_FOREACH(ll, &lpole, next) + if (ll->begsz <= off && ll->begsz + basesz > off) + break; + return ll; /* ``cannot fail'' */ +} +char *astypnames[] = { 0, 0, "\t.byte", "\t.byte", "\t.short", "\t.short", + "\t.word", "\t.word", "\t.long", "\t.long", "\t.quad", "\t.quad", + "ERR", "ERR", "ERR", +}; + +void +inval(CONSZ off, int fsz, NODE *p) +{ + struct symtab *sp; + CONSZ val; + TWORD t; + + if (p->n_op != ICON && p->n_op != FCON) { + uerror("constant required"); + return; + } + if (p->n_type == BOOL) { + if ((U_CONSZ)glval(p) > 1) + slval(p, 1); + p->n_type = BOOL_TYPE; + } + if (ninval(off, fsz, p)) + return; /* dealt with in local.c */ + t = p->n_type; + if (t > BTMASK) + t = INTPTR; + + val = (CONSZ)(glval(p) & SZMASK(sztable[t])); + if (t <= ULONGLONG) { + sp = p->n_sp; + printf("%s ",astypnames[t]); + if (val || sp == NULL) + printf(CONFMT, val); + if (val && sp != NULL) + printf("+"); + if (sp != NULL) { + if ((sp->sclass == STATIC && sp->slevel > 0)) { + printf(LABFMT, sp->soffset); + } else + printf("%s", sp->soname ? + sp->soname : exname(sp->sname)); + } + printf("\n"); + } else + cerror("inval: unhandled type %d", (int)t); +} + +#ifndef MYBFINIT + +static int inbits; +static CONSZ xinval; +/* + * Initialize a bitfield. + * XXX - use U_CONSZ? + */ +void +infld(CONSZ off, int fsz, CONSZ val) +{ +#ifdef PCC_DEBUG + if (idebug) + printf("infld off " CONFMT ", fsz %d, val " CONFMT " inbits %d\n", + off, fsz, val, inbits); +#endif + val &= SZMASK(fsz); +#if TARGET_ENDIAN == TARGET_BE + while (fsz + inbits >= SZCHAR) { + int shsz = SZCHAR-inbits; + xinval = (xinval << shsz) | (val >> (fsz - shsz)); + printf("%s " CONFMT "\n", + astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR))); + fsz -= shsz; + val &= SZMASK(fsz); + xinval = inbits = 0; + } + if (fsz) { + xinval = (xinval << fsz) | val; + inbits += fsz; + } +#else + while (fsz + inbits >= SZCHAR) { + int shsz = SZCHAR-inbits; + xinval |= (val << inbits); + printf("%s " CONFMT "\n", + astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR))); + fsz -= shsz; + val >>= shsz; + xinval = inbits = 0; + } + if (fsz) { + xinval |= (val << inbits); + inbits += fsz; + } +#endif +} + +char *asspace = "\t.space"; + +/* + * set fsz bits in sequence to zero. + */ +void +zbits(OFFSZ off, int fsz) +{ + int m; + +#ifdef PCC_DEBUG + if (idebug) + printf("zbits off " CONFMT ", fsz %d inbits %d\n", off, fsz, inbits); +#endif +#if TARGET_ENDIAN == TARGET_BE + if ((m = (inbits % SZCHAR))) { + m = SZCHAR - m; + if (fsz < m) { + inbits += fsz; + xinval <<= fsz; + return; + } else { + fsz -= m; + xinval <<= m; + printf("%s " CONFMT "\n", + astypnames[CHAR], xinval & SZMASK(SZCHAR)); + xinval = inbits = 0; + } + } +#else + if ((m = (inbits % SZCHAR))) { + m = SZCHAR - m; + if (fsz < m) { + inbits += fsz; + return; + } else { + fsz -= m; + printf("%s " CONFMT "\n", + astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR))); + xinval = inbits = 0; + } + } +#endif + if (fsz >= SZCHAR) { + printf("%s %d\n", asspace, fsz/SZCHAR); + fsz -= (fsz/SZCHAR) * SZCHAR; + } + if (fsz) { + xinval = 0; + inbits = fsz; + } +} +#endif + +/* + * beginning of initialization; allocate space to store initialized data. + * remember storage class for writeout in endinit(). + * p is the newly declarated type. + */ +void +beginit(struct symtab *sp) +{ + struct initctx *ict; + struct instk *is = &pbase; + +#ifdef PCC_DEBUG + if (idebug) + printf("beginit(%p), sclass %s\n", sp, scnames(sp->sclass)); +#endif + + if (pstk) { +#ifdef PCC_DEBUG + if (idebug) + printf("beginit: saving ctx pstk %p\n", pstk); +#endif + /* save old context */ + ict = tmpalloc(sizeof(struct initctx)); + ict->prev = inilnk; + inilnk = ict; + ict->pstk = pstk; + ict->psym = csym; + ict->lpole = lpole; + ict->basesz = basesz; + ict->numents = numents; + is = tmpalloc(sizeof(struct instk)); + } + csym = sp; + + numents = 0; /* no entries in array list */ + if (ISARY(sp->stype)) { + basesz = tsize(DECREF(sp->stype), sp->sdf+1, sp->sap); + if (basesz == 0) { + uerror("array has incomplete type"); + basesz = SZINT; + } + } else + basesz = tsize(sp->stype, sp->sdf, sp->sap); + SLIST_INIT(&lpole); + + /* first element */ + if (ISSOU(sp->stype)) { + is->in_lnk = strmemb(sp->sap); + } else + is->in_lnk = NULL; + is->in_n = 0; + is->in_t = sp->stype; + is->in_sym = sp; + is->in_df = sp->sdf; + is->in_fl = 0; + is->in_prev = NULL; + pstk = is; + doing_init++; + if (sp->sclass == STATIC || sp->sclass == EXTDEF) + statinit++; +} + +/* + * Push a new entry on the initializer stack. + * The new entry will be "decremented" to the new sub-type of the previous + * entry when called. + * Popping of entries is done elsewhere. + */ +static void +stkpush(void) +{ + struct instk *is; + struct symtab *sq, *sp; + TWORD t; + + if (pstk == NULL) { + sp = csym; + t = 0; + } else { + t = pstk->in_t; + sp = pstk->in_sym; + } + +#ifdef PCC_DEBUG + if (idebug) { + printf("stkpush: '%s' %s ", sp->sname, scnames(sp->sclass)); + tprint(t, 0); + } +#endif + + /* + * Figure out what the next initializer will be, and push it on + * the stack. If this is an array, just decrement type, if it + * is a struct or union, extract the next element. + */ + is = tmpalloc(sizeof(struct instk)); + is->in_fl = 0; + is->in_n = 0; + if (pstk == NULL) { + /* stack empty */ + is->in_lnk = ISSOU(sp->stype) ? strmemb(sp->sap) : NULL; + is->in_t = sp->stype; + is->in_sym = sp; + is->in_df = sp->sdf; + } else if (ISSOU(t)) { + sq = pstk->in_lnk; + if (sq == NULL) { + uerror("excess of initializing elements"); + } else { + is->in_lnk = ISSOU(sq->stype) ? strmemb(sq->sap) : NULL; + is->in_t = sq->stype; + is->in_sym = sq; + is->in_df = sq->sdf; + } + } else if (ISARY(t)) { + is->in_lnk = ISSOU(DECREF(t)) ? strmemb(pstk->in_sym->sap) : 0; + is->in_t = DECREF(t); + is->in_sym = sp; + if (pstk->in_df->ddim != NOOFFSET && pstk->in_df->ddim && + pstk->in_n >= pstk->in_df->ddim) { + werror("excess of initializing elements"); + pstk->in_n--; + } + is->in_df = pstk->in_df+1; + } else + uerror("too many left braces"); + is->in_prev = pstk; + pstk = is; + +#ifdef PCC_DEBUG + if (idebug) { + printf(" newtype "); + tprint(is->in_t, 0); + printf("\n"); + } +#endif +} + +/* + * pop down to either next level that can handle a new initializer or + * to the next braced level. + */ +static void +stkpop(void) +{ +#ifdef PCC_DEBUG + if (idebug) + printf("stkpop\n"); +#endif + for (; pstk; pstk = pstk->in_prev) { + if (pstk->in_t == STRTY && pstk->in_lnk != NULL) { + pstk->in_lnk = pstk->in_lnk->snext; + if (pstk->in_lnk != NULL) + break; + } + if (ISSOU(pstk->in_t) && pstk->in_fl) + break; /* need } */ + if (ISARY(pstk->in_t)) { + pstk->in_n++; + if (pstk->in_fl) + break; + if (pstk->in_df->ddim == NOOFFSET || + pstk->in_n < pstk->in_df->ddim) + break; /* ger more elements */ + } + } +#ifdef PCC_DEBUG + if (idebug > 1) + prtstk(pstk); +#endif +} + +/* + * Count how many elements an array may consist of. + */ +static int +acalc(struct instk *is, int n) +{ + if (is == NULL || !ISARY(is->in_t)) + return 0; + return acalc(is->in_prev, n * is->in_df->ddim) + n * is->in_n; +} + +/* + * Find current bit offset of the top element on the stack from + * the beginning of the aggregate. + */ +static CONSZ +findoff(void) +{ + struct instk *is; + OFFSZ off; + +#ifdef PCC_DEBUG + if (ISARY(pstk->in_t)) + cerror("findoff on bad type %x", pstk->in_t); +#endif + + /* + * Offset calculations. If: + * - previous type is STRTY, soffset has in-struct offset. + * - this type is ARY, offset is ninit*stsize. + */ + for (off = 0, is = pstk; is; is = is->in_prev) { + if (is->in_prev && is->in_prev->in_t == STRTY) + off += is->in_sym->soffset; + if (ISARY(is->in_t)) { + /* suesize is the basic type, so adjust */ + TWORD t = is->in_t; + OFFSZ o; + while (ISARY(t)) + t = DECREF(t); + if (ISPTR(t)) { + o = SZPOINT(t); /* XXX use tsize() */ + } else { + o = tsize(t, is->in_sym->sdf, is->in_sym->sap); + } + off += o * acalc(is, 1); + while (is->in_prev && ISARY(is->in_prev->in_t)) { + if (is->in_prev->in_prev && + is->in_prev->in_prev->in_t == STRTY) + off += is->in_sym->soffset; + is = is->in_prev; + } + } + } +#ifdef PCC_DEBUG + if (idebug>1) { + printf("findoff: off " CONFMT "\n", off); + prtstk(pstk); + } +#endif + return off; +} + +/* + * Insert the node p with size fsz at position off. + * Bit fields are already dealt with, so a node of correct type + * with correct alignment and correct bit offset is given. + */ +static void +nsetval(CONSZ off, int fsz, NODE *p) +{ + struct llist *ll; + struct ilist *il; + + if (idebug>1) + printf("setval: off " CONFMT " fsz %d p %p\n", off, fsz, p); + + if (fsz == 0) + return; + + ll = setll(off); + off -= ll->begsz; + if (ll->il == NULL) { + ll->il = getil(NULL, off, fsz, p); + } else { + il = ll->il; + if (il->off > off) { + ll->il = getil(ll->il, off, fsz, p); + } else { + for (il = ll->il; il->next; il = il->next) + if (il->off <= off && il->next->off > off) + break; + if (il->off == off) { + /* replace */ + nfree(il->n); + il->n = p; + } else + il->next = getil(il->next, off, fsz, p); + } + } +} + +/* + * take care of generating a value for the initializer p + * inoff has the current offset (last bit written) + * in the current word being generated + * Returns the offset. + */ +CONSZ +scalinit(NODE *p) +{ + CONSZ woff; + NODE *q; + int fsz; + +#ifdef PCC_DEBUG + if (idebug > 2) { + printf("scalinit(%p)\n", p); + fwalk(p, eprint, 0); + prtstk(pstk); + } +#endif + + if (nerrors) + return 0; + + p = optim(p); + +#ifdef notdef /* leave to the target to decide if useable */ + if (csym->sclass != AUTO && p->n_op != ICON && + p->n_op != FCON && p->n_op != NAME) + cerror("scalinit not leaf"); +#endif + + /* Out of elements? */ + if (pstk == NULL) { + uerror("excess of initializing elements"); + return 0; + } + + /* + * Get to the simple type if needed. + */ + while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) { + stkpush(); + /* If we are doing auto struct init */ + if (ISSOU(pstk->in_t) && ISSOU(p->n_type) && + suemeq(pstk->in_sym->sap, p->n_ap)) + break; + } + + if (ISSOU(pstk->in_t) == 0) { + /* let buildtree do typechecking (and casting) */ + q = block(NAME, NIL,NIL, pstk->in_t, pstk->in_df, + pstk->in_sym->sap); + p = buildtree(ASSIGN, q, p); + nfree(p->n_left); + q = p->n_right; + nfree(p); + } else + q = p; +#ifndef WORD_ADDRESSED + if (csym->sclass != AUTO) + q = rmpconv(optim(rmpconv(q))); +#endif + q = optim(q); + + woff = findoff(); + + /* bitfield sizes are special */ + if (pstk->in_sym->sclass & FIELD) + fsz = -(pstk->in_sym->sclass & FLDSIZ); + else + fsz = (int)tsize(pstk->in_t, pstk->in_sym->sdf, + pstk->in_sym->sap); + + nsetval(woff, fsz, q); + + stkpop(); +#ifdef PCC_DEBUG + if (idebug > 2) { + printf("scalinit e(%p)\n", q); + } +#endif + return woff; +} + +/* + * Generate code to insert a value into a bitfield. + */ +static void +insbf(OFFSZ off, int fsz, int val) +{ + struct symtab sym; + NODE *p, *r; + TWORD typ; + +#ifdef PCC_DEBUG + if (idebug > 1) + printf("insbf: off " CONFMT " fsz %d val %d\n", off, fsz, val); +#endif + + if (fsz == 0) + return; + + /* small opt: do char instead of bf asg */ + if ((off & (ALCHAR-1)) == 0 && fsz == SZCHAR) + typ = CHAR; + else + typ = INT; + /* Fake a struct reference */ + p = buildtree(ADDROF, nametree(csym), NIL); + sym.stype = typ; + sym.squal = 0; + sym.sdf = 0; + sym.sap = NULL; + sym.soffset = (int)off; + sym.sclass = (char)(typ == INT ? FIELD | fsz : MOU); + r = xbcon(0, &sym, typ); + p = block(STREF, p, r, INT, 0, 0); + ecomp(buildtree(ASSIGN, stref(p), bcon(val))); +} + +/* + * Clear a bitfield, starting at off and size fsz. + */ +static void +clearbf(OFFSZ off, OFFSZ fsz) +{ + /* Pad up to the next even initializer */ + if ((off & (ALCHAR-1)) || (fsz < SZCHAR)) { + int ba = (int)(((off + (SZCHAR-1)) & ~(SZCHAR-1)) - off); + if (ba > fsz) + ba = (int)fsz; + insbf(off, ba, 0); + off += ba; + fsz -= ba; + } + while (fsz >= SZCHAR) { + insbf(off, SZCHAR, 0); + off += SZCHAR; + fsz -= SZCHAR; + } + if (fsz) + insbf(off, fsz, 0); +} + +/* + * final step of initialization. + * print out init nodes and generate copy code (if needed). + */ +void +endinit(int seg) +{ + struct llist *ll; + struct ilist *il; + int fsz; + OFFSZ lastoff, tbit; + +#ifdef PCC_DEBUG + if (idebug) + printf("endinit()\n"); +#endif + + /* Calculate total block size */ + if (ISARY(csym->stype) && csym->sdf->ddim == NOOFFSET) { + tbit = numents*basesz; /* open-ended arrays */ + csym->sdf->ddim = numents; + if (csym->sclass == AUTO) { /* Get stack space */ + csym->soffset = NOOFFSET; + oalloc(csym, &autooff); + } + } else + tbit = tsize(csym->stype, csym->sdf, csym->sap); + + /* Setup symbols */ + if (csym->sclass != AUTO) { + locctr(seg ? UDATA : DATA, csym); + defloc(csym); + } + + /* Traverse all entries and print'em out */ + lastoff = 0; + SLIST_FOREACH(ll, &lpole, next) { + for (il = ll->il; il; il = il->next) { +#ifdef PCC_DEBUG + if (idebug > 1) { + printf("off " CONFMT " size %d val " CONFMT " type ", + ll->begsz+il->off, il->fsz, glval(il->n)); + tprint(il->n->n_type, 0); + printf("\n"); + } +#endif + fsz = il->fsz; + if (csym->sclass == AUTO) { + struct symtab sym; + NODE *p, *r, *n; + + if (ll->begsz + il->off > lastoff) + clearbf(lastoff, + (ll->begsz + il->off) - lastoff); + + /* Fake a struct reference */ + p = buildtree(ADDROF, nametree(csym), NIL); + n = il->n; + sym.stype = n->n_type; + sym.squal = n->n_qual; + sym.sdf = n->n_df; + sym.sap = n->n_ap; + sym.soffset = (int)(ll->begsz + il->off); + sym.sclass = (char)(fsz < 0 ? FIELD | -fsz : 0); + r = xbcon(0, &sym, INT); + p = block(STREF, p, r, INT, 0, 0); + ecomp(buildtree(ASSIGN, stref(p), il->n)); + if (fsz < 0) + fsz = -fsz; + + } else { + if (ll->begsz + il->off > lastoff) + zbits(lastoff, + (ll->begsz + il->off) - lastoff); + if (fsz < 0) { + fsz = -fsz; + infld(il->off, fsz, glval(il->n)); + } else + inval(il->off, fsz, il->n); + tfree(il->n); + } + lastoff = ll->begsz + il->off + fsz; + } + } + if (csym->sclass == AUTO) { + clearbf(lastoff, tbit-lastoff); + } else + zbits(lastoff, tbit-lastoff); + + doing_init--; + if (csym->sclass == STATIC || csym->sclass == EXTDEF) + statinit--; + endictx(); +} + +void +endictx(void) +{ + struct initctx *ict = inilnk; + + if (ict == NULL) + return; + + pstk = ict->pstk; + csym = ict->psym; + lpole = ict->lpole; + basesz = ict->basesz; + numents = ict->numents; + inilnk = inilnk->prev; +#ifdef PCC_DEBUG + if (idebug) + printf("endinit: restoring ctx pstk %p\n", pstk); +#endif +} + +/* + * process an initializer's left brace + */ +void +ilbrace(void) +{ +#ifdef PCC_DEBUG + if (idebug) + printf("ilbrace()\n"); +#endif + + if (pstk == NULL) + return; + + stkpush(); + pstk->in_fl = 1; /* mark lbrace */ +#ifdef PCC_DEBUG + if (idebug > 1) + prtstk(pstk); +#endif +} + +/* + * called when a '}' is seen + */ +void +irbrace(void) +{ +#ifdef PCC_DEBUG + if (idebug) + printf("irbrace()\n"); + if (idebug > 2) + prtstk(pstk); +#endif + + if (pstk == NULL) + return; + + /* Got right brace, search for corresponding in the stack */ + for (; pstk->in_prev != NULL; pstk = pstk->in_prev) { + if(!pstk->in_fl) + continue; + + /* we have one now */ + + pstk->in_fl = 0; /* cancel { */ + if (ISARY(pstk->in_t)) + pstk->in_n = pstk->in_df->ddim; + else if (pstk->in_t == STRTY) { + while (pstk->in_lnk != NULL && + pstk->in_lnk->snext != NULL) + pstk->in_lnk = pstk->in_lnk->snext; + } + stkpop(); + return; + } +} + +/* + * Create a new init stack based on given elements. + */ +static void +mkstack(NODE *p) +{ + +#ifdef PCC_DEBUG + if (idebug) { + printf("mkstack: %p\n", p); + if (idebug > 1 && p) + fwalk(p, eprint, 0); + } +#endif + + if (p == NULL) + return; + mkstack(p->n_left); + + switch (p->n_op) { + case LB: /* Array index */ + if (p->n_right->n_op != ICON) + cerror("mkstack"); + if (!ISARY(pstk->in_t)) + uerror("array indexing non-array"); + pstk->in_n = (int)glval(p->n_right); + nfree(p->n_right); + break; + + case NAME: + if (pstk->in_lnk) { + for (; pstk->in_lnk; pstk->in_lnk = pstk->in_lnk->snext) + if (pstk->in_lnk->sname == (char *)p->n_sp) + break; + if (pstk->in_lnk == NULL) + uerror("member missing"); + } else { + uerror("not a struct/union"); + } + break; + default: + cerror("mkstack2"); + } + nfree(p); + stkpush(); + +} + +/* + * Initialize a specific element, as per C99. + */ +void +desinit(NODE *p) +{ + int op = p->n_op; + + if (pstk == NULL) + stkpush(); /* passed end of array */ + while (pstk->in_prev && pstk->in_fl == 0) + pstk = pstk->in_prev; /* Empty stack */ + + if (ISSOU(pstk->in_t)) + pstk->in_lnk = strmemb(pstk->in_sym->sap); + + mkstack(p); /* Setup for assignment */ + + /* pop one step if SOU, ilbrace will push */ + if (op == NAME || op == LB) + pstk = pstk->in_prev; + +#ifdef PCC_DEBUG + if (idebug > 1) { + printf("desinit e\n"); + prtstk(pstk); + } +#endif +} + +/* + * Convert a string to an array of char/wchar for asginit. + */ +static void +strcvt(NODE *p) +{ + NODE *q = p; + char *s; + int i; + +#ifdef mach_arm + /* XXX */ + if (p->n_op == UMUL && p->n_left->n_op == ADDROF) + p = p->n_left->n_left; +#endif + + for (s = p->n_sp->sname; *s != 0; ) { + if (*s++ == '\\') { + i = esccon(&s); + } else + i = (unsigned char)s[-1]; + asginit(bcon(i)); + } + tfree(q); +} + +/* + * Do an assignment to a struct element. + */ +void +asginit(NODE *p) +{ + int g; + +#ifdef PCC_DEBUG + if (idebug) + printf("asginit %p\n", p); + if (idebug > 1 && p) + fwalk(p, eprint, 0); +#endif + + /* convert string to array of char/wchar */ + if (p && (DEUNSIGN(p->n_type) == ARY+CHAR || + p->n_type == ARY+WCHAR_TYPE)) { + struct instk *is; + TWORD t; + + t = p->n_type == ARY+WCHAR_TYPE ? ARY+WCHAR_TYPE : ARY+CHAR; + /* + * ...but only if next element is ARY+CHAR, otherwise + * just fall through. + */ + + /* HACKHACKHACK */ + is = pstk; + + if (pstk == NULL) + stkpush(); + while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) + stkpush(); + if (pstk->in_prev && + (DEUNSIGN(pstk->in_prev->in_t) == t || + pstk->in_prev->in_t == t)) { + pstk = pstk->in_prev; + if ((g = pstk->in_fl) == 0) + pstk->in_fl = 1; /* simulate ilbrace */ + + strcvt(p); + if (g == 0) + irbrace(); /* will fill with zeroes */ + return; + } else + pstk = is; /* no array of char */ + /* END HACKHACKHACK */ + } + + if (p == NULL) { /* only end of compound stmt */ + irbrace(); + } else /* assign next element */ + scalinit(p); +} + +#ifdef PCC_DEBUG +void +prtstk(struct instk *in) +{ + int i, o = 0; + + printf("init stack:\n"); + for (; in != NULL; in = in->in_prev) { + for (i = 0; i < o; i++) + printf(" "); + printf("%p) '%s' ", in, in->in_sym->sname); + tprint(in->in_t, 0); + printf(" %s ", scnames(in->in_sym->sclass)); + if (in->in_df /* && in->in_df->ddim */) + printf("arydim=%d ", in->in_df->ddim); + printf("ninit=%d ", in->in_n); + if (BTYPE(in->in_t) == STRTY || ISARY(in->in_t)) + printf("stsize=%d ", + (int)tsize(in->in_t, in->in_df, in->in_sym->sap)); + if (in->in_fl) printf("{ "); + printf("soff=%d ", in->in_sym->soffset); + if (in->in_t == STRTY) { + if (in->in_lnk) + printf("curel %s ", in->in_lnk->sname); + else + printf("END struct"); + } + printf("\n"); + o++; + } +} +#endif + +/* + * Do a simple initialization. + * At block 0, just print out the value, at higher levels generate + * appropriate code. + */ +void +simpleinit(struct symtab *sp, NODE *p) +{ + NODE *q, *r, *nt; + TWORD t; + int sz; + + /* May be an initialization of an array of char by a string */ + if ((DEUNSIGN(p->n_type) == ARY+CHAR && + DEUNSIGN(sp->stype) == ARY+CHAR) || + (DEUNSIGN(p->n_type) == DEUNSIGN(ARY+WCHAR_TYPE) && + DEUNSIGN(sp->stype) == DEUNSIGN(ARY+WCHAR_TYPE))) { + /* Handle "aaa" as { 'a', 'a', 'a' } */ + beginit(sp); + strcvt(p); + if (csym->sdf->ddim == NOOFFSET) + scalinit(bcon(0)); /* Null-term arrays */ + endinit(0); + return; + } + + nt = nametree(sp); + switch (sp->sclass) { + case STATIC: + case EXTDEF: + q = nt; + locctr(DATA, sp); + defloc(sp); +#ifndef NO_COMPLEX + if (ANYCX(q) || ANYCX(p)) { + r = cxop(ASSIGN, q, p); + /* XXX must unwind the code generated here */ + /* We can rely on correct code generated */ + p = r->n_left->n_right->n_left; + r->n_left->n_right->n_left = bcon(0); + tfree(r); + r = p->n_left->n_right; + sz = (int)tsize(r->n_type, r->n_df, r->n_ap); + inval(0, sz, r); + inval(0, sz, p->n_right->n_right); + tfree(p); + break; + } +#endif + p = optim(buildtree(ASSIGN, nt, p)); +#ifndef WORD_ADDRESSED + p = optim(rmpconv(p)); +#endif + q = p->n_right; + t = q->n_type; + sz = (int)tsize(t, q->n_df, q->n_ap); + inval(0, sz, q); + tfree(p); + break; + + case AUTO: + case REGISTER: + if (ISARY(sp->stype)) + cerror("no array init"); + q = nt; +#ifndef NO_COMPLEX + + if (ANYCX(q) || ANYCX(p)) + r = cxop(ASSIGN, q, p); + else +#endif + r = buildtree(ASSIGN, q, p); + ecomp(r); + break; + + default: + uerror("illegal initialization"); + } +} diff --git a/lang/pcc/pcc/cc/cxxcom/inline.c b/lang/pcc/pcc/cc/cxxcom/inline.c new file mode 100644 index 000000000..4afb4d7a9 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/inline.c @@ -0,0 +1,573 @@ +/* $Id: inline.c,v 1.6 2015/11/24 17:30:20 ragge Exp $ */ +/* + * Copyright (c) 2003, 2008 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +#include + +/* + * Simple description of how the inlining works: + * A function found with the keyword "inline" is always saved. + * If it also has the keyword "extern" it is written out thereafter. + * If it has the keyword "static" it will be written out if it is referenced. + * inlining will only be done if -xinline is given, and only if it is + * possible to inline the function. + */ +static void printip(struct interpass *pole); + +struct ntds { + int temp; + TWORD type; + union dimfun *df; + struct attr *attr; +}; + +/* + * ilink from ipole points to the next struct in the list of functions. + */ +static struct istat { + SLIST_ENTRY(istat) link; + struct symtab *sp; + int flags; +#define CANINL 1 /* function is possible to inline */ +#define WRITTEN 2 /* function is written out */ +#define REFD 4 /* Referenced but not yet written out */ + struct ntds *nt;/* Array of arg temp type data */ + int nargs; /* number of args in array */ + int retval; /* number of return temporary, if any */ + struct interpass shead; +} *cifun; + +static SLIST_HEAD(, istat) ipole = { NULL, &ipole.q_forw }; +static int nlabs; + +#define IP_REF (MAXIP+1) +#ifdef PCC_DEBUG +#define SDEBUG(x) if (sdebug) printf x +#else +#define SDEBUG(x) +#endif + +int isinlining; +int inlnodecnt, inlstatcnt; + +#define SZSI sizeof(struct istat) +#define ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++ + +static void +tcnt(NODE *p, void *arg) +{ + inlnodecnt++; + if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) && + regno(p) == FPREG) + SLIST_FIRST(&ipole)->flags &= ~CANINL; /* no stack refs */ + if (p->n_op == NAME || p->n_op == ICON) + p->n_sp = NULL; /* let symtabs be freed for inline funcs */ + if (ndebug) + printf("locking node %p\n", p); +} + +static struct istat * +findfun(struct symtab *sp) +{ + struct istat *is; + + SLIST_FOREACH(is, &ipole, link) + if (is->sp == sp) + return is; + return NULL; +} + +static void +refnode(struct symtab *sp) +{ + struct interpass *ip; + + SDEBUG(("refnode(%s)\n", sp->sname)); + + ip = permalloc(sizeof(*ip)); + ip->type = IP_REF; + ip->ip_name = (char *)sp; + inline_addarg(ip); +} + +void +inline_addarg(struct interpass *ip) +{ + extern NODE *cftnod; + + SDEBUG(("inline_addarg(%p)\n", ip)); + DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem); + if (ip->type == IP_DEFLAB) + nlabs++; + if (ip->type == IP_NODE) + walkf(ip->ip_node, tcnt, 0); /* Count as saved */ + if (cftnod) + cifun->retval = regno(cftnod); +} + +/* + * Called to setup for inlining of a new function. + */ +void +inline_start(struct symtab *sp) +{ + struct istat *is; + + SDEBUG(("inline_start(\"%s\")\n", sp->sname)); + + if (isinlining) + cerror("already inlining function"); + + if ((is = findfun(sp)) != 0) { + if (!DLIST_ISEMPTY(&is->shead, qelem)) + uerror("inline function already defined"); + } else { + is = ialloc(); + is->sp = sp; + SLIST_INSERT_FIRST(&ipole, is, link); + DLIST_INIT(&is->shead, qelem); + } + cifun = is; + nlabs = 0; + isinlining++; +} + +/* + * End of an inline function. In C99 an inline function declared "extern" + * should also have external linkage and are therefore printed out. + * + * Gcc inline syntax is a mess, see matrix below on emitting functions: + * without extern + * -std= - gnu89 gnu99 + * gcc 3.3.5: ja ja ja + * gcc 4.1.3: ja ja ja + * gcc 4.3.1 ja ja nej + * + * with extern + * gcc 3.3.5: nej nej nej + * gcc 4.1.3: nej nej nej + * gcc 4.3.1 nej nej ja + * + * The attribute gnu_inline sets gnu89 behaviour. + * Since pcc mimics gcc 4.3.1 that is the behaviour we emulate. + */ +void +inline_end(void) +{ + struct symtab *sp = cifun->sp; + + SDEBUG(("inline_end()\n")); + + if (sdebug)printip(&cifun->shead); + isinlining = 0; + +#ifdef GCC_COMPAT + if (sp->sclass != STATIC && + (attr_find(sp->sap, GCC_ATYP_GNU_INLINE) || xgnu89)) { + if (sp->sclass == EXTDEF) + sp->sclass = 0; + else + sp->sclass = EXTDEF; + } +#endif + if (sp->sclass == EXTDEF) { + cifun->flags |= REFD; + inline_prtout(); + } +} + +/* + * Called when an inline function is found, to be sure that it will + * be written out. + * The function may not be defined when inline_ref() is called. + */ +void +inline_ref(struct symtab *sp) +{ + struct istat *w; + + SDEBUG(("inline_ref(\"%s\")\n", sp->sname)); + if (sp->sclass == SNULL) + return; /* only inline, no references */ + if (isinlining) { + refnode(sp); + } else { + SLIST_FOREACH(w,&ipole, link) { + if (w->sp != sp) + continue; + w->flags |= REFD; + return; + } + /* function not yet defined, print out when found */ + w = ialloc(); + w->sp = sp; + w->flags |= REFD; + SLIST_INSERT_FIRST(&ipole, w, link); + DLIST_INIT(&w->shead, qelem); + } +} + +static void +puto(struct istat *w) +{ + struct interpass_prolog *ipp, *epp, *pp; + struct interpass *ip, *nip; + extern int crslab; + int lbloff = 0; + + /* Copy the saved function and print it out */ + ipp = 0; /* XXX data flow analysis */ + DLIST_FOREACH(ip, &w->shead, qelem) { + switch (ip->type) { + case IP_EPILOG: + case IP_PROLOG: + if (ip->type == IP_PROLOG) { + ipp = (struct interpass_prolog *)ip; + /* fix label offsets */ + lbloff = crslab - ipp->ip_lblnum; + } else { + epp = (struct interpass_prolog *)ip; + crslab += (epp->ip_lblnum - ipp->ip_lblnum); + } + pp = tmpalloc(sizeof(struct interpass_prolog)); + memcpy(pp, ip, sizeof(struct interpass_prolog)); + pp->ip_lblnum += lbloff; +#ifdef PCC_DEBUG + if (ip->type == IP_EPILOG && crslab != pp->ip_lblnum) + cerror("puto: %d != %d", crslab, pp->ip_lblnum); +#endif + pass2_compile((struct interpass *)pp); + break; + + case IP_REF: + inline_ref((struct symtab *)ip->ip_name); + break; + + default: + nip = tmpalloc(sizeof(struct interpass)); + *nip = *ip; + if (nip->type == IP_NODE) { + NODE *p; + + p = nip->ip_node = ccopy(nip->ip_node); + if (p->n_op == GOTO) + glval(p->n_left) += lbloff; + else if (p->n_op == CBRANCH) + glval(p->n_right) += lbloff; + } else if (nip->type == IP_DEFLAB) + nip->ip_lbl += lbloff; + pass2_compile(nip); + break; + } + } + w->flags |= WRITTEN; +} + +/* + * printout functions that are referenced. + */ +void +inline_prtout(void) +{ + struct istat *w; + int gotone = 0; + + SLIST_FOREACH(w, &ipole, link) { + if ((w->flags & (REFD|WRITTEN)) == REFD && + !DLIST_ISEMPTY(&w->shead, qelem)) { + locctr(PROG, w->sp); + defloc(w->sp); + puto(w); + w->flags |= WRITTEN; + gotone++; + } + } + if (gotone) + inline_prtout(); +} + +#if 1 +static void +printip(struct interpass *pole) +{ + static char *foo[] = { + 0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" }; + struct interpass *ip; + struct interpass_prolog *ipplg, *epplg; + + DLIST_FOREACH(ip, pole, qelem) { + if (ip->type > MAXIP) + printf("IP(%d) (%p): ", ip->type, ip); + else + printf("%s (%p): ", foo[ip->type], ip); + switch (ip->type) { + case IP_NODE: printf("\n"); +#ifdef PCC_DEBUG + fwalk(ip->ip_node, eprint, 0); break; +#endif + case IP_PROLOG: + ipplg = (struct interpass_prolog *)ip; + printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n", + ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "", + (long)ipplg->ipp_regs[0], ipplg->ipp_autos, + ipplg->ip_tmpnum, ipplg->ip_lblnum); + break; + case IP_EPILOG: + epplg = (struct interpass_prolog *)ip; + printf("%s %s regs %lx autos %d mintemp %d minlbl %d\n", + epplg->ipp_name, epplg->ipp_vis ? "(local)" : "", + (long)epplg->ipp_regs[0], epplg->ipp_autos, + epplg->ip_tmpnum, epplg->ip_lblnum); + break; + case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break; + case IP_DEFNAM: printf("\n"); break; + case IP_ASM: printf("%s", ip->ip_asm); break; + default: + break; + } + } +} +#endif + +static int toff; + +static NODE * +mnode(struct ntds *nt, NODE *p) +{ + NODE *q; + int num = nt->temp + toff; + + if (p->n_op == CM) { + q = p->n_right; + q = tempnode(num, nt->type, nt->df, nt->attr); + nt--; + p->n_right = buildtree(ASSIGN, q, p->n_right); + p->n_left = mnode(nt, p->n_left); + p->n_op = COMOP; + } else { + p = pconvert(p); + q = tempnode(num, nt->type, nt->df, nt->attr); + p = buildtree(ASSIGN, q, p); + } + return p; +} + +static void +rtmps(NODE *p, void *arg) +{ + if (p->n_op == TEMP) + regno(p) += toff; +} + +/* + * Inline a function. Returns the return value. + * There are two major things that must be converted when + * inlining a function: + * - Label numbers must be updated with an offset. + * - The stack block must be relocated (add to REG or OREG). + * - Temporaries should be updated (but no must) + */ +NODE * +inlinetree(struct symtab *sp, NODE *f, NODE *ap) +{ + extern int crslab, tvaloff; + struct istat *is = findfun(sp); + struct interpass *ip, *ipf, *ipl; + int lmin, l0, l1, l2, gainl; + NODE *p, *rp; + + if (is == NULL || nerrors) { + inline_ref(sp); /* prototype of not yet declared inline ftn */ + return NIL; + } + + SDEBUG(("inlinetree(%p,%p) OK %d\n", f, ap, is->flags & CANINL)); + +#ifdef GCC_COMPAT + gainl = attr_find(sp->sap, GCC_ATYP_ALW_INL) != NULL; +#else + gainl = 0; +#endif + + if ((is->flags & CANINL) == 0 && gainl) + werror("cannot inline but always_inline"); + + if ((is->flags & CANINL) == 0 || (xinline == 0 && gainl == 0)) { + if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC) + inline_ref(sp); + return NIL; + } + + if (isinlining && cifun->sp == sp) { + /* Do not try to inline ourselves */ + inline_ref(sp); + return NIL; + } + +#ifdef mach_i386 + if (kflag) { + is->flags |= REFD; /* if static inline, emit */ + return NIL; /* XXX cannot handle hidden ebx arg */ + } +#endif + + /* emit jumps to surround inline function */ + branch(l0 = getlab()); + plabel(l1 = getlab()); + l2 = getlab(); + SDEBUG(("branch labels %d,%d,%d\n", l0, l1, l2)); + + ipf = DLIST_NEXT(&is->shead, qelem); /* prolog */ + ipl = DLIST_PREV(&is->shead, qelem); /* epilog */ + + /* Fix label & temp offsets */ +#define IPP(x) ((struct interpass_prolog *)x) + SDEBUG(("pre-offsets crslab %d tvaloff %d\n", crslab, tvaloff)); + lmin = crslab - IPP(ipf)->ip_lblnum; + crslab += (IPP(ipl)->ip_lblnum - IPP(ipf)->ip_lblnum) + 1; + toff = tvaloff - IPP(ipf)->ip_tmpnum; + tvaloff += (IPP(ipl)->ip_tmpnum - IPP(ipf)->ip_tmpnum) + 1; + SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n", + crslab, lmin, tvaloff, toff)); + + /* traverse until first real label */ + ipf = DLIST_NEXT(ipf, qelem); + do + ipf = DLIST_NEXT(ipf, qelem); + while (ipf->type != IP_DEFLAB); + + /* traverse backwards to last label */ + do + ipl = DLIST_PREV(ipl, qelem); + while (ipl->type != IP_DEFLAB); + + /* So, walk over all statements and emit them */ + for (ip = ipf; ip != ipl; ip = DLIST_NEXT(ip, qelem)) { + switch (ip->type) { + case IP_NODE: + p = ccopy(ip->ip_node); + if (p->n_op == GOTO) + glval(p->n_left) += lmin; + else if (p->n_op == CBRANCH) + glval(p->n_right) += lmin; + walkf(p, rtmps, 0); +#ifdef PCC_DEBUG + if (sdebug) { + printf("converted node\n"); + fwalk(ip->ip_node, eprint, 0); + fwalk(p, eprint, 0); + } +#endif + send_passt(IP_NODE, p); + break; + + case IP_DEFLAB: + SDEBUG(("converted label %d to %d\n", + ip->ip_lbl, ip->ip_lbl + lmin)); + send_passt(IP_DEFLAB, ip->ip_lbl + lmin); + break; + + case IP_ASM: + send_passt(IP_ASM, ip->ip_asm); + break; + + case IP_REF: + inline_ref((struct symtab *)ip->ip_name); + break; + + default: + cerror("bad inline stmt %d", ip->type); + } + } + SDEBUG(("last label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin)); + send_passt(IP_DEFLAB, ip->ip_lbl + lmin); + + branch(l2); + plabel(l0); + + rp = block(GOTO, bcon(l1), NIL, INT, 0, 0); + if (is->retval) + p = tempnode(is->retval + toff, DECREF(sp->stype), + sp->sdf, sp->sap); + else + p = bcon(0); + rp = buildtree(COMOP, rp, p); + + if (is->nargs) { + p = mnode(&is->nt[is->nargs-1], ap); + rp = buildtree(COMOP, p, rp); + } + + tfree(f); + return rp; +} + +void +inline_args(struct symtab **sp, int nargs) +{ + union arglist *al; + struct istat *cf; + TWORD t; + int i; + + SDEBUG(("inline_args\n")); + cf = cifun; + /* + * First handle arguments. We currently do not inline anything if: + * - function has varargs + * - function args are volatile, checked if no temp node is asg'd. + */ + /* XXX - this is ugly, invent something better */ + if (cf->sp->sdf->dfun == NULL) + return; /* no prototype */ + for (al = cf->sp->sdf->dfun; al->type != TNULL; al++) { + t = al->type; + if (t == TELLIPSIS) + return; /* cannot inline */ + if (ISSOU(BTYPE(t))) + al++; + for (; t > BTMASK; t = DECREF(t)) + if (ISARY(t) || ISFTN(t)) + al++; + } + + if (nargs) { + for (i = 0; i < nargs; i++) + if ((sp[i]->sflags & STNODE) == 0) + return; /* not temporary */ + cf->nt = permalloc(sizeof(struct ntds)*nargs); + for (i = 0; i < nargs; i++) { + cf->nt[i].temp = sp[i]->soffset; + cf->nt[i].type = sp[i]->stype; + cf->nt[i].df = sp[i]->sdf; + cf->nt[i].attr = sp[i]->sap; + } + } + cf->nargs = nargs; + cf->flags |= CANINL; +} diff --git a/lang/pcc/pcc/cc/cxxcom/main.c b/lang/pcc/pcc/cc/cxxcom/main.c new file mode 100644 index 000000000..255ea2294 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/main.c @@ -0,0 +1,357 @@ +/* $Id: main.c,v 1.6 2014/10/12 11:52:13 ragge Exp $ */ + +/* + * Copyright (c) 2002 Anders Magnusson. All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "config.h" + +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#include "pass1.h" +#include "pass2.h" + +int bdebug, ddebug, edebug, idebug, ndebug; +int odebug, pdebug, sdebug, tdebug, xdebug, cppdebug, wdebug; +int b2debug, c2debug, e2debug, f2debug, g2debug, o2debug; +int r2debug, s2debug, t2debug, u2debug, x2debug; +int gflag, kflag, pflag, sflag; +int sspflag; +int xssa, xtailcall, xtemps, xdeljumps, xdce, xinline, xccp, xgnu89, xgnu99; +int xuchar; +int freestanding; +char *prgname; + +static void prtstats(void); + +static void +usage(void) +{ + (void)fprintf(stderr, "usage: %s [option] [infile] [outfile]...\n", + prgname); + exit(1); +} + +static void +segvcatch(int a) +{ + char buf[1024]; + + snprintf(buf, sizeof buf, "%sinternal compiler error: %s, line %d\n", + nerrors ? "" : "major ", ftitle, lineno); + (void)write(STDERR_FILENO, buf, strlen(buf)); + _exit(1); +} + +static void +xopt(char *str) +{ + if (strcmp(str, "ssa") == 0) + xssa++; + else if (strcmp(str, "tailcall") == 0) + xtailcall++; + else if (strcmp(str, "temps") == 0) + xtemps++; + else if (strcmp(str, "deljumps") == 0) + xdeljumps++; + else if (strcmp(str, "dce") == 0) + xdce++; + else if (strcmp(str, "inline") == 0) + xinline++; + else if (strcmp(str, "ccp") == 0) + xccp++; + else if (strcmp(str, "gnu89") == 0) + xgnu89++; + else if (strcmp(str, "gnu99") == 0) + xgnu99++; + else if (strcmp(str, "uchar") == 0) + xuchar++; + else { + fprintf(stderr, "unknown -x option '%s'\n", str); + usage(); + } +} + +static void +fflags(char *str) +{ + int flagval = 1; + + if (strncmp("no-", str, 3) == 0) { + str += 3; + flagval = 0; + } + + if (strcmp(str, "stack-protector") == 0) + sspflag = flagval; + else if (strcmp(str, "stack-protector-all") == 0) + sspflag = flagval; + else if (strncmp(str, "pack-struct", 11) == 0) + pragma_allpacked = (strlen(str) > 12 ? atoi(str+12) : 1); + else if (strcmp(str, "freestanding") == 0) + freestanding = flagval; + else { + fprintf(stderr, "unknown -f option '%s'\n", str); + usage(); + } +} + +/* control multiple files */ +int +main(int argc, char *argv[]) +{ + int ch; + +#ifdef TIMING + struct timeval t1, t2; + + (void)gettimeofday(&t1, NULL); +#endif + + prgname = argv[0]; + + while ((ch = getopt(argc, argv, "OT:VW:X:Z:f:gkm:psvwx:")) != -1) { + switch (ch) { +#if !defined(MULTIPASS) || defined(PASS1) + case 'X': /* pass1 debugging */ + while (*optarg) + switch (*optarg++) { + case 'b': ++bdebug; break; /* buildtree */ + case 'd': ++ddebug; break; /* declarations */ + case 'e': ++edebug; break; /* pass1 exit */ + case 'i': ++idebug; break; /* initializations */ + case 'n': ++ndebug; break; /* node allocation */ + case 'o': ++odebug; break; /* optim */ + case 'p': ++pdebug; break; /* prototype */ + case 's': ++sdebug; break; /* inline */ + case 't': ++tdebug; break; /* type match */ + case 'x': ++xdebug; break; /* MD code */ + case '+': ++cppdebug; break; /* C++ */ + default: + fprintf(stderr, "unknown -X flag '%c'\n", + optarg[-1]); + exit(1); + } + break; +#endif +#if !defined(MULTIPASS) || defined(PASS2) + case 'Z': /* pass2 debugging */ + while (*optarg) + switch (*optarg++) { + case 'b': /* basic block and SSA building */ + ++b2debug; + break; + case 'c': /* code printout */ + ++c2debug; + break; + case 'e': /* print tree upon pass2 enter */ + ++e2debug; + break; + case 'f': /* instruction matching */ + ++f2debug; + break; + case 'g': /* print flow graphs */ + ++g2debug; + break; + case 'n': /* node allocation */ + ++ndebug; + break; + case 'o': /* instruction generator */ + ++o2debug; + break; + case 'r': /* register alloc/graph coloring */ + ++r2debug; + break; + case 's': /* shape matching */ + ++s2debug; + break; + case 't': /* type matching */ + ++t2debug; + break; + case 'u': /* Sethi-Ullman debugging */ + ++u2debug; + break; + case 'x': /* target specific */ + ++x2debug; + break; + default: + fprintf(stderr, "unknown -Z flag '%c'\n", + optarg[-1]); + exit(1); + } + break; +#endif + case 'f': /* Language */ + fflags(optarg); + break; + + case 'g': /* Debugging */ + gflag = 1; + break; + + case 'k': /* PIC code */ + ++kflag; + break; + + case 'm': /* Target-specific */ + mflags(optarg); + break; + + case 'p': /* Profiling */ + pflag = 1; + break; + + case 's': /* Statistics */ + ++sflag; + break; + + case 'W': /* Enable different warnings */ + Wflags(optarg); + break; + + case 'x': /* Different settings */ + xopt(optarg); + break; + + case 'v': + printf("ccom: %s\n", VERSSTR); + break; + + case '?': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc > 0 && strcmp(argv[0], "-") != 0) { + if (freopen(argv[0], "r", stdin) == NULL) { + fprintf(stderr, "open input file '%s':", + argv[0]); + perror(NULL); + exit(1); + } + } + if (argc > 1 && strcmp(argv[1], "-") != 0) { + if (freopen(argv[1], "w", stdout) == NULL) { + fprintf(stderr, "open output file '%s':", + argv[1]); + perror(NULL); + exit(1); + } + } + + mkdope(); + signal(SIGSEGV, segvcatch); +#ifdef SIGBUS + signal(SIGBUS, segvcatch); +#endif + fregs = FREGS; /* number of free registers */ + lineno = 1; +#ifdef GCC_COMPAT + gcc_init(); +#endif + + /* starts past any of the above */ + reached = 1; + + bjobcode(); +#ifndef TARGET_VALIST + { + NODE *p = block(NAME, NIL, NIL, PTR|CHAR, NULL, 0); + struct symtab *sp = lookup(addname("__builtin_va_list"), 0); + p->n_sp = sp; + defid(p, TYPEDEF); + nfree(p); + } +#endif + complinit(); + +#ifdef STABS + if (gflag) { + stabs_file(argc ? argv[0] : ""); + stabs_init(); + } +#endif + + if (sspflag) + sspinit(); + + (void) yyparse(); + yyaccpt(); + + if (!nerrors) + lcommprint(); + +#ifdef STABS + if (gflag) + stabs_efile(argc ? argv[0] : ""); +#endif + + ejobcode( nerrors ? 1 : 0 ); + +#ifdef TIMING + (void)gettimeofday(&t2, NULL); + t2.tv_sec -= t1.tv_sec; + t2.tv_usec -= t1.tv_usec; + if (t2.tv_usec < 0) { + t2.tv_usec += 1000000; + t2.tv_sec -= 1; + } + fprintf(stderr, "ccom total time: %ld s %ld us\n", + t2.tv_sec, t2.tv_usec); +#endif + + if (sflag) + prtstats(); + + return(nerrors?1:0); +} + +void +prtstats(void) +{ + extern int nametabs, namestrlen, tmpallocsize, permallocsize; + extern int lostmem, arglistcnt, dimfuncnt, inlnodecnt, inlstatcnt; + extern int symtabcnt, suedefcnt; + + fprintf(stderr, "Name table entries: %d pcs\n", nametabs); + fprintf(stderr, "Name string size: %d B\n", namestrlen); + fprintf(stderr, "Permanent allocated memory: %d B\n", permallocsize); + fprintf(stderr, "Temporary allocated memory: %d B\n", tmpallocsize); + fprintf(stderr, "Lost memory: %d B\n", lostmem); + fprintf(stderr, "Argument list unions: %d pcs\n", arglistcnt); + fprintf(stderr, "Dimension/function unions: %d pcs\n", dimfuncnt); + fprintf(stderr, "Struct/union/enum blocks: %d pcs\n", suedefcnt); + fprintf(stderr, "Inline node count: %d pcs\n", inlnodecnt); + fprintf(stderr, "Inline control blocks: %d pcs\n", inlstatcnt); + fprintf(stderr, "Permanent symtab entries: %d pcs\n", symtabcnt); +} diff --git a/lang/pcc/pcc/cc/cxxcom/optim.c b/lang/pcc/pcc/cc/cxxcom/optim.c new file mode 100644 index 000000000..0da5d7e2f --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/optim.c @@ -0,0 +1,426 @@ +/* $Id: optim.c,v 1.5 2015/11/24 17:30:20 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "pass1.h" + +# define SWAP(p,q) {sp=p; p=q; q=sp;} +# define RCON(p) (p->n_right->n_op==ICON) +# define RO(p) p->n_right->n_op +# define RV(p) glval(p->n_right) +# define LCON(p) (p->n_left->n_op==ICON) +# define LO(p) p->n_left->n_op +# define LV(p) glval(p->n_left) + +/* remove left node */ +static NODE * +zapleft(NODE *p) +{ + NODE *q; + + q = p->n_left; + nfree(p->n_right); + nfree(p); + return q; +} + +/* + * fortran function arguments + */ +static NODE * +fortarg(NODE *p) +{ + if( p->n_op == CM ){ + p->n_left = fortarg( p->n_left ); + p->n_right = fortarg( p->n_right ); + return(p); + } + + while( ISPTR(p->n_type) ){ + p = buildtree( UMUL, p, NIL ); + } + return( optim(p) ); +} + + /* mapping relationals when the sides are reversed */ +short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT }; + +/* + * local optimizations, most of which are probably + * machine independent + */ +NODE * +optim(NODE *p) +{ + int o, ty; + NODE *sp, *q; + OFFSZ sz; + int i; + + if (odebug) return(p); + + ty = coptype(p->n_op); + if( ty == LTYPE ) return(p); + + if( ty == BITYPE ) p->n_right = optim(p->n_right); + p->n_left = optim(p->n_left); + + /* collect constants */ +again: o = p->n_op; + switch(o){ + + case SCONV: + if (concast(p->n_left, p->n_type)) { + q = p->n_left; + nfree(p); + p = q; + break; + } + /* FALLTHROUGH */ + case PCONV: + if (p->n_type != VOID) + p = clocal(p); + break; + + case FORTCALL: + p->n_right = fortarg( p->n_right ); + break; + + case ADDROF: + if (LO(p) == TEMP) + break; + if( LO(p) != NAME ) cerror( "& error" ); + + if( !andable(p->n_left) && !statinit) + break; + + LO(p) = ICON; + + setuleft: + /* paint over the type of the left hand side with the type of the top */ + p->n_left->n_type = p->n_type; + p->n_left->n_df = p->n_df; + p->n_left->n_ap = p->n_ap; + q = p->n_left; + nfree(p); + p = q; + break; + + case NOT: + case UMINUS: + case COMPL: + if (LCON(p) && conval(p->n_left, o, p->n_left)) + p = nfree(p); + break; + + case UMUL: + /* Do not discard ADDROF TEMP's */ + if (LO(p) == ADDROF && LO(p->n_left) != TEMP) { + q = p->n_left->n_left; + nfree(p->n_left); + nfree(p); + p = q; + break; + } + if( LO(p) != ICON ) break; + LO(p) = NAME; + goto setuleft; + + case RS: + if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right)) + goto zapright; + + sz = tsize(p->n_type, p->n_df, p->n_ap); + + if (LO(p) == RS && RCON(p->n_left) && RCON(p) && + (RV(p) + RV(p->n_left)) < sz) { + /* two right-shift by constants */ + RV(p) += RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#if 0 + else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { + RV(p) -= RV(p->n_left); + if (RV(p) < 0) + o = p->n_op = LS, RV(p) = -RV(p); + p->n_left = zapleft(p->n_left); + } +#endif + if (RO(p) == ICON) { + if (RV(p) < 0) { + RV(p) = -RV(p); + p->n_op = LS; + goto again; + } +#ifdef notyet /* must check for side effects, --a >> 32; */ + if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) && + ISUNSIGNED(p->n_type)) { /* ignore signed shifts */ + /* too many shifts */ + tfree(p->n_left); + nfree(p->n_right); + p->n_op = ICON; glval(p) = 0; p->n_sp = NULL; + } else +#endif + /* avoid larger shifts than type size */ + if (RV(p) >= sz) { + RV(p) = RV(p) % sz; + werror("shift larger than type"); + } + if (RV(p) == 0) + p = zapleft(p); + } + break; + + case LS: + if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right)) + goto zapright; + + sz = tsize(p->n_type, p->n_df, p->n_ap); + + if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { + /* two left-shift by constants */ + RV(p) += RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#if 0 + else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) { + RV(p) -= RV(p->n_left); + p->n_left = zapleft(p->n_left); + } +#endif + if (RO(p) == ICON) { + if (RV(p) < 0) { + RV(p) = -RV(p); + p->n_op = RS; + goto again; + } +#ifdef notyet /* must check for side effects */ + if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) { + /* too many shifts */ + tfree(p->n_left); + nfree(p->n_right); + p->n_op = ICON; glval(p) = 0; p->n_sp = NULL; + } else +#endif + /* avoid larger shifts than type size */ + if (RV(p) >= sz) { + RV(p) = RV(p) % sz; + werror("shift larger than type"); + } + if (RV(p) == 0) + p = zapleft(p); + } + break; + + case MINUS: + if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) { + /* link-time constants, but both are the same */ + /* solve it now by forgetting the symbols */ + p->n_left->n_sp = p->n_right->n_sp = NULL; + } + if( !nncon(p->n_right) ) break; + RV(p) = -RV(p); + o = p->n_op = PLUS; + + case MUL: + /* + * Check for u=(x-y)+z; where all vars are pointers to + * the same struct. This has two advantages: + * 1: avoid a mul+div + * 2: even if not allowed, people may get surprised if this + * calculation do not give correct result if using + * unaligned structs. + */ + if (p->n_type == INTPTR && RCON(p) && + LO(p) == DIV && RCON(p->n_left) && + RV(p) == RV(p->n_left) && + LO(p->n_left) == MINUS) { + q = p->n_left->n_left; + if (q->n_left->n_type == PTR+STRTY && + q->n_right->n_type == PTR+STRTY && + strmemb(q->n_left->n_ap) == + strmemb(q->n_right->n_ap)) { + p = zapleft(p); + p = zapleft(p); + } + } + /* FALLTHROUGH */ + case PLUS: + case AND: + case OR: + case ER: + /* commutative ops; for now, just collect constants */ + /* someday, do it right */ + if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) ) + SWAP( p->n_left, p->n_right ); + /* make ops tower to the left, not the right */ + if( RO(p) == o ){ + NODE *t1, *t2, *t3; + t1 = p->n_left; + sp = p->n_right; + t2 = sp->n_left; + t3 = sp->n_right; + /* now, put together again */ + p->n_left = sp; + sp->n_left = t1; + sp->n_right = t2; + sp->n_type = p->n_type; + p->n_right = t3; + } + if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) && + conval(p->n_right, MINUS, p->n_left->n_right)){ + zapleft: + + q = p->n_left->n_left; + nfree(p->n_left->n_right); + nfree(p->n_left); + p->n_left = q; + } + if( RCON(p) && LO(p)==o && RCON(p->n_left) && + conval( p->n_right, o, p->n_left->n_right ) ){ + goto zapleft; + } + else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){ + zapright: + nfree(p->n_right); + q = makety(p->n_left, p->n_type, p->n_qual, + p->n_df, p->n_ap); + nfree(p); + p = clocal(q); + break; + } + + /* change muls to shifts */ + + if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){ + if( i == 0 ) { /* multiplication by 1 */ + goto zapright; + } + o = p->n_op = LS; + p->n_right->n_type = INT; + p->n_right->n_df = NULL; + RV(p) = i; + } + + /* change +'s of negative consts back to - */ + if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){ + RV(p) = -RV(p); + o = p->n_op = MINUS; + } + + /* remove ops with RHS 0 */ + if ((o == PLUS || o == MINUS || o == OR || o == ER) && + nncon(p->n_right) && RV(p) == 0) { + goto zapright; + } + break; + + case DIV: + if( nncon( p->n_right ) && glval(p->n_right) == 1 ) + goto zapright; + if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right)) + goto zapright; + if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) { + p->n_op = RS; + RV(p) = i; + q = p->n_right; + if(tsize(q->n_type, q->n_df, q->n_ap) > SZINT) + p->n_right = makety(q, INT, 0, 0, 0); + + break; + } + break; + + case MOD: + if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) { + p->n_op = AND; + RV(p) = RV(p) -1; + break; + } + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + case ULT: + case ULE: + case UGT: + case UGE: + if( !LCON(p) ) break; + + /* exchange operands */ + + sp = p->n_left; + p->n_left = p->n_right; + p->n_right = sp; + p->n_op = revrel[p->n_op - EQ ]; + break; + +#ifdef notyet + case ASSIGN: + /* Simple test to avoid two branches */ + if (RO(p) != NE) + break; + q = p->n_right; + if (RCON(q) && RV(q) == 0 && LO(q) == AND && + RCON(q->n_left) && (i = ispow2(RV(q->n_left))) && + q->n_left->n_type == INT) { + q->n_op = RS; + RV(q) = i; + } + break; +#endif + } + + return(p); + } + +int +ispow2(CONSZ c) +{ + int i; + if( c <= 0 || (c&(c-1)) ) return(-1); + for( i=0; c>1; ++i) c >>= 1; + return(i); +} + +int +nncon(NODE *p) +{ + /* is p a constant without a name */ + return( p->n_op == ICON && p->n_sp == NULL ); +} diff --git a/lang/pcc/pcc/cc/cxxcom/pass1.h b/lang/pcc/pcc/cc/cxxcom/pass1.h new file mode 100644 index 000000000..984b4adcc --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/pass1.h @@ -0,0 +1,664 @@ +/* $Id: pass1.h,v 1.20 2016/03/05 15:31:25 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "config.h" + +#include +#include +#include +#ifdef HAVE_STDINT_H +#include +#endif +#include + +#ifndef MKEXT +#include "external.h" +#else +typedef unsigned int bittype; /* XXX - for basicblock */ +#endif +#include "manifest.h" +#include "softfloat.h" + +/* + * Storage classes + */ +#define SNULL 0 +#define AUTO 1 +#define EXTERN 2 +#define STATIC 3 +#define REGISTER 4 +#define EXTDEF 5 +/* #define LABEL 6*/ +/* #define ULABEL 7*/ +#define MOS 8 +#define PARAM 9 +#define STNAME 10 +#define MOU 11 +#define UNAME 12 +#define TYPEDEF 13 +/* #define FORTRAN 14 */ +#define ENAME 15 +#define MOE 16 +/* #define UFORTRAN 17 */ +#define USTATIC 18 +#define MAXSTCL 20 + + /* field size is ORed in */ +#define FIELD 0200 +#define FLDSIZ 0177 +extern char *scnames(int); + +/* + * Symbol table flags + */ +#define SNORMAL 0 +#define STAGNAME 01 +#define SLBLNAME 02 +#define SMOSNAME 03 +#define SSTRING 04 +#define NSTYPES 05 +#define SMASK 07 + +#define STLS 00010 /* Thread Local Support variable */ +/* #define SREF 00020 */ +#define SNOCREAT 00040 /* don't create a symbol in lookup() */ +#define STEMP 00100 /* Allocate symtab from temp or perm mem */ +#define SDYNARRAY 00200 /* symbol is dynamic array on stack */ +#define SINLINE 00400 /* function is of type inline */ +#define STNODE 01000 /* symbol shall be a temporary node */ +#define SBUILTIN 02000 /* this is a builtin function */ +#define SASG 04000 /* symbol is assigned to already */ +#define SLOCAL1 010000 +#define SLOCAL2 020000 +#define SLOCAL3 040000 + + /* alignment of initialized quantities */ +#ifndef AL_INIT +#define AL_INIT ALINT +#endif + +struct rstack; +struct symtab; +union arglist; +#ifdef GCC_COMPAT +struct gcc_attr_pack; +#endif + +struct namespace; + +/* + * Dimension/prototype information. + * ddim > 0 holds the dimension of an array. + * ddim < 0 is a dynamic array and refers to a tempnode. + * ...unless: + * ddim == NOOFFSET, an array without dimenston, "[]" + * ddim == -1, dynamic array while building before defid. + */ +union dimfun { + int ddim; /* Dimension of an array */ + union arglist *dfun; /* Prototype index */ +}; + +/* + * Argument list member info when storing prototypes. + */ +union arglist { + TWORD type; + union dimfun *df; + struct attr *sap; +}; +#define TNULL INCREF(FARG) /* pointer to FARG -- impossible type */ +#define TELLIPSIS INCREF(INCREF(FARG)) + +/* + * Symbol table definition. + */ +struct symtab { + struct symtab *snext; /* link to other symbols in the same scope */ + struct symtab *sdown; /* link to parent class */ + struct symtab *sup; /* link to child class */ + int soffset; /* offset or value */ + char sclass; /* storage class */ + char slevel; /* scope level */ + short sflags; /* flags, see below */ + char *sname; /* Symbol name */ + char *soname; /* Written-out name */ + TWORD stype; /* type word */ + TWORD squal; /* qualifier word */ + union dimfun *sdf; /* ptr to the dimension/prototype array */ + struct attr *sap; /* the base type attribute list */ +}; + +#define ISSOU(ty) ((ty) == STRTY || (ty) == UNIONTY) + +/* + * External definitions + */ +struct swents { /* switch table */ + struct swents *next; /* Next struct in linked list */ + CONSZ sval; /* case value */ + int slab; /* associated label */ +}; +int mygenswitch(int, TWORD, struct swents **, int); + +extern int blevel; +extern int oldstyle; + +extern int lineno, nerrors; + +extern char *ftitle; +extern struct symtab *cftnsp; +extern int autooff, maxautooff, argoff; + +extern OFFSZ inoff; + +extern int reached; +extern int isinlining; +extern int xinline, xgnu89, xgnu99; +extern int bdebug, ddebug, edebug, idebug, ndebug; +extern int odebug, pdebug, sdebug, tdebug, xdebug; + +/* various labels */ +extern int brklab; +extern int contlab; +extern int flostat; +extern int retlab; +extern int doing_init, statinit; +extern short sztable[]; +extern char *astypnames[]; + +/* pragma globals */ +extern int pragma_allpacked, pragma_packed, pragma_aligned; +extern char *pragma_renamed; + +/* + * Flags used in the (elementary) flow analysis ... + */ +#define FBRK 02 +#define FCONT 04 +#define FDEF 010 +#define FLOOP 020 + +/* + * Location counters + */ +#define NOSEG -1 +#define PROG 0 /* (ro) program segment */ +#define DATA 1 /* (rw) data segment */ +#define RDATA 2 /* (ro) data segment */ +#define LDATA 3 /* (rw) local data */ +#define UDATA 4 /* (rw) uninitialized data */ +#define STRNG 5 /* (ro) string segment */ +#define PICDATA 6 /* (rw) relocatable data segment */ +#define PICRDATA 7 /* (ro) relocatable data segment */ +#define PICLDATA 8 /* (rw) local relocatable data */ +#define TLSDATA 9 /* (rw) TLS data segment */ +#define TLSUDATA 10 /* (rw) TLS uninitialized segment */ +#define CTORS 11 /* constructor */ +#define DTORS 12 /* destructor */ +#define NMSEG 13 /* other (named) segment */ + +extern int lastloc; +void locctr(int type, struct symtab *sp); +void setseg(int type, char *name); +void defalign(int al); +void symdirec(struct symtab *sp); + +/* mark an offset which is undefined */ + +#define NOOFFSET (-10201) + +/* declarations of various functions */ +extern NODE + *buildtree(int, NODE *, NODE *r), + *mkty(unsigned, union dimfun *, struct attr *), + *rstruct(char *, int), + *dclstruct(struct rstack *), + *strend(int gtype, char *), + *tymerge(NODE *, NODE *), + *stref(NODE *), +#ifdef WORD_ADDRESSED + *offcon(OFFSZ, TWORD, union dimfun *, struct attr *), +#endif + *bcon(int), + *xbcon(CONSZ, struct symtab *, TWORD), + *bpsize(NODE *), + *convert(NODE *, int), + *pconvert(NODE *), + *oconvert(NODE *), + *ptmatch(NODE *), + *makety(NODE *, TWORD, TWORD, union dimfun *, struct attr *), + *block(int, NODE *, NODE *, TWORD, union dimfun *, struct attr *), + *doszof(NODE *), + *talloc(void), + *optim(NODE *), + *clocal(NODE *), + *ccopy(NODE *), + *tempnode(int, TWORD, union dimfun *, struct attr *), + *eve(NODE *), + *doacall(struct symtab *, NODE *, NODE *, int); +NODE *intprom(NODE *); +OFFSZ tsize(TWORD, union dimfun *, struct attr *), + psize(NODE *); +NODE * typenode(NODE *new); +void spalloc(NODE *, NODE *, OFFSZ); +char *exname(char *); +NODE *floatcon(char *); +NODE *fhexcon(char *); +NODE *bdty(int op, ...); +extern struct rstack *rpole; + +int oalloc(struct symtab *, int *); +void deflabel(char *, NODE *); +void gotolabel(char *); +unsigned int esccon(char **); +void inline_start(struct symtab *); +void inline_end(void); +void inline_addarg(struct interpass *); +void inline_ref(struct symtab *); +void inline_prtout(void); +void inline_args(struct symtab **, int); +NODE *inlinetree(struct symtab *, NODE *, NODE *); +void ftnarg(NODE *); +struct rstack *bstruct(char *, int, NODE *); +void moedef(char *); +void beginit(struct symtab *); +void simpleinit(struct symtab *, NODE *); +struct symtab *lookup(char *, int); +struct symtab *getsymtab(char *, int); +char *addstring(char *); +char *addname(char *); +void symclear(int); +struct symtab *hide(struct symtab *); +void soumemb(NODE *, char *, int); +int talign(unsigned int, struct attr *); +void bfcode(struct symtab **, int); +int chkftn(union arglist *, union arglist *); +void branch(int); +void cbranch(NODE *, NODE *); +void extdec(struct symtab *); +void defzero(struct symtab *); +int falloc(struct symtab *, int, NODE *); +TWORD ctype(TWORD); +void inval(CONSZ, int, NODE *); +int ninval(CONSZ, int, NODE *); +void infld(CONSZ, int, CONSZ); +void zbits(CONSZ, int); +void instring(struct symtab *); +void inwstring(struct symtab *); +void plabel(int); +void bjobcode(void); +void ejobcode(int); +void calldec(NODE *, NODE *); +int cisreg(TWORD); +void asginit(NODE *); +void desinit(NODE *); +void endinit(int); +void endictx(void); +void sspinit(void); +void sspstart(void); +void sspend(void); +void ilbrace(void); +void irbrace(void); +CONSZ scalinit(NODE *); +void p1print(char *, ...); +char *copst(int); +int cdope(int); +void myp2tree(NODE *); +void lcommprint(void); +void lcommdel(struct symtab *); +NODE *funcode(NODE *); +struct symtab *enumhd(char *); +NODE *enumdcl(struct symtab *); +NODE *enumref(char *); +CONSZ icons(NODE *); +CONSZ valcast(CONSZ v, TWORD t); +int mypragma(char *); +char *pragtok(char *); +int eat(int); +void fixdef(struct symtab *); +int cqual(TWORD, TWORD); +void defloc(struct symtab *); +int fldchk(int); +int nncon(NODE *); +void cunput(char); +NODE *nametree(struct symtab *sp); +void *inlalloc(int size); +void *blkalloc(int size); +void pass1_lastchance(struct interpass *); +void fldty(struct symtab *p); +int getlab(void); +struct suedef *sueget(struct suedef *p); +void complinit(void); +NODE *structref(NODE *p, int f, char *name); +NODE *cxop(int op, NODE *l, NODE *r); +NODE *imop(int op, NODE *l, NODE *r); +NODE *cxelem(int op, NODE *p); +NODE *cxconj(NODE *p); +NODE *cxret(NODE *p, NODE *q); +NODE *cast(NODE *p, TWORD t, TWORD q); +NODE *ccast(NODE *p, TWORD t, TWORD u, union dimfun *df, struct attr *sue); +int andable(NODE *); +int conval(NODE *, int, NODE *); +int ispow2(CONSZ); +void defid(NODE *q, int class); +void efcode(void); +void ecomp(NODE *p); +int upoff(int size, int alignment, int *poff); +void nidcl(NODE *p, int class); +void eprint(NODE *, int, int *, int *); +int uclass(int class); +int notlval(NODE *); +void ecode(NODE *p); +void ftnend(void); +void dclargs(void); +int suemeq(struct attr *s1, struct attr *s2); +struct symtab *strmemb(struct attr *ap); +int yylex(void); +void yyerror(char *); +int pragmas_gcc(char *t); +NODE *cstknode(TWORD t, union dimfun *df, struct attr *ap); +int concast(NODE *p, TWORD t); +#ifdef WORD_ADDRESSED +#define rmpconv(p) (p) +#else +NODE *rmpconv(NODE *); +#endif +NODE *nlabel(int label); +int isbuiltin(char *n); +char *getexname(struct symtab *); + +enum { ATTR_FIRST = ATTR_MI_MAX + 1, + + /* PCC used attributes */ + ATTR_COMPLEX, /* Internal definition of complex */ + xxxATTR_BASETYP, /* Internal; see below */ + ATTR_QUALTYP, /* Internal; const/volatile, see below */ + ATTR_ALIGNED, + ATTR_STRUCT, /* Internal; element list */ +#define ATTR_MAX ATTR_STRUCT + + ATTR_SONAME, + +#ifdef GCC_COMPAT + /* type attributes */ + GCC_ATYP_PACKED, + GCC_ATYP_SECTION, + GCC_ATYP_TRANSP_UNION, + GCC_ATYP_UNUSED, + GCC_ATYP_DEPRECATED, + GCC_ATYP_MAYALIAS, + + /* variable attributes */ + GCC_ATYP_MODE, + + /* function attributes */ + GCC_ATYP_NORETURN, + GCC_ATYP_FORMAT, + GCC_ATYP_NONNULL, + GCC_ATYP_SENTINEL, + GCC_ATYP_WEAK, + GCC_ATYP_FORMATARG, + GCC_ATYP_GNU_INLINE, + GCC_ATYP_MALLOC, + GCC_ATYP_NOTHROW, + GCC_ATYP_CONST, + GCC_ATYP_PURE, + GCC_ATYP_CONSTRUCTOR, + GCC_ATYP_DESTRUCTOR, + GCC_ATYP_VISIBILITY, + GCC_ATYP_WARN_UNUSED_RESULT, + GCC_ATYP_USED, + GCC_ATYP_NO_INSTR_FUN, + GCC_ATYP_NOINLINE, + GCC_ATYP_ALIAS, + GCC_ATYP_WEAKREF, + GCC_ATYP_ALLOCSZ, + GCC_ATYP_ALW_INL, + GCC_ATYP_TLSMODEL, + GCC_ATYP_ALIASWEAK, + GCC_ATYP_REGPARM, + GCC_ATYP_FASTCALL, + + /* other stuff */ + GCC_ATYP_BOUNDED, /* OpenBSD extra boundary checks */ + + GCC_ATYP_MAX, +#endif +#ifdef ATTR_P1_TARGET + ATTR_P1_TARGET, +#endif + ATTR_P1_MAX + +}; + +struct flt { + long double fp; +}; +typedef struct flt FLT; +extern FLT flt_zero; +#define fltallo() tmpalloc(sizeof(FLT)) +#define FCAST(x) ((FLT *)x) + +#define FLOAT_ZERO (&flt_zero) +#define FLOAT_PLUS(p1,p2) (FCAST((p1)->n_dcon)->fp += FCAST((p2)->n_dcon)->fp) +#define FLOAT_MINUS(p1,p2) (FCAST((p1)->n_dcon)->fp -= FCAST((p2)->n_dcon)->fp) +#define FLOAT_MUL(p1,p2) (FCAST((p1)->n_dcon)->fp *= FCAST((p2)->n_dcon)->fp) +#define FLOAT_DIV(p1,p2) (FCAST((p1)->n_dcon)->fp /= FCAST((p2)->n_dcon)->fp) +#define FLOAT_ISZERO(p) ((p)->fp == 0.0) +#define FLOAT_FP2FP(f,t) (f->fp = (t == FLOAT ? (float)f->fp : \ + t == DOUBLE ? (double)f->fp : f->fp)) +#define FLOAT_INT2FP(d,p,v) (ISUNSIGNED(v) ? \ + (d->fp = (long double)(U_CONSZ)(p)) : (d->fp = (long double)(CONSZ)(p))) +#define FLOAT_FP2INT(i,d,t) (ISUNSIGNED(t) ? \ + (i = (U_CONSZ)(d->fp)) : (i = d->fp)) +#define FLOAT_EQ(d1,d2) (d1->fp == d2->fp) +#define FLOAT_NE(d1,d2) (d1->fp != d2->fp) +#define FLOAT_GE(d1,d2) (d1->fp >= d2->fp) +#define FLOAT_GT(d1,d2) (d1->fp > d2->fp) +#define FLOAT_LE(d1,d2) (d1->fp <= d2->fp) +#define FLOAT_LT(d1,d2) (d1->fp < d2->fp) +#define FLOAT_NEG(p) (p->fp = -p->fp) +#define FLOAT_SETZERO(d) (d)->fp = FLOAT_ZERO + + +/* +#ifdef notdef + * ATTR_BASETYP has the following layout: + * aa[0].iarg has size + * aa[1].iarg has alignment +#endif + * ATTR_QUALTYP has the following layout: + * aa[0].iarg has CON/VOL + FUN/ARY/PTR + * Not defined yet... + * aa[3].iarg is dimension for arrays (XXX future) + * aa[3].varg is function defs for functions. + */ +#ifdef notdef +#define atypsz aa[0].iarg +#define aalign aa[1].iarg +#endif + +/* + * ATTR_STRUCT member list. + */ +#define amlist aa[0].varg +#define amsize aa[1].iarg +#define strattr(x) (attr_find(x, ATTR_STRUCT)) + +#define iarg(x) aa[x].iarg +#define sarg(x) aa[x].sarg +#define varg(x) aa[x].varg + +void gcc_init(void); +int gcc_keyword(char *, NODE **); +struct attr *gcc_attr_parse(NODE *); +void gcc_tcattrfix(NODE *); +struct gcc_attrib *gcc_get_attr(struct suedef *, int); +void dump_attr(struct attr *gap); + +#ifndef NO_C_BUILTINS +struct bitable { + char *name; + NODE *(*fun)(const struct bitable *, NODE *a); + short flags; +#define BTNOPROTO 001 +#define BTNORVAL 002 +#define BTNOEVE 004 + short narg; + TWORD *tp; + TWORD rt; +}; + +NODE *builtin_check(struct symtab *, NODE *a); +void builtin_init(void); + +/* Some builtins targets need to implement */ +NODE *builtin_frame_address(const struct bitable *bt, NODE *a); +NODE *builtin_return_address(const struct bitable *bt, NODE *a); +NODE *builtin_cfa(const struct bitable *bt, NODE *a); +#endif + + +#ifdef STABS +void stabs_init(void); +void stabs_file(char *); +void stabs_efile(char *); +void stabs_line(int); +void stabs_rbrac(int); +void stabs_lbrac(int); +void stabs_func(struct symtab *); +void stabs_newsym(struct symtab *); +void stabs_chgsym(struct symtab *); +void stabs_struct(struct symtab *, struct attr *); +#endif + +#ifndef CHARCAST +/* to make character constants into character connstants */ +/* this is a macro to defend against cross-compilers, etc. */ +#define CHARCAST(x) (char)(x) +#endif + +/* sometimes int is smaller than pointers */ +#if SZPOINT(CHAR) <= SZINT +#define INTPTR INT +#elif SZPOINT(CHAR) <= SZLONG +#define INTPTR LONG +#elif SZPOINT(CHAR) <= SZLONGLONG +#define INTPTR LONGLONG +#else +#error int size unknown +#endif + +#ifdef TWOPASS +#define PRTPREF "* " +#else +#define PRTPREF "" +#endif + +/* Generate a bitmask from a given type size */ +#define SZMASK(y) ((((1LL << ((y)-1))-1) << 1) | 1) + +/* + * C compiler first pass extra defines. + */ +#define QUALIFIER (MAXOP+1) +#define CLASS (MAXOP+2) +#define RB (MAXOP+3) +#define DOT (MAXOP+4) +#define ELLIPSIS (MAXOP+5) +#define TYPE (MAXOP+6) +#define LB (MAXOP+7) +#define COMOP (MAXOP+8) +#define QUEST (MAXOP+9) +#define COLON (MAXOP+10) +#define ANDAND (MAXOP+11) +#define OROR (MAXOP+12) +#define NOT (MAXOP+13) +#define CAST (MAXOP+14) +#define STRING (MAXOP+15) + +/* The following must be in the same order as their NOASG counterparts */ +#define PLUSEQ (MAXOP+16) +#define MINUSEQ (MAXOP+17) +#define DIVEQ (MAXOP+18) +#define MODEQ (MAXOP+19) +#define MULEQ (MAXOP+20) +#define ANDEQ (MAXOP+21) +#define OREQ (MAXOP+22) +#define EREQ (MAXOP+23) +#define LSEQ (MAXOP+24) +#define RSEQ (MAXOP+25) + +#define UNASG (-(PLUSEQ-PLUS))+ + +#define INCR (MAXOP+26) +#define DECR (MAXOP+27) +#define SZOF (MAXOP+28) +#define CLOP (MAXOP+29) +#define ATTRIB (MAXOP+30) +#define XREAL (MAXOP+31) +#define XIMAG (MAXOP+32) +#define TYMERGE (MAXOP+33) +#define LABEL (MAXOP+34) +#define STREF (MAXOP+35) + +/* + * The following types are only used in pass1. + */ +#define SIGNED (MAXTYPES+1) +#define FARG (MAXTYPES+2) +#define FIMAG (MAXTYPES+3) +#define IMAG (MAXTYPES+4) +#define LIMAG (MAXTYPES+5) +#define FCOMPLEX (MAXTYPES+6) +#define COMPLEX (MAXTYPES+7) +#define LCOMPLEX (MAXTYPES+8) +#define ENUMTY (MAXTYPES+9) + +#define ISFTY(x) ((x) >= FLOAT && (x) <= LDOUBLE) +#define ISCTY(x) ((x) >= FCOMPLEX && (x) <= LCOMPLEX) +#define ISITY(x) ((x) >= FIMAG && (x) <= LIMAG) +#define ANYCX(p) (p->n_type == STRTY && attr_find(p->n_ap, ATTR_COMPLEX)) + +#define coptype(o) (cdope(o)&TYFLG) +#define clogop(o) (cdope(o)&LOGFLG) +#define casgop(o) (cdope(o)&ASGFLG) + +#define slval setlval +#define glval getlval + +#include + diff --git a/lang/pcc/pcc/cc/cxxcom/pftn.c b/lang/pcc/pcc/cc/cxxcom/pftn.c new file mode 100644 index 000000000..2e73c90b8 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/pftn.c @@ -0,0 +1,3325 @@ +/* $Id: pftn.c,v 1.16 2016/03/05 15:31:25 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ + +/* + * Many changes from the 32V sources, among them: + * - New symbol table manager (moved to another file). + * - Prototype saving/checks. + */ + +# include "pass1.h" + +#include "cgram.h" + +struct symtab *cftnsp; +int arglistcnt, dimfuncnt; /* statistics */ +int symtabcnt, suedefcnt; /* statistics */ +int autooff, /* the next unused automatic offset */ + maxautooff, /* highest used automatic offset in function */ + argoff; /* the next unused argument offset */ +int retlab = NOLAB; /* return label for subroutine */ +int brklab; +int contlab; +int flostat; +int blevel; +int reached, prolab; + +struct params; + +#define MKTY(p, t, d, s) r = talloc(); *r = *p; \ + r = argcast(r, t, d, s); *p = *r; nfree(r); + +/* + * Linked list stack while reading in structs. + */ +struct rstack { + struct rstack *rnext; + int rsou; + int rstr; + struct symtab *rsym; +// struct symtab *rb; + struct attr *ap; + int flags; +#define LASTELM 1 +} *rpole; + +/* + * Linked list for parameter (and struct elements) declaration. + */ +static struct params { + struct params *prev; + struct symtab *sym; +} *lparam; +static int nparams; + +/* defines used for getting things off of the initialization stack */ + +NODE *arrstk[10]; +int arrstkp; +static int intcompare; +NODE *parlink; + +void fixtype(NODE *p, int class); +int fixclass(int class, TWORD type); +static void dynalloc(struct symtab *p, int *poff); +static void evalidx(struct symtab *p); +int isdyn(struct symtab *p); +void inforce(OFFSZ n); +void vfdalign(int n); +static void ssave(struct symtab *); +#ifdef PCC_DEBUG +static void alprint(union arglist *al, int in); +#endif +static void lcommadd(struct symtab *sp); +static NODE *mkcmplx(NODE *p, TWORD dt); +extern int fun_inline; + +FLT flt_zero = { .fp = 0.0, }; + +/* + * Declaration of an identifier. Handles redeclarations, hiding, + * incomplete types and forward declarations. + * + * q is a TYPE node setup after parsing with n_type, n_df and n_ap. + * n_sp is a pointer to the not-yet initalized symbol table entry + * unless it's a redeclaration or supposed to hide a variable. + */ + +void +defid(NODE *q, int class) +{ + struct attr *ap; + struct symtab *p; + TWORD type, qual; + TWORD stp, stq; + int scl; + union dimfun *dsym, *ddef; + int slev, temp, changed; + + if (q == NIL) + return; /* an error was detected */ + + p = q->n_sp; + + if (p->sname == NULL) + cerror("defining null identifier"); + +#ifdef PCC_DEBUG + if (ddebug) { + printf("defid(%s (%p), ", p->sname, p); + tprint(q->n_type, q->n_qual); + printf(", %s, (%p)), level %d\n\t", scnames(class), + q->n_df, blevel); +#ifdef GCC_COMPAT + dump_attr(q->n_ap); +#endif + } +#endif + + fixtype(q, class); + + type = q->n_type; + qual = q->n_qual; + class = fixclass(class, type); + + stp = p->stype; + stq = p->squal; + slev = p->slevel; + +#ifdef PCC_DEBUG + if (ddebug) { + printf(" modified to "); + tprint(type, qual); + printf(", %s\n", scnames(class)); + printf(" previous def'n: "); + tprint(stp, stq); + printf(", %s, (%p,%p)), level %d\n", + scnames(p->sclass), p->sdf, p->sap, slev); + } +#endif + + if (blevel == 1) { + switch (class) { + default: + if (!(class&FIELD) && !ISFTN(type)) + uerror("declared argument %s missing", + p->sname ); + case MOS: + case MOU: + cerror("field5"); + case TYPEDEF: + case PARAM: + ; + } + } + + if (stp == UNDEF) + goto enter; /* New symbol */ + + if (type != stp) + goto mismatch; + + if (blevel > slev && (class == AUTO || class == REGISTER)) + /* new scope */ + goto mismatch; + + /* + * test (and possibly adjust) dimensions. + * also check that prototypes are correct. + */ + dsym = p->sdf; + ddef = q->n_df; + changed = 0; + for (temp = type; temp & TMASK; temp = DECREF(temp)) { + if (ISARY(temp)) { + if (dsym->ddim == NOOFFSET) { + dsym->ddim = ddef->ddim; + changed = 1; + } else if (ddef->ddim != NOOFFSET && + dsym->ddim!=ddef->ddim) { + goto mismatch; + } + ++dsym; + ++ddef; + } else if (ISFTN(temp)) { + /* add a late-defined prototype here */ + if (cftnsp == NULL && dsym->dfun == NULL) + dsym->dfun = ddef->dfun; + if (!oldstyle && ddef->dfun != NULL && + chkftn(dsym->dfun, ddef->dfun)) + uerror("declaration doesn't match prototype"); + dsym++, ddef++; + } + } +#ifdef STABS + if (changed && gflag) + stabs_chgsym(p); /* symbol changed */ +#endif + + /* check that redeclarations are to the same structure */ + if (temp == STRTY || temp == UNIONTY) { + if (strmemb(p->sap) != strmemb(q->n_ap)) + goto mismatch; + } + + scl = p->sclass; + +#ifdef PCC_DEBUG + if (ddebug) + printf(" previous class: %s\n", scnames(scl)); +#endif + + /* + * Its allowed to add attributes to existing declarations. + * Be careful though not to trash existing attributes. + * XXX - code below is probably not correct. + */ + if (p->sap && p->sap->atype <= ATTR_MAX) { + /* nothing special, just overwrite */ + p->sap = q->n_ap; + } else { + if (p->slevel == blevel) { + for (ap = q->n_ap; ap; ap = ap->next) { + if (ap->atype > ATTR_MAX) + p->sap = attr_add(p->sap, attr_dup(ap)); + } + } else + p->sap = q->n_ap; + } + + if (class & FIELD) + cerror("field1"); + switch(class) { + + case EXTERN: + if (pragma_renamed) + p->soname = pragma_renamed; + pragma_renamed = NULL; + switch( scl ){ + case STATIC: + case USTATIC: + if( slev==0 ) + goto done; + break; + case EXTDEF: + case EXTERN: + goto done; + case SNULL: + if (p->sflags & SINLINE) { + p->sclass = EXTDEF; + inline_ref(p); + goto done; + } + break; + } + break; + + case STATIC: + if (scl==USTATIC || (scl==EXTERN && blevel==0)) { + p->sclass = STATIC; + goto done; + } + if (changed || (scl == STATIC && blevel == slev)) + goto done; /* identical redeclaration */ + break; + + case USTATIC: + if (scl==STATIC || scl==USTATIC) + goto done; + break; + + case TYPEDEF: + if (scl == class) + goto done; + break; + + case MOU: + case MOS: + cerror("field6"); + + case EXTDEF: + switch (scl) { + case EXTERN: + p->sclass = EXTDEF; + goto done; + case USTATIC: + p->sclass = STATIC; + goto done; + case SNULL: + /* + * Handle redeclarations of inlined functions. + * This is allowed if the previous declaration is of + * type gnu_inline. + */ +#ifdef GCC_COMPAT + if (attr_find(p->sap, GCC_ATYP_GNU_INLINE)) + goto done; +#endif + break; + } + break; + + case AUTO: + case REGISTER: + break; /* mismatch.. */ + case SNULL: + if (fun_inline && ISFTN(type)) + goto done; + break; + } + + mismatch: + + /* + * Only allowed for automatic variables. + */ + if (blevel <= slev || class == EXTERN) { + uerror("redeclaration of %s", p->sname); + return; + } + q->n_sp = p = hide(p); + + enter: /* make a new entry */ + +#ifdef PCC_DEBUG + if(ddebug) + printf(" new entry made\n"); +#endif +#ifdef GCC_COMPAT + if (type < BTMASK && (ap = attr_find(q->n_ap, GCC_ATYP_MODE))) { + type = ENUNSIGN(ap->iarg(0)); + if (type == XTYPE) + uerror("fix XTYPE basetyp"); + } +#endif + p->stype = type; + p->squal = qual; + p->sclass = (char)class; + p->slevel = (char)blevel; + p->soffset = NOOFFSET; +#if 0 + if (class != TYPEDEF && blevel == 0) + p->soname = decoratename(p, NM_NORMAL); +#endif + if (q->n_ap) + p->sap = attr_add(q->n_ap, p->sap); + + /* copy dimensions */ + p->sdf = q->n_df; + /* Do not save param info for old-style functions */ + if (ISFTN(type) && oldstyle) + p->sdf->dfun = NULL; + + if (arrstkp) + evalidx(p); + + /* allocate offsets */ + if (class&FIELD) { + cerror("field2"); /* new entry */ + } else switch (class) { + + case REGISTER: + cerror("register var"); + + case AUTO: + if (isdyn(p)) { + p->sflags |= SDYNARRAY; + dynalloc(p, &autooff); + } else + oalloc(p, &autooff); + break; + + case PARAM: + if (q->n_type != FARG) + oalloc(p, &argoff); + break; + + case STATIC: + case EXTDEF: + case EXTERN: + p->soffset = getlab(); + if (pragma_renamed) + p->soname = pragma_renamed; + pragma_renamed = NULL; + break; + + case MOU: + case MOS: + cerror("field7"); + case SNULL: +#ifdef notdef + if (fun_inline) { + p->slevel = 1; + p->soffset = getlab(); + } +#endif + break; + } + +#ifdef STABS + if (gflag && p->stype != FARG) + stabs_newsym(p); +#endif + +done: + cxxsetname(p); + fixdef(p); /* Leave last word to target */ +#ifndef HAVE_WEAKREF + { + struct attr *at; + + /* Refer renamed function */ + if ((at = attr_find(p->sap, GCC_ATYP_WEAKREF))) + p->soname = at->sarg(0); + } +#endif +#ifdef PCC_DEBUG + if (ddebug) { + printf( " sdf, offset: %p, %d\n\t", + p->sdf, p->soffset); +#ifdef GCC_COMPAT + dump_attr(p->sap); +#endif + } +#endif +} + +void +ssave(struct symtab *sym) +{ + struct params *p; + + p = tmpalloc(sizeof(struct params)); + p->prev = lparam; + p->sym = sym; + lparam = p; +} + +/* + * end of function + */ +void +ftnend(void) +{ +#ifdef GCC_COMPAT + struct attr *gc, *gd; +#endif + extern NODE *cftnod; + extern struct savbc *savbc; + extern struct swdef *swpole; + extern int tvaloff; + char *c; + + if (retlab != NOLAB && nerrors == 0) { /* inside a real function */ + plabel(retlab); + if (cftnod) + ecomp(buildtree(FORCE, cftnod, NIL)); + efcode(); /* struct return handled here */ + if ((c = cftnsp->soname) == NULL) + c = addname(exname(cftnsp->sname)); + SETOFF(maxautooff, ALCHAR); + send_passt(IP_EPILOG, maxautooff/SZCHAR, c, + cftnsp->stype, cftnsp->sclass == EXTDEF, retlab, tvaloff); + } + + cftnod = NIL; + tcheck(); + brklab = contlab = retlab = NOLAB; + flostat = 0; + if (nerrors == 0) { + if (savbc != NULL) + cerror("bcsave error"); + if (lparam != NULL) + cerror("parameter reset error"); + if (swpole != NULL) + cerror("switch error"); + } +#ifdef GCC_COMPAT + if (cftnsp) { + gc = attr_find(cftnsp->sap, GCC_ATYP_CONSTRUCTOR); + gd = attr_find(cftnsp->sap, GCC_ATYP_DESTRUCTOR); + if (gc || gd) { + struct symtab sts = *cftnsp; + NODE *p; + sts.stype = INCREF(sts.stype); + p = nametree(&sts); + p->n_op = ICON; + if (gc) { + locctr(CTORS, &sts); + inval(0, SZPOINT(0), p); + } + if (gd) { + locctr(DTORS, &sts); + inval(0, SZPOINT(0), p); + } + tfree(p); + } + } +#endif + savbc = NULL; + lparam = NULL; + cftnsp = NULL; + maxautooff = autooff = AUTOINIT; + reached = 1; + + if (isinlining) + inline_end(); + inline_prtout(); + + tmpfree(); /* Release memory resources */ +} + +static struct symtab nulsym = { + NULL, NULL, NULL, 0, 0, 0, 0, "null", "null", INT, 0, NULL, NULL +}; + +void +dclargs(void) +{ + union dimfun *df; + union arglist *al, *al2, *alb; + struct params *a; + struct symtab *p, **parr = NULL; /* XXX gcc */ + int i; + + /* + * Deal with fun(void) properly. + */ + if (nparams == 1 && lparam->sym && lparam->sym->stype == VOID) + goto done; + + if (cftnsp->sdown && cftnsp->sdown->sclass != NSPACE) { + /* first arg is a pointer to the "sprev" class */ + p = cxxstrvar(cftnsp->sdown); + ssave(p); + nparams++; + } + /* + * Generate a list for bfcode(). + * Parameters were pushed in reverse order. + */ + if (nparams != 0) + parr = tmpalloc(sizeof(struct symtab *) * nparams); + + if (nparams) + for (a = lparam, i = 0; a != NULL; a = a->prev) { + p = a->sym; + parr[i++] = p; + if (p == NULL) { + uerror("parameter %d name missing", i); + p = &nulsym; /* empty symtab */ + } + if (p->stype == FARG) + p->stype = INT; + if (ISARY(p->stype)) { + p->stype += (PTR-ARY); + p->sdf++; + } else if (ISFTN(p->stype)) { + werror("function declared as argument"); + p->stype = INCREF(p->stype); + } +#ifdef STABS + if (gflag) + stabs_newsym(p); +#endif + } + if (oldstyle && (df = cftnsp->sdf) && (al = df->dfun)) { + /* + * Check against prototype of oldstyle function. + */ + alb = al2 = tmpalloc(sizeof(union arglist) * nparams * 3 + 1); + for (i = 0; i < nparams; i++) { + TWORD type = parr[i]->stype; + (al2++)->type = type; + if (ISSOU(BTYPE(type))) + (al2++)->sap = parr[i]->sap; + while (!ISFTN(type) && !ISARY(type) && type > BTMASK) + type = DECREF(type); + if (type > BTMASK) + (al2++)->df = parr[i]->sdf; + } + al2->type = TNULL; + intcompare = 1; + if (chkftn(al, alb)) + uerror("function doesn't match prototype"); + intcompare = 0; + + } + + if (oldstyle && nparams) { + /* Must recalculate offset for oldstyle args here */ + argoff = ARGINIT; + for (i = 0; i < nparams; i++) { + parr[i]->soffset = NOOFFSET; + oalloc(parr[i], &argoff); + } + } + +done: autooff = AUTOINIT; + + plabel(prolab); /* after prolog, used in optimization */ + retlab = getlab(); + bfcode(parr, nparams); + if (fun_inline && (xinline +#ifdef GCC_COMPAT + || attr_find(cftnsp->sap, GCC_ATYP_ALW_INL) +#endif + )) + inline_args(parr, nparams); + plabel(getlab()); /* used when spilling */ + if (parlink) + ecomp(parlink); + parlink = NIL; + lparam = NULL; + nparams = 0; + symclear(1); /* In case of function pointer args */ +} + +/* + * basic attributes for structs and enums + */ +static struct attr * +seattr(void) +{ + return attr_add(attr_new(ATTR_ALIGNED, 4), attr_new(ATTR_STRUCT, 2)); +} + +/* + * Struct/union/enum symtab construction. + */ +static void +defstr(struct symtab *sp, int class) +{ + sp->sclass = (char)class; + if (class == STNAME || class == CLNAME) + sp->stype = STRTY; + else if (class == UNAME) + sp->stype = UNIONTY; + else if (class == ENAME) + sp->stype = ENUMTY; +} + +/* + * Declare a struct/union/enum tag. + * If not found, create a new tag with UNDEF type. + */ +static struct symtab * +deftag(char *name, int class) +{ + struct symtab *sp; + + if ((sp = cxxdclstr(name))->sap == NULL) { + /* New tag */ + defstr(sp, class); + } else if (sp->sclass != class) + uerror("tag %s redeclared", name); + return sp; +} + +/* + * reference to a structure or union, with no definition + */ +NODE * +rstruct(char *tag, int soru) +{ + struct symtab *sp; + + sp = deftag(tag, soru); + if (sp->sap == NULL) + sp->sap = seattr(); + return mkty(sp->stype, 0, sp->sap); +} + +static int enumlow, enumhigh; +int enummer; + +/* + * Declare a member of enum. + */ +void +moedef(char *name) +{ + struct symtab *sp; + + sp = lookup(name, SNORMAL); + if (sp->stype == UNDEF || (sp->slevel < blevel)) { + if (sp->stype != UNDEF) + sp = hide(sp); + sp->stype = INT; /* always */ + sp->sclass = MOE; + sp->soffset = enummer; + } else + uerror("%s redeclared", name); + if (enummer < enumlow) + enumlow = enummer; + if (enummer > enumhigh) + enumhigh = enummer; + enummer++; +} + +/* + * Declare an enum tag. Complain if already defined. + */ +struct symtab * +enumhd(char *name) +{ + struct attr *ap; + struct symtab *sp; + + enummer = enumlow = enumhigh = 0; + if (name == NULL) + return NULL; + + sp = deftag(name, ENAME); + if (sp->stype != ENUMTY) { + if (sp->slevel == blevel) + uerror("%s redeclared", name); + sp = hide(sp); + defstr(sp, ENAME); + } + if (sp->sap == NULL) + ap = sp->sap = attr_new(ATTR_STRUCT, 4); + else + ap = attr_find(sp->sap, ATTR_STRUCT); + ap->amlist = sp; + return sp; +} + +/* + * finish declaration of an enum + */ +NODE * +enumdcl(struct symtab *sp) +{ + NODE *p; + TWORD t; + +#ifdef ENUMSIZE + t = ENUMSIZE(enumhigh, enumlow); +#else + t = ctype(enumlow < 0 ? INT : UNSIGNED); +#ifdef notdef + if (enumhigh <= MAX_CHAR && enumlow >= MIN_CHAR) + t = ctype(CHAR); + else if (enumhigh <= MAX_SHORT && enumlow >= MIN_SHORT) + t = ctype(SHORT); + else + t = ctype(INT); +#endif +#endif + + if (sp) + sp->stype = t; + p = mkty(t, 0, 0); + p->n_sp = sp; + return p; +} + +/* + * Handle reference to an enum + */ +NODE * +enumref(char *name) +{ + struct symtab *sp; + NODE *p; + + sp = lookup(name, STAGNAME); + +#ifdef notdef + /* + * 6.7.2.3 Clause 2: + * "A type specifier of the form 'enum identifier' without an + * enumerator list shall only appear after the type it specifies + * is complete." + */ + if (sp->sclass != ENAME) + uerror("enum %s undeclared", name); +#endif + if (sp->sclass == SNULL) { + /* declare existence of enum */ + sp = enumhd(name); + sp->stype = ENUMTY; + } + + p = mkty(sp->stype, 0, sp->sap); + p->n_sp = sp; + return p; +} + +/* + * begining of structure or union declaration + * It's an error if this routine is called twice with the same struct. + */ +struct rstack * +bstruct(char *name, int soru, NODE *gp) +{ + struct rstack *r; + struct symtab *sp; + struct attr *ap, *gap; + char nbuf[20]; + +#ifdef GCC_COMPAT + gap = gp ? gcc_attr_parse(gp) : NULL; +#else + gap = NULL; +#endif + + if (name == NULL) { + static int ancnt; + snprintf(nbuf, sizeof(nbuf), "__%%ANON%d", ancnt++); + name = addname(nbuf); + } + + if (name != NULL) { + sp = deftag(name, soru); + if (sp->sap == NULL) + sp->sap = seattr(); + ap = attr_find(sp->sap, ATTR_ALIGNED); + if (ap->iarg(0) != 0) { + if (sp->slevel < blevel) { + sp = hide(sp); + defstr(sp, soru); + sp->sap = seattr(); + } else + uerror("%s redeclared", name); + } + INSSYM(sp); + nscur = sp; + gap = sp->sap = attr_add(sp->sap, gap); + } else { + gap = attr_add(seattr(), gap); + sp = getsymtab("__%", SNORMAL); + } + + r = tmpcalloc(sizeof(struct rstack)); + r->rsou = soru; + r->rsym = sp; +// r->rb = NULL; + r->ap = gap; + r->rnext = rpole; + rpole = r; + + return r; +} + +/* + * Called after a struct is declared to restore the environment. + * - If ALSTRUCT is defined, this will be the struct alignment and the + * struct size will be a multiple of ALSTRUCT, otherwise it will use + * the alignment of the largest struct member. + */ +NODE * +dclstruct(struct rstack *r) +{ + NODE *n; + struct attr *aps, *apb; + struct symtab *sp; + int al, sa, sz; + + apb = attr_find(r->ap, ATTR_ALIGNED); + aps = attr_find(r->ap, ATTR_STRUCT); +// aps->amlist = r->rb; + aps->amlist = nscur->sup; + +#ifdef ALSTRUCT + al = ALSTRUCT; +#else + al = ALCHAR; +#endif + + /* + * extract size and alignment, calculate offsets + */ + for (sp = /* r->rb */nscur->sup; sp; sp = sp->snext) { + sp->sdown = r->rsym; + if (ISFTN(sp->stype)) + continue; + sa = talign(sp->stype, sp->sap); + if (sp->sclass & FIELD) + sz = sp->sclass&FLDSIZ; + else + sz = (int)tsize(sp->stype, sp->sdf, sp->sap); + if (sz > rpole->rstr) + rpole->rstr = sz; /* for use with unions */ + /* + * set al, the alignment, to the lcm of the alignments + * of the members. + */ + SETOFF(al, sa); + } + + SETOFF(rpole->rstr, al); + + aps->amsize = rpole->rstr; + apb->iarg(0) = al; + +#ifdef PCC_DEBUG + if (ddebug) { + printf("dclstruct(%s): size=%d, align=%d\n", + r->rsym ? r->rsym->sname : "??", + aps->amsize, apb->iarg(0)); + } + if (ddebug>1) { + printf("\tsize %d align %d link %p\n", + aps->amsize, apb->iarg(0), aps->amlist); + for (sp = aps->amlist; sp != NULL; sp = sp->snext) { + printf("\tmember %s(%p)\n", sp->sname, sp); + } + } +#endif + +#ifdef STABS + if (gflag) + stabs_struct(r->rsym, r->ap); +#endif + + rpole = r->rnext; + n = mkty(r->rsou == STNAME ? STRTY : UNIONTY, 0, r->ap); + n->n_sp = r->rsym; + + POPSYM(); + + n->n_qual |= 1; /* definition place XXX used by attributes */ + return n; +} + +/* + * Add a new member to the current struct or union being declared. + */ +void +soumemb(NODE *n, char *name, int class) +{ + struct symtab *sp, *lsp; + int incomp, tsz, al; + TWORD t; + + if (rpole == NULL) + cerror("soumemb"); + + /* check if tag name exists */ + lsp = NULL; + for (sp = /* rpole->rb */ nscur->sup; sp != NULL; lsp = sp, sp = sp->snext) + if (*name != '*' && sp->sname == name && class == sp->sclass) + uerror("redeclaration of %s", name); + + sp = getsymtab(name, SMOSNAME); +#if 0 + if (rpole->rb == NULL) + rpole->rb = sp; + else + lsp->snext = sp; +#endif + if (nscur->sup == NULL) + nscur->sup = sp; + else + lsp->snext = sp; + + n->n_sp = sp; + sp->stype = n->n_type; + sp->squal = n->n_qual; + sp->slevel = blevel; + sp->sap = n->n_ap; + sp->sdf = n->n_df; + sp->sdown = rpole->rsym; + + if (class & FIELD) { + sp->sclass = (char)class; + falloc(sp, class&FLDSIZ, NIL); + } else if (class == STATIC) { + sp->sclass = USTATIC; + cxxsetname(sp); + } else if (ISFTN(sp->stype)) { + sp->sclass = EXTERN; + cxxsetname(sp); + } else if (rpole->rsou == STNAME || rpole->rsou == UNAME) { + sp->sclass = rpole->rsou == STNAME ? MOS : MOU; + if (sp->sclass == MOU) + rpole->rstr = 0; + al = talign(sp->stype, sp->sap); + tsz = (int)tsize(sp->stype, sp->sdf, sp->sap); + sp->soffset = upoff(tsz, al, &rpole->rstr); + } + + /* + * 6.7.2.1 clause 16: + * "...the last member of a structure with more than one + * named member may have incomplete array type;" + */ + if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET) + incomp = 1; + else + incomp = 0; + if ((rpole->flags & LASTELM) || (/* rpole->rb */ nscur->sup == sp && incomp == 1)) + uerror("incomplete array in struct"); + if (incomp == 1) + rpole->flags |= LASTELM; + + /* + * 6.7.2.1 clause 2: + * "...such a structure shall not be a member of a structure + * or an element of an array." + */ + t = sp->stype; + if (rpole->rsou != STNAME || BTYPE(t) != STRTY) + return; /* not for unions */ + while (ISARY(t)) + t = DECREF(t); + if (ISPTR(t)) + return; + + if ((lsp = strmemb(sp->sap)) != NULL) { + for (; lsp->snext; lsp = lsp->snext) + ; + if (ISARY(lsp->stype) && lsp->snext && + lsp->sdf->ddim == NOOFFSET) + uerror("incomplete struct in struct"); + } +} + +/* + * error printing routine in parser + */ +void +yyerror(char *s) +{ + uerror(s); +} + +void yyaccpt(void); +void +yyaccpt(void) +{ + ftnend(); +} + +/* + * p is top of type list given to tymerge later. + * Find correct CALL node and declare parameters from there. + */ +void +ftnarg(NODE *p) +{ + NODE *q; + +#ifdef PCC_DEBUG + if (ddebug > 2) + printf("ftnarg(%p)\n", p); +#endif + /* + * Push argument symtab entries onto param stack in reverse order, + * due to the nature of the stack it will be reclaimed correct. + */ + for (; p->n_op != NAME; p = p->n_left) { + if (p->n_op == UCALL && p->n_left->n_op == NAME) + return; /* Nothing to enter */ + if (p->n_op == CALL && + (p->n_left->n_op == NAME || p->n_left->n_op == NMLIST)) + break; + } + + p = p->n_right; + while (p->n_op == CM) { + q = p->n_right; + if (q->n_op != ELLIPSIS) { + ssave(q->n_sp); + nparams++; +#ifdef PCC_DEBUG + if (ddebug > 2) + printf(" saving sym %s (%p) from (%p)\n", + q->n_sp->sname, q->n_sp, q); +#endif + } + p = p->n_left; + } + ssave(p->n_sp); + if (p->n_type != VOID) + nparams++; + +#ifdef PCC_DEBUG + if (ddebug > 2) + printf(" saving sym %s (%p) from (%p)\n", + nparams ? p->n_sp->sname : "", p->n_sp, p); +#endif +} + +/* + * compute the alignment of an object with type ty, sizeoff index s + */ +int +talign(unsigned int ty, struct attr *apl) +{ + struct attr *al; + int a; + + for (; ty > BTMASK; ty = DECREF(ty)) { + switch (ty & TMASK) { + case PTR: + return(ALPOINT); + case ARY: + continue; + case FTN: + cerror("compiler takes alignment of function"); + } + } + + /* check for alignment attribute */ + if ((al = attr_find(apl, ATTR_ALIGNED))) { + if ((a = al->iarg(0)) == 0) { + uerror("no alignment"); + a = ALINT; + } + return a; + } + + ty = BTYPE(ty); + if (ty >= CHAR && ty <= ULONGLONG && ISUNSIGNED(ty)) + ty = DEUNSIGN(ty); + + switch (ty) { + case BOOL: a = ALBOOL; break; + case CHAR: a = ALCHAR; break; + case SHORT: a = ALSHORT; break; + case INT: a = ALINT; break; + case LONG: a = ALLONG; break; + case LONGLONG: a = ALLONGLONG; break; + case FLOAT: a = ALFLOAT; break; + case DOUBLE: a = ALDOUBLE; break; + case LDOUBLE: a = ALLDOUBLE; break; + default: + uerror("no alignment"); + a = ALINT; + } + return a; +} + +short sztable[] = { 0, SZBOOL, SZCHAR, SZCHAR, SZSHORT, SZSHORT, SZINT, SZINT, + SZLONG, SZLONG, SZLONGLONG, SZLONGLONG, SZFLOAT, SZDOUBLE, SZLDOUBLE }; + +/* compute the size associated with type ty, + * dimoff d, and sizoff s */ +/* BETTER NOT BE CALLED WHEN t, d, and s REFER TO A BIT FIELD... */ +OFFSZ +tsize(TWORD ty, union dimfun *d, struct attr *apl) +{ + struct attr *ap, *ap2; + OFFSZ mult, sz; + + mult = 1; + + for (; ty > BTMASK; ty = DECREF(ty)) { + switch (ty & TMASK) { + + case FTN: + uerror( "cannot take size of function"); + case PTR: + return( SZPOINT(ty) * mult ); + case ARY: + if (d->ddim == NOOFFSET) + return 0; + if (d->ddim < 0) + cerror("tsize: dynarray"); + mult *= d->ddim; + d++; + } + } + + if (ty == VOID) + ty = CHAR; + if (ty <= LDOUBLE) + sz = sztable[ty]; + else if (ISSOU(ty)) { + if ((ap = strattr(apl)) == NULL || + (ap2 = attr_find(apl, ATTR_ALIGNED)) == NULL || + (ap2->iarg(0) == 0)) { + uerror("unknown structure/union/enum"); + sz = SZINT; + } else + sz = ap->amsize; + } else { + uerror("unknown type"); + sz = SZINT; + } + + return((unsigned int)sz * mult); +} + +/* + * Save string (and print it out). If wide then wide string. + */ +NODE * +strend(int wide, char *str) +{ + struct symtab *sp; + NODE *p; + + /* If an identical string is already emitted, just forget this one */ + if (wide) { + /* Do not save wide strings, at least not now */ + sp = getsymtab(str, SSTRING|STEMP); + } else { + str = addstring(str); /* enter string in string table */ + sp = lookup(str, SSTRING); /* check for existence */ + } + + if (sp->soffset == 0) { /* No string */ + char *wr; + int i; + + sp->sclass = STATIC; + sp->slevel = 1; + sp->soffset = getlab(); + sp->squal = (CON >> TSHIFT); + sp->sdf = permalloc(sizeof(union dimfun)); + if (wide) { + sp->stype = WCHAR_TYPE+ARY; + } else { + if (xuchar) { + sp->stype = UCHAR+ARY; + } else { + sp->stype = CHAR+ARY; + } + } + for (wr = sp->sname, i = 1; *wr; i++) + if (*wr++ == '\\') + (void)esccon(&wr); + + sp->sdf->ddim = i; + if (wide) + inwstring(sp); + else + instring(sp); + } + + p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap); + p->n_sp = sp; + return(clocal(p)); +} + +/* + * Print out a wide string by calling ninval(). + */ +void +inwstring(struct symtab *sp) +{ + char *s = sp->sname; + NODE *p; + + locctr(STRNG, sp); + defloc(sp); + p = xbcon(0, NULL, WCHAR_TYPE); + do { + if (*s++ == '\\') + glval(p) = esccon(&s); + else + glval(p) = (unsigned char)s[-1]; + inval(0, tsize(WCHAR_TYPE, NULL, NULL), p); + } while (s[-1] != 0); + nfree(p); +} + +#ifndef MYINSTRING +/* + * Print out a string of characters. + * Assume that the assembler understands C-style escape + * sequences. + */ +void +instring(struct symtab *sp) +{ + char *s, *str; + + locctr(STRNG, sp); + defloc(sp); + str = sp->sname; + + /* be kind to assemblers and avoid long strings */ + printf("\t.ascii \""); + for (s = str; *s != 0; ) { + if (*s++ == '\\') { + (void)esccon(&s); + } + if (s - str > 60) { + fwrite(str, 1, s - str, stdout); + printf("\"\n\t.ascii \""); + str = s; + } + } + fwrite(str, 1, s - str, stdout); + printf("\\0\"\n"); +} +#endif + +/* + * update the offset pointed to by poff; return the + * offset of a value of size `size', alignment `alignment', + * given that off is increasing + */ +int +upoff(int size, int alignment, int *poff) +{ + int off; + + off = *poff; + SETOFF(off, alignment); + if (off < 0) + cerror("structure or stack overgrown"); /* wrapped */ + *poff = off+size; + return (off); +} + +/* + * allocate p with offset *poff, and update *poff + */ +int +oalloc(struct symtab *p, int *poff ) +{ + int al, off, tsz; + int noff; + + /* + * Only generate tempnodes if we are optimizing, + * and only for integers, floats or pointers, + * and not if the type on this level is volatile. + */ + if (xtemps && ((p->sclass == AUTO) || (p->sclass == REGISTER)) && + (p->stype < STRTY || ISPTR(p->stype)) && + !(cqual(p->stype, p->squal) & VOL) && cisreg(p->stype)) { + NODE *tn = tempnode(0, p->stype, p->sdf, p->sap); + p->soffset = regno(tn); + p->sflags |= STNODE; + nfree(tn); + return 0; + } + + al = talign(p->stype, p->sap); + noff = off = *poff; + tsz = (int)tsize(p->stype, p->sdf, p->sap); +#ifdef BACKAUTO + if (p->sclass == AUTO) { + noff = off + tsz; + if (noff < 0) + cerror("stack overflow"); + SETOFF(noff, al); + off = -noff; + } else +#endif + if (p->sclass == PARAM && (p->stype == CHAR || p->stype == UCHAR || + p->stype == SHORT || p->stype == USHORT || p->stype == BOOL)) { + off = upoff(SZINT, ALINT, &noff); +#if TARGET_ENDIAN == TARGET_BE + off = noff - tsz; +#endif + } else { + off = upoff(tsz, al, &noff); + } + + if (p->sclass != REGISTER) { + /* in case we are allocating stack space for register arguments */ + if (p->soffset == NOOFFSET) + p->soffset = off; + else if(off != p->soffset) + return(1); + } + + *poff = noff; + return(0); +} + +/* + * Delay emission of code generated in argument headers. + */ +static void +edelay(NODE *p) +{ + if (blevel == 1) { + /* Delay until after declarations */ + if (parlink == NULL) + parlink = p; + else + parlink = block(COMOP, parlink, p, 0, 0, 0); + } else + ecomp(p); +} + +/* + * Traverse through the array args, evaluate them and put the + * resulting temp numbers in the dim fields. + */ +static void +evalidx(struct symtab *sp) +{ + union dimfun *df; + NODE *p; + TWORD t; + int astkp = 0; + + if (arrstk[0] == NIL) + astkp++; /* for parameter arrays */ + + if (isdyn(sp)) + sp->sflags |= SDYNARRAY; + + df = sp->sdf; + for (t = sp->stype; t > BTMASK; t = DECREF(t)) { + if (!ISARY(t)) + continue; + if (df->ddim == -1) { + p = tempnode(0, INT, 0, 0); + df->ddim = -regno(p); + edelay(buildtree(ASSIGN, p, arrstk[astkp++])); + } + df++; + } + arrstkp = 0; +} + +/* + * Return 1 if dynamic array, 0 otherwise. + */ +int +isdyn(struct symtab *sp) +{ + union dimfun *df = sp->sdf; + TWORD t; + + for (t = sp->stype; t > BTMASK; t = DECREF(t)) { + if (!ISARY(t)) + return 0; + if (df->ddim < 0 && df->ddim != NOOFFSET) + return 1; + df++; + } + return 0; +} + +/* + * Allocate space on the stack for dynamic arrays (or at least keep track + * of the index). + * Strategy is as follows: + * - first entry is a pointer to the dynamic datatype. + * - if it's a one-dimensional array this will be the only entry used. + * - if it's a multi-dimensional array the following (numdim-1) integers + * will contain the sizes to multiply the indexes with. + * - code to write the dimension sizes this will be generated here. + * - code to allocate space on the stack will be generated here. + */ +static void +dynalloc(struct symtab *p, int *poff) +{ + union dimfun *df; + NODE *n, *tn, *pol; + TWORD t; + + /* + * The pointer to the array is not necessarily stored in a + * TEMP node, but if it is, its number is in the soffset field; + */ + t = p->stype; + p->sflags |= STNODE; + p->stype = INCREF(p->stype); /* Make this an indirect pointer */ + tn = tempnode(0, p->stype, p->sdf, p->sap); + p->soffset = regno(tn); + + df = p->sdf; + + pol = bcon(1); + for (; t > BTMASK; t = DECREF(t)) { + if (!ISARY(t)) + break; + if (df->ddim < 0) + n = tempnode(-df->ddim, INT, 0, 0); + else + n = bcon(df->ddim); + + pol = buildtree(MUL, pol, n); + df++; + } + /* Create stack gap */ + spalloc(tn, pol, tsize(t, 0, p->sap)); +} + +/* + * allocate a field of width w + * new is 0 if new entry, 1 if redefinition, -1 if alignment + */ +int +falloc(struct symtab *p, int w, NODE *pty) +{ + TWORD otype, type; + int al,sz; + + otype = type = p ? p->stype : pty->n_type; + + if (type == BOOL) + type = BOOL_TYPE; + if (!ISINTEGER(type)) { + uerror("illegal field type"); + type = INT; + } + + al = talign(type, NULL); + sz = tsize(type, NULL, NULL); + + if (w > sz) { + uerror("field too big"); + w = sz; + } + + if (w == 0) { /* align only */ + SETOFF(rpole->rstr, al); + if (p != NULL) + uerror("zero size field"); + return(0); + } + + if (rpole->rstr%al + w > sz) + SETOFF(rpole->rstr, al); + if (p == NULL) { + rpole->rstr += w; /* we know it will fit */ + return(0); + } + + /* establish the field */ + + p->soffset = rpole->rstr; + rpole->rstr += w; + p->stype = otype; + fldty(p); + return(0); +} + +/* + * Check if this symbol should be a common or must be handled in data seg. + */ +static void +commchk(struct symtab *sp) +{ + if ((sp->sflags & STLS) +#ifdef GCC_COMPAT + || attr_find(sp->sap, GCC_ATYP_SECTION) +#endif + ) { + /* TLS handled in data segment */ + if (sp->sclass == EXTERN) + sp->sclass = EXTDEF; + beginit(sp); + endinit(1); + } else { + symdirec(sp); + defzero(sp); + } +} + +/* + * handle unitialized declarations assumed to be not functions: + * int a; + * extern int a; + * static int a; + */ +void +nidcl(NODE *p, int class) +{ + struct symtab *sp; + int commflag = 0; + + /* compute class */ + if (class == SNULL) { + if (blevel > 1) + class = AUTO; + else if (blevel != 0 || rpole) + cerror( "nidcl error" ); + else /* blevel = 0 */ + commflag = 1, class = EXTERN; + } + + defid(p, class); + + sp = p->n_sp; + /* check if forward decl */ + if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET) + return; + + if (sp->sflags & SASG) + return; /* already initialized */ + + switch (class) { + case EXTDEF: + /* simulate initialization by 0 */ + simpleinit(p->n_sp, bcon(0)); + break; + case EXTERN: + if (commflag) + lcommadd(p->n_sp); + else + extdec(p->n_sp); + break; + case STATIC: + if (blevel == 0) + lcommadd(p->n_sp); + else + commchk(p->n_sp); + break; + } +} + +struct lcd { + SLIST_ENTRY(lcd) next; + struct symtab *sp; +}; + +static SLIST_HEAD(, lcd) lhead = { NULL, &lhead.q_forw}; + +/* + * Add a local common statement to the printout list. + */ +void +lcommadd(struct symtab *sp) +{ + struct lcd *lc, *lcp; + + lcp = NULL; + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp == sp) + return; /* already exists */ + if (lc->sp == NULL && lcp == NULL) + lcp = lc; + } + if (lcp == NULL) { + lc = permalloc(sizeof(struct lcd)); + lc->sp = sp; + SLIST_INSERT_LAST(&lhead, lc, next); + } else + lcp->sp = sp; +} + +/* + * Delete a local common statement. + */ +void +lcommdel(struct symtab *sp) +{ + struct lcd *lc; + + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp == sp) { + lc->sp = NULL; + return; + } + } +} + +/* + * Print out the remaining common statements. + */ +void +lcommprint(void) +{ + struct lcd *lc; + + SLIST_FOREACH(lc, &lhead, next) { + if (lc->sp != NULL) + commchk(lc->sp); + } +} + +/* + * Merge given types to a single node. + * Any type can end up here. + * p is the old node, q is the old (if any). + * CLASS is AUTO, EXTERN, REGISTER, STATIC or TYPEDEF. + * QUALIFIER is VOL or CON + * TYPE is CHAR, SHORT, INT, LONG, SIGNED, UNSIGNED, VOID, BOOL, FLOAT, + * DOUBLE, STRTY, UNIONTY. + */ +struct typctx { + int class, qual, sig, uns, cmplx, imag, err; + TWORD type; + NODE *saved; + struct attr *pre, *post; +}; + +static void +typwalk(NODE *p, void *arg) +{ + struct typctx *tc = arg; + +#define cmop(x,y) block(CM, x, y, INT, 0, 0) + switch (p->n_op) { + case ATTRIB: +#ifdef GCC_COMPAT + if (tc->saved && (tc->saved->n_qual & 1)) { + tc->post = attr_add(tc->post,gcc_attr_parse(p->n_left)); + } else { + tc->pre = attr_add(tc->pre, gcc_attr_parse(p->n_left)); + } + p->n_left = bcon(0); /* For tfree() */ +#endif + break; + case CLASS: + if (tc->class) + tc->err = 1; /* max 1 class */ + tc->class = p->n_type; + break; + + case QUALIFIER: +#if 0 + if (p->n_qual == 0) + uerror("invalid use of 'restrict'"); +#endif + tc->qual |= p->n_qual >> TSHIFT; + break; + + case TYPE: + if (p->n_sp != NULL || ISSOU(p->n_type)) { + /* typedef, enum or struct/union */ + if (tc->saved || tc->type) + tc->err = 1; +#ifdef GCC_COMPAT + if (ISSOU(p->n_type) && p->n_left) { + if (tc->post) + cerror("typwalk"); + tc->post = gcc_attr_parse(p->n_left); + } +#endif + tc->saved = ccopy(p); + break; + } + + switch (p->n_type) { + case BOOL: + case CHAR: + case FLOAT: + case VOID: + if (tc->type) + tc->err = 1; + tc->type = p->n_type; + break; + case DOUBLE: + if (tc->type == 0) + tc->type = DOUBLE; + else if (tc->type == LONG) + tc->type = LDOUBLE; + else + tc->err = 1; + break; + case SHORT: + if (tc->type == 0 || tc->type == INT) + tc->type = SHORT; + else + tc->err = 1; + break; + case INT: + if (tc->type == SHORT || tc->type == LONG || + tc->type == LONGLONG) + break; + else if (tc->type == 0) + tc->type = INT; + else + tc->err = 1; + break; + case LONG: + if (tc->type == 0) + tc->type = LONG; + else if (tc->type == INT) + break; + else if (tc->type == LONG) + tc->type = LONGLONG; + else if (tc->type == DOUBLE) + tc->type = LDOUBLE; + else + tc->err = 1; + break; + case SIGNED: + if (tc->sig || tc->uns) + tc->err = 1; + tc->sig = 1; + break; + case UNSIGNED: + if (tc->sig || tc->uns) + tc->err = 1; + tc->uns = 1; + break; + case COMPLEX: + tc->cmplx = 1; + break; + case IMAG: + tc->imag = 1; + break; + default: + cerror("typwalk"); + } + } + +} + +NODE * +typenode(NODE *p) +{ + struct symtab *sp; + struct typctx tc; + NODE *q; + char *c; + + memset(&tc, 0, sizeof(struct typctx)); + + flist(p, typwalk, &tc); + tfree(p); + + if (tc.err) + goto bad; + + if (tc.cmplx || tc.imag) { + if (tc.type == 0) + tc.type = DOUBLE; + if ((tc.cmplx && tc.imag) || tc.sig || tc.uns || + !ISFTY(tc.type)) + goto bad; + if (tc.cmplx) { + c = tc.type == DOUBLE ? "0d" : + tc.type == FLOAT ? "0f" : "0l"; + sp = lookup(addname(c), 0); + tc.type = STRTY; + tc.saved = mkty(tc.type, sp->sdf, sp->sap); + tc.saved->n_sp = sp; + tc.type = 0; + } else + tc.type += (FIMAG-FLOAT); + } + + if (tc.saved && tc.type) + goto bad; + if (tc.sig || tc.uns) { + if (tc.type == 0) + tc.type = tc.sig ? INT : UNSIGNED; + if (tc.type > ULONGLONG) + goto bad; + if (tc.uns) + tc.type = ENUNSIGN(tc.type); + } + + if (xuchar && tc.type == CHAR && tc.sig == 0) + tc.type = UCHAR; + +#ifdef GCC_COMPAT + if (pragma_packed) { + q = bdty(CALL, bdty(NAME, "packed"), bcon(pragma_packed)); + tc.post = attr_add(tc.post, gcc_attr_parse(q)); + } + if (pragma_aligned) { + /* Deal with relevant pragmas */ + q = bdty(CALL, bdty(NAME, "aligned"), bcon(pragma_aligned)); + tc.post = attr_add(tc.post, gcc_attr_parse(q)); + } + pragma_aligned = pragma_packed = 0; +#endif + if ((q = tc.saved) == NULL) { + TWORD t; + if ((t = BTYPE(tc.type)) > LDOUBLE && t != VOID && + t != BOOL && !(t >= FIMAG && t <= LIMAG)) + cerror("typenode2 t %x", tc.type); + if (t == UNDEF) { + t = INT; + MODTYPE(tc.type, INT); + } + q = mkty(tc.type, 0, 0); + } + q->n_ap = attr_add(q->n_ap, tc.post); + q->n_qual = tc.qual; + glval(q) = tc.class; +#ifdef GCC_COMPAT + if (tc.post) { + /* Can only occur for TYPEDEF, STRUCT or UNION */ + if (tc.saved == NULL) + cerror("typenode"); + if (tc.saved->n_sp) /* trailer attributes for structs */ + tc.saved->n_sp->sap = q->n_ap; + } + if (tc.pre) + q->n_ap = attr_add(q->n_ap, tc.pre); + gcc_tcattrfix(q); +#endif + return q; + +bad: uerror("illegal type combination"); + return mkty(INT, 0, 0); +} + +struct tylnk { + struct tylnk *next; + union dimfun df; +}; + +/* + * Retrieve all CM-separated argument types, sizes and dimensions and + * put them in an array. + * XXX - can only check first type level, side effects? + */ +static union arglist * +arglist(NODE *n) +{ + union arglist *al; + NODE *w = n, **ap; + int num, cnt, i, j, k; + TWORD ty; + +#ifdef PCC_DEBUG + if (pdebug) { + printf("arglist %p\n", n); + fwalk(n, eprint, 0); + } +#endif + /* First: how much to allocate */ + for (num = cnt = 0, w = n; w->n_op == CM; w = w->n_left) { + cnt++; /* Number of levels */ + num++; /* At least one per step */ + if (w->n_right->n_op == ELLIPSIS) + continue; + ty = w->n_right->n_type; + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) + num++; + while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + num++; + } + cnt++; + ty = w->n_type; + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) + num++; + while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + num++; + num += 2; /* TEND + last arg type */ + + /* Second: Create list to work on */ + ap = tmpalloc(sizeof(NODE *) * cnt); + al = permalloc(sizeof(union arglist) * num); + arglistcnt += num; + + for (w = n, i = 0; w->n_op == CM; w = w->n_left) + ap[i++] = w->n_right; + ap[i] = w; + + /* Third: Create actual arg list */ + for (k = 0, j = i; j >= 0; j--) { + if (ap[j]->n_op == ELLIPSIS) { + al[k++].type = TELLIPSIS; + ap[j]->n_op = ICON; /* for tfree() */ + continue; + } + /* Convert arrays to pointers */ + if (ISARY(ap[j]->n_type)) { + ap[j]->n_type += (PTR-ARY); + ap[j]->n_df++; + } + /* Convert (silently) functions to pointers */ + if (ISFTN(ap[j]->n_type)) + ap[j]->n_type = INCREF(ap[j]->n_type); + ty = ap[j]->n_type; +#ifdef GCC_COMPAT + if (ty == UNIONTY && + attr_find(ap[j]->n_ap, GCC_ATYP_TRANSP_UNION)){ + /* transparent unions must have compatible types + * shortcut here: if pointers, set void *, + * otherwise btype. + */ + struct symtab *sp = strmemb(ap[j]->n_ap); + ty = ISPTR(sp->stype) ? PTR|VOID : sp->stype; + } +#endif + al[k++].type = ty; + if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) + al[k++].sap = ap[j]->n_ap; + while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) + ty = DECREF(ty); + if (ty > BTMASK) + al[k++].df = ap[j]->n_df; + } + al[k++].type = TNULL; + if (k > num) + cerror("arglist: k%d > num%d", k, num); + tfree(n); +#ifdef PCC_DEBUG + if (pdebug) + alprint(al, 0); +#endif + return al; +} + +static void +tylkadd(union dimfun dim, struct tylnk **tylkp, int *ntdim) +{ + (*tylkp)->next = tmpalloc(sizeof(struct tylnk)); + *tylkp = (*tylkp)->next; + (*tylkp)->next = NULL; + (*tylkp)->df = dim; + (*ntdim)++; +} + +/* + * build a type, and stash away dimensions, + * from a parse tree of the declaration + * the type is build top down, the dimensions bottom up + */ +static void +tyreduce(NODE *p, struct tylnk **tylkp, int *ntdim) +{ + union dimfun dim; + NODE *r = NULL; + int o; + TWORD t, q; + + o = p->n_op; + if (o == NAME) { + p->n_qual = DECQAL(p->n_qual); + return; + } + + t = INCREF(p->n_type); + q = p->n_qual; + switch (o) { + case CALL: + t += (FTN-PTR); + dim.dfun = arglist(p->n_right); + break; + case UCALL: + t += (FTN-PTR); + dim.dfun = NULL; + break; + case LB: + t += (ARY-PTR); + if (p->n_right->n_op != ICON) { + r = p->n_right; + o = RB; + } else { + dim.ddim = (int)glval(p->n_right); + nfree(p->n_right); +#ifdef notdef + /* XXX - check dimensions at usage time */ + if (dim.ddim == NOOFFSET && p->n_left->n_op == LB) + uerror("null dimension"); +#endif + } + break; + } + + p->n_left->n_type = t; + p->n_left->n_qual = INCQAL(q) | p->n_left->n_qual; + tyreduce(p->n_left, tylkp, ntdim); + + if (o == LB || o == UCALL || o == CALL) + tylkadd(dim, tylkp, ntdim); + if (o == RB) { + dim.ddim = -1; + tylkadd(dim, tylkp, ntdim); + arrstk[arrstkp++] = r; + } + + p->n_sp = p->n_left->n_sp; + p->n_type = p->n_left->n_type; + p->n_qual = p->n_left->n_qual; +} + +/* + * merge type typ with identifier idp. + * idp is returned as a NAME node with correct types, + * typ is untouched since multiple declarations uses it. + * typ has type attributes, idp can never carry such attributes + * so on return just a pointer to the typ attributes is returned. + */ +NODE * +tymerge(NODE *typ, NODE *idp) +{ + TWORD t; + NODE *p; + union dimfun *j; + struct tylnk *base, tylnk, *tylkp; + struct attr *bap; + int ntdim, i; + +#ifdef PCC_DEBUG + if (ddebug > 2) { + printf("tymerge(%p,%p)\n", typ, idp); + fwalk(typ, eprint, 0); + fwalk(idp, eprint, 0); + } +#endif + + if (typ->n_op != TYPE) + cerror("tymerge: arg 1"); + + bap = typ->n_ap; + + idp->n_type = typ->n_type; + idp->n_qual |= typ->n_qual; + + tylkp = &tylnk; + tylkp->next = NULL; + ntdim = 0; + + tyreduce(idp, &tylkp, &ntdim); + + for (t = typ->n_type, j = typ->n_df; t&TMASK; t = DECREF(t)) + if (ISARY(t) || ISFTN(t)) + tylkadd(*j++, &tylkp, &ntdim); + + if (ntdim) { + union dimfun *a = permalloc(sizeof(union dimfun) * ntdim); + dimfuncnt += ntdim; + for (i = 0, base = tylnk.next; base; base = base->next, i++) + a[i] = base->df; + idp->n_df = a; + } else + idp->n_df = NULL; + + /* now idp is a single node: fix up type */ + if ((t = ctype(idp->n_type)) != idp->n_type) + idp->n_type = t; + + if (idp->n_op != NAME) { + for (p = idp->n_left; p->n_op != NAME; p = p->n_left) + nfree(p); + nfree(p); + idp->n_op = NAME; + } + idp->n_ap = bap; + + return(idp); +} + +static NODE * +argcast(NODE *p, TWORD t, union dimfun *d, struct attr *ap) +{ + NODE *u, *r = talloc(); + + r->n_op = NAME; + r->n_type = t; + r->n_qual = 0; /* XXX */ + r->n_df = d; + r->n_ap = ap; + + u = buildtree(CAST, r, p); + nfree(u->n_left); + r = u->n_right; + nfree(u); + return r; +} + +#ifdef PCC_DEBUG +/* + * Print a prototype. + */ +static void +alprint(union arglist *al, int in) +{ + TWORD t; + int i = 0, j; + + for (; al->type != TNULL; al++) { + for (j = in; j > 0; j--) + printf(" "); + printf("arg %d: ", i++); + t = al->type; + tprint(t, 0); + while (t > BTMASK) { + if (ISARY(t)) { + al++; + printf(" dim %d ", al->df->ddim); + } else if (ISFTN(t)) { + al++; + alprint(al->df->dfun, in+1); + } + t = DECREF(t); + } + if (ISSOU(t)) { + al++; + printf(" (size %d align %d)", (int)tsize(t, 0, al->sap), + (int)talign(t, al->sap)); + } + printf("\n"); + } + if (in == 0) + printf("end arglist\n"); +} +#endif +int +suemeq(struct attr *s1, struct attr *s2) +{ + + return (strmemb(s1) == strmemb(s2)); +} + +/* + * Sanity-check old-style args. + */ +static NODE * +oldarg(NODE *p) +{ + if (p->n_op == TYPE) + uerror("type is not an argument"); + if (p->n_type == FLOAT) + return cast(p, DOUBLE, p->n_qual); + return p; +} + +/* + * Do prototype checking and add conversions before calling a function. + * Argument f is function and a is a CM-separated list of arguments. + * Returns a merged node (via buildtree() of function and arguments. + */ +NODE * +doacall(struct symtab *sp, NODE *f, NODE *a, int hidden) +{ + NODE *w, *r; + union arglist *al; + struct ap { + struct ap *next; + NODE *node; + } *at, *apole = NULL; + int argidx/* , hasarray = 0*/; + TWORD type, arrt; + +#ifdef PCC_DEBUG + if (ddebug) { + printf("doacall.\n"); + fwalk(f, eprint, 0); + if (a) + fwalk(a, eprint, 0); + } +#endif + + /* First let MD code do something */ + calldec(f, a); +/* XXX XXX hack */ + if ((f->n_op == CALL) && + f->n_left->n_op == ADDROF && + f->n_left->n_left->n_op == NAME && + (f->n_left->n_left->n_type & 0x7e0) == 0x4c0) + goto build; +/* XXX XXX hack */ + + /* Check for undefined or late defined enums */ + if (BTYPE(f->n_type) == ENUMTY) { + /* not-yet check if declared enum */ + struct symtab *sq = strmemb(f->n_ap); + if (sq->stype != ENUMTY) + MODTYPE(f->n_type, sq->stype); + if (BTYPE(f->n_type) == ENUMTY) + uerror("enum %s not declared", sq->sname); + } + + /* + * Do some basic checks. + */ + if (f->n_df == NULL || (al = f->n_df[0].dfun) == NULL) { + /* + * Handle non-prototype declarations. + */ + if (f->n_op == NAME && f->n_sp != NULL) { + if (strncmp(f->n_sp->sname, "__builtin", 9) != 0) + warner(Wmissing_prototypes, f->n_sp->sname); + } else + warner(Wmissing_prototypes, ""); + + /* floats must be cast to double */ + if (a == NULL) + goto build; + if (a->n_op != CM) { + a = oldarg(a); + } else { + for (w = a; w->n_left->n_op == CM; w = w->n_left) + w->n_right = oldarg(w->n_right); + w->n_left = oldarg(w->n_left); + w->n_right = oldarg(w->n_right); + } + goto build; + } + if (al->type == VOID) { + if (a != NULL) + uerror("function takes no arguments"); + goto build; /* void function */ + } else { + if (a == NULL) { + uerror("function needs arguments"); + goto build; + } + } +#ifdef PCC_DEBUG + if (pdebug) { + printf("arglist for %s\n", + f->n_sp != NULL ? f->n_sp->sname : "function pointer"); + alprint(al, 0); + } +#endif + + /* + * Create a list of pointers to the nodes given as arg. + */ + for (w = a; w->n_op == CM; w = w->n_left) { + at = tmpalloc(sizeof(struct ap)); + at->node = w->n_right; + at->next = apole; + apole = at; + } + if (hidden == 0) { + at = tmpalloc(sizeof(struct ap)); + at->node = w; + at->next = apole; + apole = at; + } + + /* + * Do the typechecking by walking up the list. + */ + argidx = 1; + while (al->type != TNULL) { + if (al->type == TELLIPSIS) { + /* convert the rest of float to double */ + for (; apole; apole = apole->next) { + if (apole->node->n_type != FLOAT) + continue; + MKTY(apole->node, DOUBLE, 0, 0); + } + goto build; + } + if (apole == NULL) { + uerror("too few arguments to function"); + goto build; + } +/* al = prototyp, apole = argument till ftn */ +/* type = argumentets typ, arrt = prototypens typ */ + type = apole->node->n_type; + arrt = al->type; +#if 0 + if ((hasarray = ISARY(arrt))) + arrt += (PTR-ARY); +#endif + /* Taking addresses of arrays are meaningless in expressions */ + /* but people tend to do that and also use in prototypes */ + /* this is mostly a problem with typedefs */ + if (ISARY(type)) { + if (ISPTR(arrt) && ISARY(DECREF(arrt))) + type = INCREF(type); + else + type += (PTR-ARY); + } else if (ISPTR(type) && !ISARY(DECREF(type)) && + ISPTR(arrt) && ISARY(DECREF(arrt))) { + type += (ARY-PTR); + type = INCREF(type); + } + + /* Check structs */ + if (type <= BTMASK && arrt <= BTMASK) { + if (type != arrt) { + if (ISSOU(BTYPE(type)) || ISSOU(BTYPE(arrt))) { +incomp: uerror("incompatible types for arg %d", + argidx); + } else { + MKTY(apole->node, arrt, 0, 0) + } +#ifndef NO_COMPLEX + } else if (type == STRTY && + attr_find(apole->node->n_ap, ATTR_COMPLEX) && + attr_find(al[1].sap, ATTR_COMPLEX)) { + /* Both are complex */ + if (strmemb(apole->node->n_ap)->stype != + strmemb(al[1].sap)->stype) { + /* must convert to correct type */ + w = talloc(); + *w = *apole->node; + w = mkcmplx(w, + strmemb(al[1].sap)->stype); + *apole->node = *w; + nfree(w); + } + goto out; +#endif + } else if (ISSOU(BTYPE(type))) { + if (!suemeq(apole->node->n_ap, al[1].sap)) + goto incomp; + } + goto out; + } + + /* XXX should (recusively) check return type and arg list of + func ptr arg XXX */ + if (ISFTN(DECREF(arrt)) && ISFTN(type)) + type = INCREF(type); + + /* Hereafter its only pointers (or arrays) left */ + /* Check for struct/union intermixing with other types */ + if (((type <= BTMASK) && ISSOU(BTYPE(type))) || + ((arrt <= BTMASK) && ISSOU(BTYPE(arrt)))) + goto incomp; + + /* Check for struct/union compatibility */ + if (type == arrt) { + if (ISSOU(BTYPE(type))) { + if (suemeq(apole->node->n_ap, al[1].sap)) + goto out; + } else + goto out; + } + if (BTYPE(arrt) == VOID && type > BTMASK) + goto skip; /* void *f = some pointer */ + if (arrt > BTMASK && BTYPE(type) == VOID) + goto skip; /* some *f = void pointer */ + if (apole->node->n_op == ICON && glval(apole->node) == 0) + goto skip; /* Anything assigned a zero */ + + if ((type & ~BTMASK) == (arrt & ~BTMASK)) { + /* do not complain for pointers with signedness */ + if ((DEUNSIGN(BTYPE(type)) == DEUNSIGN(BTYPE(arrt))) && + (BTYPE(type) != BTYPE(arrt))) { + warner(Wpointer_sign); + goto skip; + } + } + + werror("implicit conversion of argument %d due to prototype", + argidx); + +skip: if (ISSOU(BTYPE(arrt))) { + MKTY(apole->node, arrt, 0, al[1].sap) + } else { + MKTY(apole->node, arrt, 0, 0) + } + +out: al++; + if (ISSOU(BTYPE(arrt))) + al++; +#if 0 + while (arrt > BTMASK && !ISFTN(arrt)) + arrt = DECREF(arrt); + if (ISFTN(arrt) || hasarray) + al++; +#else + while (arrt > BTMASK) { + if (ISARY(arrt) || ISFTN(arrt)) { + al++; + break; + } + arrt = DECREF(arrt); + } +#endif + apole = apole->next; + argidx++; + } + if (apole != NULL) + uerror("too many arguments to function"); + +build: if (sp != NULL && (sp->sflags & SINLINE) && (w = inlinetree(sp, f, a))) + return w; + return buildtree(a == NIL ? UCALL : CALL, f, a); +} + +static int +chk2(TWORD type, union dimfun *dsym, union dimfun *ddef) +{ + while (type > BTMASK) { + switch (type & TMASK) { + case ARY: + /* may be declared without dimension */ + if (dsym->ddim == NOOFFSET) + dsym->ddim = ddef->ddim; + if (dsym->ddim < 0 && ddef->ddim < 0) + ; /* dynamic arrays as arguments */ + else if (ddef->ddim > 0 && dsym->ddim != ddef->ddim) + return 1; + dsym++, ddef++; + break; + case FTN: + /* old-style function headers with function pointers + * will most likely not have a prototype. + * This is not considered an error. */ + if (ddef->dfun == NULL) { +#ifdef notyet + werror("declaration not a prototype"); +#endif + } else if (chkftn(dsym->dfun, ddef->dfun)) + return 1; + dsym++, ddef++; + break; + } + type = DECREF(type); + } + return 0; +} + +/* + * Compare two function argument lists to see if they match. + */ +int +chkftn(union arglist *usym, union arglist *udef) +{ + TWORD t2; + int ty, tyn; + + if (usym == NULL) + return 0; + if (cftnsp != NULL && udef == NULL && usym->type == VOID) + return 0; /* foo() { function with foo(void); prototype */ + if (udef == NULL && usym->type != TNULL) + return 1; + while (usym->type != TNULL) { + if (usym->type == udef->type) + goto done; + /* + * If an old-style declaration, then all types smaller than + * int are given as int parameters. + */ + if (intcompare) { + ty = BTYPE(usym->type); + tyn = BTYPE(udef->type); + if (ty == tyn || ty != INT) + return 1; + if (tyn == CHAR || tyn == UCHAR || + tyn == SHORT || tyn == USHORT) + goto done; + return 1; + } else + return 1; + +done: ty = BTYPE(usym->type); + t2 = usym->type; + if (ISSOU(ty)) { + usym++, udef++; + if (suemeq(usym->sap, udef->sap) == 0) + return 1; + } + + while (!ISFTN(t2) && !ISARY(t2) && t2 > BTMASK) + t2 = DECREF(t2); + if (t2 > BTMASK) { + usym++, udef++; + if (chk2(t2, usym->df, udef->df)) + return 1; + } + usym++, udef++; + } + if (usym->type != udef->type) + return 1; + return 0; +} + +void +fixtype(NODE *p, int class) +{ + unsigned int t, type; + int mod1, mod2; + /* fix up the types, and check for legality */ + + /* forward declared enums */ + if (BTYPE(p->n_sp->stype) == ENUMTY) { + MODTYPE(p->n_sp->stype, strmemb(p->n_sp->sap)->stype); + } + + if( (type = p->n_type) == UNDEF ) return; + if ((mod2 = (type&TMASK))) { + t = DECREF(type); + while( mod1=mod2, mod2 = (t&TMASK) ){ + if( mod1 == ARY && mod2 == FTN ){ + uerror( "array of functions is illegal" ); + type = 0; + } + else if( mod1 == FTN && ( mod2 == ARY || mod2 == FTN ) ){ + uerror( "function returns illegal type" ); + type = 0; + } + t = DECREF(t); + } + } + + /* detect function arguments, watching out for structure declarations */ + if (rpole && ISFTN(type)) { + uerror("function illegal in structure or union"); + type = INCREF(type); + } + p->n_type = type; +} + +/* + * give undefined version of class + */ +int +uclass(int class) +{ + if (class == SNULL) + return(EXTERN); + else if (class == STATIC) + return(USTATIC); + else + return(class); +} + +int +fixclass(int class, TWORD type) +{ + extern int fun_inline; + + /* first, fix null class */ + if (class == SNULL) { + if (fun_inline && ISFTN(type)) + return SNULL; + if (rpole) + cerror("field8"); + else if (blevel == 0) + class = EXTDEF; + else + class = AUTO; + } + + /* now, do general checking */ + + if( ISFTN( type ) ){ + switch( class ) { + default: + uerror( "function has illegal storage class" ); + case AUTO: + class = EXTERN; + case EXTERN: + case EXTDEF: + case TYPEDEF: + case STATIC: + case USTATIC: + ; + } + } + + if (class & FIELD) { + cerror("field3"); + } + + switch (class) { + + case MOS: + case MOU: + cerror("field4"); + + case REGISTER: + if (blevel == 0) + uerror("illegal register declaration"); + if (blevel == 1) + return(PARAM); + else + return(AUTO); + + case AUTO: + if( blevel < 2 ) uerror( "illegal ULABEL class" ); + return( class ); + + case EXTERN: + case STATIC: + case EXTDEF: + case TYPEDEF: + case USTATIC: + case PARAM: + return( class ); + + default: + cerror( "illegal class: %d", class ); + /* NOTREACHED */ + + } + return 0; /* XXX */ +} + +/* + * Generates a goto statement; sets up label number etc. + */ +void +gotolabel(char *name) +{ + struct symtab *s = lookup(name, SLBLNAME); + + if (s->soffset == 0) + s->soffset = -getlab(); + branch(s->soffset < 0 ? -s->soffset : s->soffset); +} + +/* + * Sets a label for gotos. + */ +void +deflabel(char *name, NODE *p) +{ + struct symtab *s = lookup(name, SLBLNAME); + +#ifdef GCC_COMPAT + s->sap = gcc_attr_parse(p); +#endif + if (s->soffset > 0) + uerror("label '%s' redefined", name); + if (s->soffset == 0) + s->soffset = getlab(); + if (s->soffset < 0) + s->soffset = -s->soffset; + plabel( s->soffset); +} + +struct symtab * +getsymtab(char *name, int flags) +{ + struct symtab *s; + + if (flags & STEMP) { + s = tmpalloc(sizeof(struct symtab)); + } else { + s = permalloc(sizeof(struct symtab)); + symtabcnt++; + } + s->sname = name; + s->soname = NULL; + s->sup = s->sdown = s->snext = NULL; + s->stype = UNDEF; + s->squal = 0; + s->sclass = SNULL; + s->sflags = (short)(flags & SMASK); + s->soffset = 0; + s->slevel = (char)blevel; + s->sdf = NULL; + s->sap = NULL; + return s; +} + +int +fldchk(int sz) +{ + if (rpole->rsou != STNAME && rpole->rsou != UNAME) + uerror("field outside of structure"); + if (sz < 0 || sz >= FIELD) { + uerror("illegal field size"); + return 1; + } + return 0; +} + +#ifdef PCC_DEBUG +static char * +ccnames[] = { /* names of storage classes */ + "SNULL", + "AUTO", + "EXTERN", + "STATIC", + "REGISTER", + "EXTDEF", + "LABEL", + "ULABEL", + "MOS", + "PARAM", + "STNAME", + "MOU", + "UNAME", + "TYPEDEF", + "FORTRAN", + "ENAME", + "MOE", + "UFORTRAN", + "USTATIC", + "?????", + "?????", + "CLNAME", + "NSPACE", + }; + +char * +scnames(int c) +{ + /* return the name for storage class c */ + static char buf[12]; + if( c&FIELD ){ + snprintf( buf, sizeof(buf), "FIELD[%d]", c&FLDSIZ ); + return( buf ); + } + return( ccnames[c] ); + } +#endif + +#ifdef os_openbsd +static char *stack_chk_fail = "__stack_smash_handler"; +static char *stack_chk_guard = "__guard"; +#else +static char *stack_chk_fail = "__stack_chk_fail"; +static char *stack_chk_guard = "__stack_chk_guard"; +#endif +static char *stack_chk_canary = "__stack_chk_canary"; + +void +sspinit(void) +{ + NODE *p; + + p = block(NAME, NIL, NIL, FTN+VOID, 0, 0); + p->n_sp = lookup(stack_chk_fail, SNORMAL); + defid(p, EXTERN); + nfree(p); + + p = block(NAME, NIL, NIL, INT, 0, 0); + p->n_sp = lookup(stack_chk_guard, SNORMAL); + defid(p, EXTERN); + nfree(p); +} + +void +sspstart(void) +{ + NODE *p, *q; + + q = block(NAME, NIL, NIL, INT, 0, 0); + q->n_sp = lookup(stack_chk_guard, SNORMAL); + q = clocal(q); + + p = block(REG, NIL, NIL, INT, 0, 0); + glval(p) = 0; + p->n_rval = FPREG; + q = block(ER, p, q, INT, 0, 0); + q = clocal(q); + + p = block(NAME, NIL, NIL, INT, 0, 0); + p->n_qual = VOL >> TSHIFT; + p->n_sp = lookup(stack_chk_canary, SNORMAL); + defid(p, AUTO); + p = clocal(p); + ecomp(buildtree(ASSIGN, p, q)); +} + +void +sspend(void) +{ + NODE *p, *q; + TWORD t; + int lab; + + if (retlab != NOLAB) { + plabel(retlab); + retlab = getlab(); + } + + t = DECREF(cftnsp->stype); + if (t == BOOL) + t = BOOL_TYPE; + + p = block(NAME, NIL, NIL, INT, 0, 0); + p->n_sp = lookup(stack_chk_canary, SNORMAL); + p = clocal(p); + + q = block(REG, NIL, NIL, INT, 0, 0); + glval(q) = 0; + q->n_rval = FPREG; + q = block(ER, p, q, INT, 0, 0); + + p = block(NAME, NIL, NIL, INT, 0, 0); + p->n_sp = lookup(stack_chk_guard, SNORMAL); + p = clocal(p); + + lab = getlab(); + cbranch(buildtree(EQ, p, q), bcon(lab)); + + p = block(NAME, NIL, NIL, FTN+VOID, 0, 0); + p->n_sp = lookup(stack_chk_fail, SNORMAL); + p = clocal(p); + + q = eve(bdty(STRING, cftnsp->sname, 0)); + ecomp(buildtree(CALL, p, q)); + + plabel(lab); +} + +/* + * Allocate on the permanent heap for inlines, otherwise temporary heap. + */ +void * +blkalloc(int size) +{ + return isinlining || blevel < 2 ? permalloc(size) : tmpalloc(size); +} + +/* + * Allocate on the permanent heap for inlines, otherwise temporary heap. + */ +void * +inlalloc(int size) +{ + return isinlining ? permalloc(size) : tmpalloc(size); +} + +/* + * Fetch pointer to first member in a struct list. + */ +struct symtab * +strmemb(struct attr *ap) +{ + + if ((ap = attr_find(ap, ATTR_STRUCT)) == NULL) + cerror("strmemb"); + return ap->amlist; +} + +#ifndef NO_COMPLEX + +static char *real, *imag; +static struct symtab *cxsp[3]; +/* + * As complex numbers internally are handled as structs, create + * these by hand-crafting them. + */ +void +complinit(void) +{ + struct attr *ap; + struct rstack *rp; + NODE *p, *q; + char *n[] = { "0f", "0d", "0l" }; + int i, d_debug; + + d_debug = ddebug; + ddebug = 0; + real = addname("__real"); + imag = addname("__imag"); + p = block(NAME, NIL, NIL, FLOAT, 0, 0); + for (i = 0; i < 3; i++) { + p->n_type = FLOAT+i; + rpole = rp = bstruct(NULL, STNAME, NULL); + soumemb(p, real, 0); + soumemb(p, imag, 0); + q = dclstruct(rp); + cxsp[i] = q->n_sp = lookup(addname(n[i]), 0); + defid(q, TYPEDEF); + ap = attr_new(ATTR_COMPLEX, 0); + q->n_sp->sap = attr_add(q->n_sp->sap, ap); + nfree(q); + } + nfree(p); + ddebug = d_debug; +} + +/* + * Return the highest real floating point type. + * Known that at least one type is complex or imaginary. + */ +static TWORD +maxtyp(NODE *l, NODE *r) +{ + TWORD tl, tr, t; + + tl = ANYCX(l) ? strmemb(l->n_ap)->stype : l->n_type; + tr = ANYCX(r) ? strmemb(r->n_ap)->stype : r->n_type; + if (ISITY(tl)) + tl -= (FIMAG - FLOAT); + if (ISITY(tr)) + tr -= (FIMAG - FLOAT); + t = tl > tr ? tl : tr; + if (!ISFTY(t)) + cerror("maxtyp"); + return t; +} + +/* + * Fetch space on stack for complex struct. + */ +static NODE * +cxstore(TWORD t) +{ + struct symtab s; + + s = *cxsp[t - FLOAT]; + s.sclass = AUTO; + s.soffset = NOOFFSET; + oalloc(&s, &autooff); + return nametree(&s); +} + +#define comop(x,y) buildtree(COMOP, x, y) + +static NODE * +mkcmplx(NODE *p, TWORD dt) +{ + NODE *q, *r, *i, *t; + + if (!ANYCX(p)) { + /* Not complex, convert to complex on stack */ + q = cxstore(dt); + if (ISITY(p->n_type)) { + p->n_type = p->n_type - FIMAG + FLOAT; + r = bcon(0); + i = p; + } else { + r = p; + i = bcon(0); + } + p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), r); + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), i)); + p = comop(p, q); + } else { + if (strmemb(p->n_ap)->stype != dt) { + q = cxstore(dt); + p = buildtree(ADDROF, p, NIL); + t = tempnode(0, p->n_type, p->n_df, p->n_ap); + p = buildtree(ASSIGN, ccopy(t), p); + p = comop(p, buildtree(ASSIGN, + structref(ccopy(q), DOT, real), + structref(ccopy(t), STREF, real))); + p = comop(p, buildtree(ASSIGN, + structref(ccopy(q), DOT, imag), + structref(t, STREF, imag))); + p = comop(p, q); + } + } + return p; +} + +static NODE * +cxasg(NODE *l, NODE *r) +{ + TWORD tl, tr; + + tl = strattr(l->n_ap) ? strmemb(l->n_ap)->stype : 0; + tr = strattr(r->n_ap) ? strmemb(r->n_ap)->stype : 0; + + if (ANYCX(l) && ANYCX(r) && tl != tr) { + /* different types in structs */ + r = mkcmplx(r, tl); + } else if (!ANYCX(l)) + r = structref(r, DOT, ISITY(l->n_type) ? imag : real); + else if (!ANYCX(r)) + r = mkcmplx(r, tl); + return buildtree(ASSIGN, l, r); +} + +/* + * Fixup complex operations. + * At least one operand is complex. + */ +NODE * +cxop(int op, NODE *l, NODE *r) +{ + TWORD mxtyp; + NODE *p, *q; + NODE *ltemp, *rtemp; + NODE *real_l, *imag_l; + NODE *real_r, *imag_r; + + if (op == ASSIGN) + return cxasg(l, r); + + mxtyp = maxtyp(l, r); + l = mkcmplx(l, mxtyp); + r = mkcmplx(r, mxtyp); + + + /* put a pointer to left and right elements in a TEMP */ + l = buildtree(ADDROF, l, NIL); + ltemp = tempnode(0, l->n_type, l->n_df, l->n_ap); + l = buildtree(ASSIGN, ccopy(ltemp), l); + + r = buildtree(ADDROF, r, NIL); + rtemp = tempnode(0, r->n_type, r->n_df, r->n_ap); + r = buildtree(ASSIGN, ccopy(rtemp), r); + + p = comop(l, r); + + /* create the four trees needed for calculation */ + real_l = structref(ccopy(ltemp), STREF, real); + real_r = structref(ccopy(rtemp), STREF, real); + imag_l = structref(ltemp, STREF, imag); + imag_r = structref(rtemp, STREF, imag); + + /* get storage on stack for the result */ + q = cxstore(mxtyp); + + switch (op) { + case NE: + case EQ: + tfree(q); + p = buildtree(op, comop(p, real_l), real_r); + q = buildtree(op, imag_l, imag_r); + p = buildtree(op == EQ ? ANDAND : OROR, p, q); + return p; + + case PLUS: + case MINUS: + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), + buildtree(op, real_l, real_r))); + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), + buildtree(op, imag_l, imag_r))); + break; + + case MUL: + /* Complex mul is "complex" */ + /* (u+iv)*(x+iy)=((u*x)-(v*y))+i(v*x+y*u) */ + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), + buildtree(MINUS, + buildtree(MUL, ccopy(real_r), ccopy(real_l)), + buildtree(MUL, ccopy(imag_r), ccopy(imag_l))))); + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), + buildtree(PLUS, + buildtree(MUL, real_r, imag_l), + buildtree(MUL, imag_r, real_l)))); + break; + + case DIV: + /* Complex div is even more "complex" */ + /* (u+iv)/(x+iy)=(u*x+v*y)/(x*x+y*y)+i((v*x-u*y)/(x*x+y*y)) */ + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), + buildtree(DIV, + buildtree(PLUS, + buildtree(MUL, ccopy(real_r), ccopy(real_l)), + buildtree(MUL, ccopy(imag_r), ccopy(imag_l))), + buildtree(PLUS, + buildtree(MUL, ccopy(real_r), ccopy(real_r)), + buildtree(MUL, ccopy(imag_r), ccopy(imag_r)))))); + p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), + buildtree(DIV, + buildtree(MINUS, + buildtree(MUL, ccopy(imag_l), ccopy(real_r)), + buildtree(MUL, ccopy(real_l), ccopy(imag_r))), + buildtree(PLUS, + buildtree(MUL, ccopy(real_r), ccopy(real_r)), + buildtree(MUL, ccopy(imag_r), ccopy(imag_r)))))); + tfree(real_r); + tfree(real_l); + tfree(imag_r); + tfree(imag_l); + break; + default: + uerror("illegal operator %s", copst(op)); + } + return comop(p, q); +} + +/* + * Fixup imaginary operations. + * At least one operand is imaginary, none is complex. + */ +NODE * +imop(int op, NODE *l, NODE *r) +{ + NODE *p, *q; + TWORD mxtyp; + int li, ri; + + li = ri = 0; + if (ISITY(l->n_type)) + li = 1, l->n_type = l->n_type - (FIMAG-FLOAT); + if (ISITY(r->n_type)) + ri = 1, r->n_type = r->n_type - (FIMAG-FLOAT); + + mxtyp = maxtyp(l, r); + switch (op) { + case ASSIGN: + /* if both are imag, store value, otherwise store 0.0 */ + if (!(li && ri)) { + tfree(r); + r = bcon(0); + } + p = buildtree(ASSIGN, l, r); + p->n_type += (FIMAG-FLOAT); + break; + + case PLUS: + if (li && ri) { + p = buildtree(PLUS, l, r); + p->n_type += (FIMAG-FLOAT); + } else { + /* If one is imaginary and one is real, make complex */ + if (li) + q = l, l = r, r = q; /* switch */ + q = cxstore(mxtyp); + p = buildtree(ASSIGN, + structref(ccopy(q), DOT, real), l); + p = comop(p, buildtree(ASSIGN, + structref(ccopy(q), DOT, imag), r)); + p = comop(p, q); + } + break; + + case MINUS: + if (li && ri) { + p = buildtree(MINUS, l, r); + p->n_type += (FIMAG-FLOAT); + } else if (li) { + q = cxstore(mxtyp); + p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), + buildtree(UMINUS, r, NIL)); + p = comop(p, buildtree(ASSIGN, + structref(ccopy(q), DOT, imag), l)); + p = comop(p, q); + } else /* if (ri) */ { + q = cxstore(mxtyp); + p = buildtree(ASSIGN, + structref(ccopy(q), DOT, real), l); + p = comop(p, buildtree(ASSIGN, + structref(ccopy(q), DOT, imag), + buildtree(UMINUS, r, NIL))); + p = comop(p, q); + } + break; + + case MUL: + p = buildtree(MUL, l, r); + if (li && ri) + p = buildtree(UMINUS, p, NIL); + if (li ^ ri) + p->n_type += (FIMAG-FLOAT); + break; + + case DIV: + p = buildtree(DIV, l, r); + if (ri && !li) + p = buildtree(UMINUS, p, NIL); + if (li ^ ri) + p->n_type += (FIMAG-FLOAT); + break; + default: + cerror("imop"); + p = NULL; + } + return p; +} + +NODE * +cxelem(int op, NODE *p) +{ + + if (ANYCX(p)) { + p = structref(p, DOT, op == XREAL ? real : imag); + } else if (op == XIMAG) { + /* XXX sanitycheck? */ + tfree(p); + p = bcon(0); + } + return p; +} + +NODE * +cxconj(NODE *p) +{ + NODE *q, *r; + + /* XXX side effects? */ + q = cxstore(strmemb(p->n_ap)->stype); + r = buildtree(ASSIGN, structref(ccopy(q), DOT, real), + structref(ccopy(p), DOT, real)); + r = comop(r, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), + buildtree(UMINUS, structref(p, DOT, imag), NIL))); + return comop(r, q); +} + +/* + * Prepare for return. + * There may be implicit casts to other types. + */ +NODE * +cxret(NODE *p, NODE *q) +{ +//printf("cxret\n"); +//fwalk(p, eprint, 0); + if (ANYCX(q)) { /* Return complex type */ + p = mkcmplx(p, strmemb(q->n_ap)->stype); + } else if (ISFTY(q->n_type) || ISITY(q->n_type)) { /* real or imag */ + p = structref(p, DOT, ISFTY(q->n_type) ? real : imag); + if (p->n_type != q->n_type) + p = cast(p, q->n_type, 0); + } else + cerror("cxred failing type"); + return p; +} +#endif diff --git a/lang/pcc/pcc/cc/cxxcom/scan.l b/lang/pcc/pcc/cc/cxxcom/scan.l new file mode 100644 index 000000000..f6ddd47c9 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/scan.l @@ -0,0 +1,839 @@ +%{ +/* $Id: scan.l,v 1.7 2016/03/05 15:31:25 ragge Exp $ */ + +/* + * Copyright (c) 2002 Anders Magnusson. All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ +%} + + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +P [Pp][+-]?{D}+ +FS (f|F|l|L)?i? +IS (u|U|l|L)* +UL ({L}|\\u{H}{H}{H}{H}|\\U{H}{H}{H}{H}{H}{H}{H}{H}) + +%{ +#include +#include +#include +#include +#include + +#include "pass1.h" +#include "cgram.h" + +static NODE *cvtdig(int radix); +static NODE *charcon(void); +static NODE *wcharcon(void); +static void control(int); +static void pragma(void); +int notype, parbal, inattr, parlvl, nodinit, inoso; +static int resw(TWORD, int); +static int namechk(void); + +#define CPP_IDENT 2 +#define CPP_LINE 3 +#define CPP_HASH 4 + +#ifdef STABS +#define STABS_LINE(x) if (gflag && cftnsp) stabs_line(x) +#else +#define STABS_LINE(x) +#endif +#if defined(FLEX_SCANNER) && YY_FLEX_SUBMINOR_VERSION == 31 +/* Hack to avoid unnecessary warnings */ +FILE *yyget_in (void); +FILE *yyget_out (void); +int yyget_leng (void); +char *yyget_text (void); +void yyset_in (FILE *); +void yyset_out (FILE *); +int yyget_debug (void); +void yyset_debug (int); +int yylex_destroy (void); +extern int yyget_lineno (void); +extern void yyset_lineno (int); +#endif + +%} + +%% + +"__func__" { + if (cftnsp == NULL) + uerror("__func__ outside function"); + yylval.strp = cftnsp->sname; /* XXX - not C99 */ + return(C_STRING); + } +"asm" { return(C_ASM); } +"auto" { return resw(AUTO, C_CLASS); } +"_Bool" { return resw(BOOL, C_TYPE); } +"break" { return(C_BREAK); } +"case" { return(C_CASE); } +"char" { return resw(CHAR, C_TYPE); } +"class" { yylval.intval = CLNAME; notype=1; return(C_STRUCT); } +"_Complex" { return resw(COMPLEX, C_TYPE); } +"const" { return resw(CON, C_QUALIFIER); } +"const_cast" { yylval.intval = CONST_CAST; return(CXX_CASTS); } +"continue" { return(C_CONTINUE); } +"default" { return(C_DEFAULT); } +"delete" { return(CXX_DELETE); } +"do" { return(C_DO); } +"double" { return resw(DOUBLE, C_TYPE); } +"dynamic_cast" { yylval.intval = DYN_CAST; return(CXX_CASTS); } +"else" { return(C_ELSE); } +"enum" { notype=1; return(C_ENUM); } +"extern" { return resw(EXTERN, C_CLASS); } +"float" { return resw(FLOAT, C_TYPE); } +"for" { return(C_FOR); } +"goto" { notype=1; return(C_GOTO); } +"if" { return(C_IF); } +"_Imaginary" { return resw(IMAG, C_TYPE); } +"inline" { return(C_FUNSPEC); } +"int" { return resw(INT, C_TYPE); } +"long" { return resw(LONG, C_TYPE); } +"namespace" { return(CXX_NAMESPACE); } +"new" { notype = 0; return(CXX_NEW); } +"register" { return resw(REGISTER, C_CLASS); } +"reinterpret_cast" { yylval.intval = REINT_CAST; return(CXX_CASTS); } +"restrict" { ; /* just ignore */ } +"return" { return(C_RETURN); } +"short" { return resw(SHORT, C_TYPE); } +"signed" { return resw(SIGNED, C_TYPE); } +"sizeof" { return(C_SIZEOF); } +"static" { return resw(STATIC, C_CLASS); } +"static_cast" { yylval.intval = STATIC_CAST; return(CXX_CASTS); } +"struct" { yylval.intval = STNAME; notype=1; return(C_STRUCT); } +"switch" { return(C_SWITCH); } +"template" { return(CXX_TEMPLATE); } +"typedef" { return resw(TYPEDEF, C_CLASS); } +"typename" { return(CXX_TYPENAME); } +"union" { yylval.intval = UNAME; notype=1; return(C_STRUCT); } +"unsigned" { return resw(UNSIGNED, C_TYPE); } +"using" { return(CXX_USING); } +"void" { return resw(VOID, C_TYPE); } +"volatile" { return resw(VOL, C_QUALIFIER); } +"while" { return(C_WHILE); } + +{UL}({UL}|{D})* { return namechk(); } +0[xX]{H}+{IS}? { yylval.nodep = cvtdig(16); return(C_ICON); } +0{D}+{IS}? { yylval.nodep = cvtdig(8); return(C_ICON); } +{D}+{IS}? { yylval.nodep = cvtdig(10); return(C_ICON); } +L'(\\.|[^\\'])*' { yylval.nodep = wcharcon(); return(C_ICON); } +'(\\.|[^\\'])*' { yylval.nodep = charcon(); return(C_ICON); } + +{D}+{E}{FS}? { yylval.nodep = floatcon(yytext); return(C_FCON); } +{D}*"."{D}+({E})?{FS}? { yylval.nodep = floatcon(yytext); return(C_FCON); } +{D}+"."{D}*({E})?{FS}? { yylval.nodep = floatcon(yytext); return(C_FCON); } +0[xX]{H}*"."{H}+{P}{FS}? { yylval.nodep = fhexcon(yytext); return(C_FCON); } +0[xX]{H}+"."{P}{FS}? { yylval.nodep = fhexcon(yytext); return(C_FCON); } +0[xX]{H}+{P}{FS}? { yylval.nodep = fhexcon(yytext); return(C_FCON); } + +L?\"(\\.|[^\\"])*\" { yylval.strp = yytext; return C_STRING; } + +"..." { return(C_ELLIPSIS); } +">>=" { yylval.intval = RSEQ; return(C_ASOP); } +"<<=" { yylval.intval = LSEQ; return(C_ASOP); } +"+=" { yylval.intval = PLUSEQ; return(C_ASOP); } +"-=" { yylval.intval = MINUSEQ; return(C_ASOP); } +"*=" { yylval.intval = MULEQ; return(C_ASOP); } +"/=" { yylval.intval = DIVEQ; return(C_ASOP); } +"%=" { yylval.intval = MODEQ; return(C_ASOP); } +"&=" { yylval.intval = ANDEQ; return(C_ASOP); } +"^=" { yylval.intval = EREQ; return(C_ASOP); } +"|=" { yylval.intval = OREQ; return(C_ASOP); } +">>" { yylval.intval = RS; return(C_SHIFTOP); } +"<<" { yylval.intval = LS; return(C_SHIFTOP); } +"++" { yylval.intval = INCR; return(C_INCOP); } +"--" { yylval.intval = DECR; return(C_INCOP); } +"->" { yylval.intval = STREF; return(C_STROP); } +"&&" { yylval.intval = ANDAND; return(C_ANDAND); } +"||" { yylval.intval = OROR; return(C_OROR); } +"<=" { yylval.intval = LE; return(C_RELOP); } +">=" { yylval.intval = GE; return(C_RELOP); } +"==" { yylval.intval = EQ; return(C_EQUOP); } +"!=" { yylval.intval = NE; return(C_EQUOP); } +"::" { return(CXX_DUALCC); } +";" { notype = 0; return(';'); } +("{"|"<%") { notype = 0; return('{'); } +("}"|"%>") { if (rpole) notype = 1; return('}'); } +"," { if (parbal && !inoso) notype = 0; return(','); } +":" { if (doing_init) nodinit--; return(':'); } +"=" { return('='); } +"(" { parbal++; notype = 0; return('('); } +")" { parbal--; + inoso = 0; + if (parbal==0) { notype = 0; } + if (inattr && parlvl == parbal) + inattr = 0; + return(')'); } +("["|"<:") { return('['); } +("]"|":>") { return(']'); } +"." { yylval.intval = DOT; return(C_STROP); } +"&" { return('&'); } +"!" { yylval.intval = NOT; return(C_UNOP); } +"~" { yylval.intval = COMPL; return(C_UNOP); } +"-" { return('-'); } +"+" { return('+'); } +"*" { if (parbal && notype == 0) notype = 1; return('*'); } +"/" { yylval.intval = DIV; return(C_DIVOP); } +"%" { yylval.intval = MOD; return(C_DIVOP); } +"<" { yylval.intval = LT; return(C_RELOP); } +">" { yylval.intval = GT; return(C_RELOP); } +"^" { return('^'); } +"|" { return('|'); } +"?" { if (doing_init) nodinit++; return('?'); } +^#pragma[ \t].* { pragma(); } +^#ident[ \t].* { control(CPP_IDENT); } +^#line[ \t].* { control(CPP_LINE); } +^#.* { control(CPP_HASH); } + +[ \t\v\f] { } +"\n" { ++lineno; STABS_LINE(lineno); } +. { /* ignore bad characters */ } + +%% + +int lineno, issyshdr; +char *ftitle = ""; + +static int +namechk(void) +{ + struct symtab *s; + int i; + + yylval.strp = addname(yytext); + + while ((i = input()) == ' ' || i == '\t') + ; + if (i == ':') { + if ((i = input()) == ':') + return CXX_MORENM; + unput(i); + if (doing_init && nodinit == 0) + return(GCC_DESIG); + i = ':'; + } + unput(i); + +#ifdef GCC_COMPAT + if ((i = gcc_keyword(yylval.strp, &yylval.nodep)) > 0) + return i; +#endif + + if (notype) + return(C_NAME); + s = lookup(yylval.strp, SNOCREAT); + return s && s->sclass == TYPEDEF ? notype=1, C_TYPENAME : C_NAME; +} + +int +yywrap(void) +{ + if (0) unput(0); /* quiet gcc */ + return(1); +} + +int +resw(TWORD t, int rv) +{ + if (inattr) { + yylval.strp = addname(yytext); + return C_NAME; + } + + switch (rv) { + case C_CLASS: + yylval.nodep = block(CLASS, NIL, NIL, t, 0, 0); + return rv; + + case C_QUALIFIER: + yylval.nodep = block(QUALIFIER, NIL, NIL, 0, 0, 0); + yylval.nodep->n_qual = t; + return rv; + + case C_TYPE: + yylval.nodep = mkty(t, 0, 0); + notype=1; + return(rv); + + default: + cerror("resw"); + } + return 0; +} + +#ifndef SOFTFLOAT + +static long double +typround(long double dc, char *e, TWORD *tw) +{ + int im = 0; + + *tw = DOUBLE; + for (; *e; e++) { + switch (*e) { + case 'f': + case 'F': + *tw = FLOAT; + dc = (float)dc; + break; + case 'l': + case 'L': + *tw = LDOUBLE; + break; + case 'i': + case 'I': + im = 1; + break; + } + } + if (*tw == DOUBLE) + dc = (double)dc; +#ifndef NO_COMPLEX + if (im) + *tw += (FIMAG-FLOAT); +#endif + return dc; +} + +/* + * XXX floatcon() and fhexcon() should be in support libraries for + * the target floating point. + */ +static NODE * +f2(char *str) +{ + TWORD tw; + NODE *p; + long double dc; + char *eptr; + +#ifdef HAVE_STRTOLD + dc = strtold(str, &eptr); /* XXX - avoid strtod() */ +#else + dc = strtod(str, &eptr); /* XXX - avoid strtod() */ +#endif + dc = typround(dc, eptr, &tw); + p = block(FCON, NIL, NIL, tw, 0, 0); + p->n_dcon = fltallo(); + FCAST(p->n_dcon)->fp = dc; + return p; +} + +NODE * +floatcon(char *s) +{ + return f2(s); +} + +static int +h2n(int ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + return ch - 'A' + 10; + +} + +NODE * +fhexcon(char *c) +{ + TWORD tw; + char *ep; + long double d; + int i, ed; + NODE *p; + + d = 0.0; + ed = 0; + c+= 2; /* skip 0x */ +#define FSET(n) { d *= 2; if (i & n) d += 1.0; } + for (; *c != '.' && *c != 'p' && *c != 'P'; c++) { + i = h2n(*c); + FSET(8); FSET(4); FSET(2); FSET(1); + } + if (*c != '.' && *c != 'p' && *c != 'P') + cerror("fhexcon"); + if (*c == '.') { + c++; + for (; *c != 'p' && *c != 'P'; c++) { + i = h2n(*c); + FSET(8); FSET(4); FSET(2); FSET(1); + ed -= 4; + } + } + if (*c != 'P' && *c != 'p') + cerror("fhexcon2"); + c++; + ed += strtol(c, &ep, 10); + + /* avoid looping in vain. Idea from Fred J. Tydeman */ + if (ed > 32769) ed = 32769; + if (ed < -32769) ed = -32769; + + while (ed > 0) + d *= 2, ed--; + while (ed < 0) + d /= 2, ed++; + d = typround(d, ep, &tw); + p = block(FCON, NIL, NIL, tw, 0, 0); + p->n_dcon = fltallo(); + FCAST(p->n_dcon)->fp = d; + return p; +} +#endif + +unsigned int +esccon(char **sptr) +{ + char *wr = *sptr; + char *owr; + char c; + unsigned int val; + int wsz = 4, esccon_warn = 1; + + switch (*wr++) { + case 'a': val = '\a'; break; + case 'b': val = '\b'; break; + case 'f': val = '\f'; break; + case 'n': val = '\n'; break; + case 'r': val = '\r'; break; + case 't': val = '\t'; break; + case 'v': val = '\v'; break; + case '\"': val = '\"'; break; + case 'x': val = strtoul(wr, &wr, 16); break; + /* ISO/IEC 9099:1999 (E) 6.4.3 */ + case 'U'|(char)0x80: + esccon_warn = 0; + /* FALLTHROUGH */ + case 'U': + wsz = 8; + /* FALLTHROUGH */ + case 'u': + owr = wr; + while (wr < (owr + wsz)) + if (*wr == '\0') + break; + else + ++wr; + if (wr != (owr + wsz)) { + /* incomplete */ + val = strtoul(owr, &wr, 16); + } else { + c = owr[wsz]; + owr[wsz] = '\0'; /* prevent it from reading too much */ + val = strtoul(owr, &wr, 16); + owr[wsz] = c; + } + if (wr != (owr + wsz)) + werror("incomplete universal character name"); + if (wsz == 4) + val &= 0xFFFF; + if (esccon_warn && ((val >= 0xD800 && val <= 0xDFFF) || + (val < 0xA0 && val != 0x24 && val != 0x40 && val != 0x60))) + werror("invalid universal character name %04X", val); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + val = wr[-1] - '0'; + if (*wr >= '0' && *wr <= '7') { + val = (val << 3) + (*wr++ - '0'); + if (*wr >= '0' && *wr <= '7') + val = (val << 3) + (*wr++ - '0'); + } + break; + default: val = wr[-1]; + } + *sptr = wr; + return val; +} + +NODE * +cvtdig(int radix) +{ + NODE *p; + TWORD otype, ntype; + unsigned long long v; + char *ch = yytext; + int n, numl, numu; + + if (radix == 16) + ch += 2; /* Skip 0x */ + + v = 0; + while ((*ch >= '0' && *ch <= '9') || (*ch >= 'a' && *ch <= 'f') || + (*ch >= 'A' && *ch <= 'F')) { + v *= radix; + n = *ch; + n = (n <= '9' ? n - '0' : (n > 'F' ? n - 'a' : n - 'A') + 10); + ch++; + v += n; + } + /* Parse trailing chars */ + ntype = INT; + numl = numu = 0; + for (n = 0; n < 3; n++) { + if (*ch == 0) + break; + if ((*ch == 'l' || *ch == 'L') && numl < 2) + ntype+=2, numl++; + else if ((*ch == 'u' || *ch == 'U') && numu < 1) + ntype = ENUNSIGN(ntype), numu++; + else + break; + ch++; + } + if (*ch) + uerror("constant has too many '%c'", *ch); + + otype = ntype; + switch (ntype) { + case INT: + case LONG: + case LONGLONG: + if (radix == 10) { + if (otype == LONGLONG) + break; + if (v > MAX_LONG) { + ntype = LONGLONG; + if (otype == LONG) + break; + } else if (v > MAX_INT) + ntype = LONG; + } else { + if (v > MAX_LONGLONG) { + ntype = ULONGLONG; + if (otype == LONGLONG) + break; + } else if (v > MAX_ULONG) { + ntype = LONGLONG; + } else if (v > MAX_LONG) { + ntype = ULONG; + if (otype == LONG) + break; + } else if (v > MAX_UNSIGNED) { + ntype = LONG; + } else if (v > MAX_INT) + ntype = UNSIGNED; + } + break; + case UNSIGNED: + case ULONG: + if (v > MAX_ULONG) { + ntype = ULONGLONG; + if (otype == ULONG) + break; + } else if (v > MAX_UNSIGNED) + ntype = ULONG; + break; + } + + ntype = ctype(ntype); + p = xbcon(v, NULL, ntype); + ASGLVAL(p->n_slval, v); + + return p; +} + +/* + * Convert a character constant to an integer. + */ +NODE * +charcon(void) +{ + int lastcon = 0; + int val, i = 0; + char *pp = yytext; + + pp++; /* skip ' */ + while (*pp != '\'') { + if (*pp++ == '\\') { + val = esccon(&pp); + } else + val = pp[-1]; + makecc(val, i); + i++; + } + + if (i == 0) + uerror("empty character constant"); + else if (i > (SZINT/SZCHAR) || (i>1)) + werror("too many characters in character constant"); + return bcon(lastcon); +} + +NODE * +wcharcon(void) +{ + unsigned int lastcon = 0; + unsigned int val, i = 0; + char *pp = yytext; + + pp++; /* skip L */ + pp++; /* skip ' */ + while (*pp != '\'') { + if (*pp++ == '\\') { + val = esccon(&pp); + } else + val = pp[-1]; +#if WCHAR_SIZE == 2 + lastcon = (lastcon << 16) | (val & 0xFFFF); +#else + lastcon = val; +#endif + i++; + } + + if (i == 0) + uerror("empty wide-character constant"); + else if (i > 1) + werror("too many characters in wide-character constant"); + return xbcon(lastcon, NULL, ctype(UNSIGNED)); +} + +void +control(int t) +{ + char *wr = yytext; + char *eptr; + int val; + + wr++; /* Skip initial '#' */ + switch (t) { + case CPP_IDENT: + return; /* Just skip these for now. */ + + case CPP_LINE: + wr += 4; + /* FALLTHROUGH */ + case CPP_HASH: + val = strtol(wr, &eptr, 10); + if (wr == eptr) /* Illegal string */ + goto bad; + wr = eptr; + lineno = val - 1; + while (*wr && *wr != '\"') + wr++; + if (*wr == 0) + return; + if (*wr++ != '\"') + goto bad; + eptr = wr; + while (*wr && *wr != '\"') + wr++; + if (*wr != '\"') + goto bad; + *wr = 0; + ftitle = addstring(eptr); +#ifdef STABS + if (gflag) + stabs_file(ftitle); +#endif + } + return; +bad: + werror("%s: illegal control", yytext); +} + +int pragma_allpacked; +int pragma_packed, pragma_aligned; +char *pragma_renamed; + +static int +pragmas_weak(char *str) +{ + struct symtab *sp; + char *s1, *s2; + + if ((s1 = pragtok(NULL)) == NULL) + return 1; + if ((s2 = pragtok(NULL)) == NULL) { + sp = lookup(addname(s1), SNORMAL); +#ifdef GCC_COMPAT + sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(NAME, "weak"))); +#else + sp->sap = 0; +#endif + } else if (*s2 == '=') { + if ((s2 = pragtok(NULL)) == NULL) + return 1; + sp = lookup(addname(s2), SNORMAL); +#ifdef GCC_COMPAT + sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(CALL, + bdty(NAME, "aliasweak"), bdty(STRING, s1, 0)))); +#else + sp->sap = NULL; +#endif + } else + return 1; + return 0; +} + +char *pragstore; + +/* trivial tokenizer for pragmas */ +#define ps pragstore +char * +pragtok(char *sin) +{ + static char ss[2]; + char *rv; + + if (sin) + ps = sin; + + for (; isspace((int)*ps); ps++) + ; + if (*ps == 0) + return NULL; + for (rv = ps; isalpha((int)*ps) || isdigit((int)*ps) || *ps == '_'; ps++) + ; + ss[0] = *ps; + if (rv == ps) { + rv = ss, ps++; + } else { + *ps = 0; + rv = tmpstrdup(rv); + *ps = ss[0]; + } + return rv; +} + +/* return 1 on error */ +int +eat(int ch) +{ + char *s = pragtok(0); + return (s == 0 || *s != ch); +} + +static int +pragmas_alpack(char *t) +{ + char *s; + int ap; + + ap = (s = pragtok(0)) ? atoi(s) : 1; + if (strcmp(t, "packed") == 0) + pragma_packed = ap; + else + pragma_aligned = ap; + return 0; +} + + +/* + * Packing control. + * still missing push/pop. + */ +static int +pragmas_pack(char *t) +{ + char *s; + + if (eat('(')) + return 1; + s = pragtok(0); + if (*s == ')') + return pragma_allpacked = 0; + + if (*s < '0' || *s > '9') /* no number */ + return 1; + pragma_allpacked = atoi(s); + return eat(')'); +} + +static int +pragmas_renamed(char *t) +{ + char *f = pragtok(0); + + if (f == 0) + return 1; + pragma_renamed = newstring(f, strlen(f)); + return 0; +} + +static int +pragmas_stdc(char *t) +{ + return 0; /* Just ignore */ +} + +struct pragmas { + char *name; + int (*fun)(char *); +} pragmas[] = { + { "pack", pragmas_pack }, + { "packed", pragmas_alpack }, + { "aligned", pragmas_alpack }, + { "rename", pragmas_renamed }, +#ifdef GCC_COMPAT + { "GCC", pragmas_gcc }, +#endif + { "STDC", pragmas_stdc }, + { "weak", pragmas_weak }, + { "ident", NULL }, + { 0 }, +}; + +/* + * got a full pragma line. Split it up here. + */ +static void +pragma(void) +{ + struct pragmas *p; + char *t, *pt; + + if ((t = pragtok(&yytext[7])) != NULL) { + pt = ps; + for (p = pragmas; p->name; p++) { + if (strcmp(t, p->name) == 0) { + if (p->fun && (*p->fun)(t)) + uerror("bad argument to #pragma"); + return; + } + } + ps = pt; + if (mypragma(t)) + return; + } + warner(Wunknown_pragmas, t, ps); +} + +void +cunput(char c) +{ + unput(c); +} diff --git a/lang/pcc/pcc/cc/cxxcom/softfloat.c b/lang/pcc/pcc/cc/cxxcom/softfloat.c new file mode 100644 index 000000000..22ad6daa9 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/softfloat.c @@ -0,0 +1,359 @@ +/* $Id: softfloat.c,v 1.1 2012/01/01 16:20:55 ragge Exp $ */ + +/* + * Copyright (c) 2008 Anders Magnusson. All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +#ifdef SOFTFLOAT + +#include "pass1.h" + + +/* + * Floating point emulation to be used when cross-compiling. + * Currently only supports F- and D-float, used in DEC machines. + * Should be trivial to add other emulations. + * + * XXX - assumes that: + * - long long is (at least) 64 bits + * - int is at least 32 bits. + * - short is 16 bits. + */ + +#ifdef FDFLOAT + +/* + * Useful macros to manipulate the float. + */ +#define DSIGN(w) (((w).fd1 >> 15) & 1) +#define DSIGNSET(w,s) ((w).fd1 = (s << 15) | ((w).fd1 & 077777)) +#define DEXP(w) (((w).fd1 >> 7) & 0377) +#define DEXPSET(w,e) ((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177)) +#define DMANTH(w) ((w).fd1 & 0177) +#define DMANTHSET(w,m) ((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600)) + +typedef unsigned int lword; +typedef unsigned long long dword; + +#define MAXMANT 0x100000000000000LL + +/* + * Returns a zero dfloat. + */ +static SF +nulldf(void) +{ + SF rv; + + rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0; + return rv; +} + +/* + * Convert a (u)longlong to dfloat. + * XXX - fails on too large (> 55 bits) numbers. + */ +SF +soft_cast(CONSZ ll, TWORD t) +{ + int i; + SF rv; + + rv = nulldf(); + if (ll == 0) + return rv; /* fp is zero */ + if (ll < 0) + DSIGNSET(rv,1), ll = -ll; + for (i = 0; ll > 0; i++, ll <<= 1) + ; + DEXPSET(rv, 192-i); + DMANTHSET(rv, ll >> 56); + rv.fd2 = ll >> 40; + rv.fd3 = ll >> 24; + rv.fd4 = ll >> 8; + return rv; +} + +/* + * multiply two dfloat. Use chop, not round. + */ +SF +soft_mul(SF p1, SF p2) +{ + SF rv; + lword a1[2], a2[2], res[4]; + dword sum; + + res[0] = res[1] = res[2] = res[3] = 0; + + /* move mantissa into lwords */ + a1[0] = p1.fd4 | (p1.fd3 << 16); + a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000; + + a2[0] = p2.fd4 | (p2.fd3 << 16); + a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000; + +#define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \ + res[r] = sum; sum >>= 32; + + sum = 0; + MULONE(0, 0, 0); + MULONE(1, 0, 1); + res[2] = sum; + sum = 0; + MULONE(0, 1, 1); + MULONE(1, 1, 2); + res[3] = sum; + + rv.fd1 = 0; + DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2)); + DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128); + if (res[3] & 0x8000) { + res[3] = (res[3] << 8) | (res[2] >> 24); + res[2] = (res[2] << 8) | (res[1] >> 24); + } else { + DEXPSET(rv, DEXP(rv) - 1); + res[3] = (res[3] << 9) | (res[2] >> 23); + res[2] = (res[2] << 9) | (res[1] >> 23); + } + DMANTHSET(rv, res[3] >> 16); + rv.fd2 = res[3]; + rv.fd3 = res[2] >> 16; + rv.fd4 = res[2]; + return rv; +} + +SF +soft_div(SF t, SF n) +{ + SF rv; + dword T, N, K; + int c; + +#define SHL(x,b) ((dword)(x) << b) + T = SHL(1,55) | SHL(DMANTH(t), 48) | + SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4; + N = SHL(1,55) | SHL(DMANTH(n), 48) | + SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4; + + c = T > N; + for (K = 0; (K & 0x80000000000000ULL) == 0; ) { + if (T >= N) { + T -= N; + K |= 1; + } + T <<= 1; + K <<= 1; + } + rv.fd1 = 0; + DSIGNSET(rv, DSIGN(t) ^ DSIGN(n)); + DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c); + DMANTHSET(rv, K >> 48); + rv.fd2 = K >> 32; + rv.fd3 = K >> 16; + rv.fd4 = K; + return rv; +} + +/* + * Negate a float number. Easy. + */ +SF +soft_neg(SF sf) +{ + int sign = DSIGN(sf) == 0; + DSIGNSET(sf, sign); + return sf; +} + +/* + * Return true if fp number is zero. + */ +int +soft_isz(SF sf) +{ + return (DEXP(sf) == 0); +} + +int +soft_cmp_eq(SF x1, SF x2) +{ + cerror("soft_cmp_eq"); + return 0; +} + +int +soft_cmp_ne(SF x1, SF x2) +{ + cerror("soft_cmp_ne"); + return 0; +} + +int +soft_cmp_le(SF x1, SF x2) +{ + cerror("soft_cmp_le"); + return 0; +} + +int +soft_cmp_lt(SF x1, SF x2) +{ + cerror("soft_cmp_lt"); + return 0; +} + +int +soft_cmp_ge(SF x1, SF x2) +{ + cerror("soft_cmp_ge"); + return 0; +} + +int +soft_cmp_gt(SF x1, SF x2) +{ + cerror("soft_cmp_gt"); + return 0; +} + +/* + * Convert a fp number to a CONSZ. + */ +CONSZ +soft_val(SF sf) +{ + CONSZ mant; + int exp = DEXP(sf) - 128; + + mant = SHL(1,55) | SHL(DMANTH(sf), 48) | + SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4; + + while (exp < 0) + mant >>= 1, exp++; + while (exp > 0) + mant <<= 1, exp--; + return mant; +} + +SF +soft_plus(SF x1, SF x2) +{ + cerror("soft_plus"); + return x1; +} + +SF +soft_minus(SF x1, SF x2) +{ + cerror("soft_minus"); + return x1; +} + +/* + * Convert a hex constant to floating point number. + */ +NODE * +fhexcon(char *s) +{ + cerror("fhexcon"); + return NULL; +} + +/* + * Convert a floating-point constant to D-float and store it in a NODE. + */ +NODE * +floatcon(char *s) +{ + NODE *p; + dword mant; + SF fl, flexp, exp5; + int exp, negexp, bexp; + + exp = 0; + mant = 0; +#define ADDTO(sum, val) sum = sum * 10 + val - '0' + for (; *s >= '0' && *s <= '9'; s++) { + if (mant= '0' && *s <= '9'; s++) { + if (mant= '0' && *s <= '9'; s++) + ADDTO(eexp, *s); + if (sign) + eexp = -eexp; + exp = exp + eexp; + } + + negexp = 1; + if (exp<0) { + negexp = -1; + exp = -exp; + } + + + flexp = soft_cast(1, INT); + exp5 = soft_cast(5, INT); + bexp = exp; + fl = soft_cast(mant, INT); + + for (; exp; exp >>= 1) { + if (exp&01) + flexp = soft_mul(flexp, exp5); + exp5 = soft_mul(exp5, exp5); + } + if (negexp<0) + fl = soft_div(fl, flexp); + else + fl = soft_mul(fl, flexp); + + DEXPSET(fl, DEXP(fl) + negexp*bexp); + p = block(FCON, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); /* XXX type */ + p->n_dcon = fl; + return p; +} +#else +#error missing softfloat definition +#endif +#endif diff --git a/lang/pcc/pcc/cc/cxxcom/stabs.c b/lang/pcc/pcc/cc/cxxcom/stabs.c new file mode 100644 index 000000000..fdd63bf61 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/stabs.c @@ -0,0 +1,460 @@ +/* $Id: stabs.c,v 1.3 2012/04/22 21:07:41 plunky Exp $ */ + +/* + * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Simple implementation of the "stabs" debugging format. + * Not complete but at least makes it possible to set breakpoints, + * examine simple variables and do stack traces. + * Based on the stabs documentation that follows gdb. + */ + +#include "pass1.h" + +#ifdef STABS + +#include +#include +#include + +#define STABHASH 256 +#define INTNUM 1 /* internal number of type "int" */ +#undef BIT2BYTE /* from external.h */ +#define BIT2BYTE(x) ((x)/SZCHAR) + +#ifndef STABLBL +#error macdefs.h must define STABLBL +#endif + +/* defines taken from BSD */ +#define N_GSYM 0x20 /* global symbol */ +#define N_FUN 0x24 /* procedure name */ +#define N_LCSYM 0x28 /* bss segment variable */ +#define N_RSYM 0x40 /* register variable */ +#define N_SLINE 0x44 /* text segment line number */ +#define N_SO 0x64 /* main source file name */ +#define N_LSYM 0x80 /* stack variable */ +#define N_SOL 0x84 /* included source file name */ +#define N_PSYM 0xa0 /* parameter variable */ +#define N_LBRAC 0xc0 /* left bracket */ +#define N_RBRAC 0xe0 /* right bracket */ + +/* + * Local type mapping + * Types are defined as a typeword, a dimension pointer (in the case + * of arrays) and struct/union/enum declarations. + * Function prototypes are ignored. + */ +static struct stabtype { + struct stabtype *next; /* linked list */ + TWORD type; /* pcc type number */ + union dimfun *df; /* dimension of arrays */ + struct attr *ap; /* struct/union/enum declarations */ + int num; /* local type number */ +} *stabhash[STABHASH]; +static int ntypes; +static char *curfun; +static int stablbl = 10; +extern int inftn; + +void ptype(char *name, int num, int inhnum, long long min, long long max); +struct stabtype *addtype(TWORD, union dimfun *, struct attr *); +struct stabtype *findtype(TWORD t, union dimfun *df, struct attr *sue); +void printtype(struct symtab *s, char *str, int len); +void cprint(int p2, char *fmt, ...); + +#define MAXPSTR 100 + +extern int isinlining; + +/* + * Output type definitions for the stab debugging format. + * Note that "int" is always internal number 1. + */ +void +stabs_init(void) +{ + struct stabtype *st; + +#define ADDTYPE(y) addtype(y, NULL, 0) + + ptype("int", ADDTYPE(INT)->num, INTNUM, MIN_INT, MAX_INT); + + st = ADDTYPE(CHAR); + ptype("char", st->num, st->num, 0, MAX_CHAR); + ptype("short", ADDTYPE(SHORT)->num, INTNUM, MIN_SHORT, MAX_SHORT); + ptype("long", ADDTYPE(LONG)->num, INTNUM, MIN_LONG, MAX_LONG); + ptype("long long", ADDTYPE(LONGLONG)->num, INTNUM, + MIN_LONGLONG, MAX_LONGLONG); + ptype("unsigned char", ADDTYPE(UCHAR)->num, INTNUM, 0, MAX_UCHAR); + ptype("unsigned short", ADDTYPE(USHORT)->num, INTNUM, 0, MAX_USHORT); + ptype("unsigned int", ADDTYPE(UNSIGNED)->num, INTNUM, 0, MAX_UNSIGNED); + ptype("unsigned long", ADDTYPE(ULONG)->num, INTNUM, 0, MAX_ULONG); + ptype("unsigned long long", ADDTYPE(ULONGLONG)->num, INTNUM, + 0, MAX_ULONGLONG); + + ptype("float", ADDTYPE(FLOAT)->num, INTNUM, 4, 0); + ptype("double", ADDTYPE(DOUBLE)->num, INTNUM, 8, 0); + ptype("long double", ADDTYPE(LDOUBLE)->num, INTNUM, 12, 0); + st = ADDTYPE(VOID); + cprint(0, "\t.stabs \"void:t%d=r%d\",%d,0,0,0\n", + st->num, st->num, N_LSYM); + +} + +/* + * Print a type in stabs format + */ +void +ptype(char *name, int num, int inhnum, long long min, long long max) +{ + cprint(0, "\t.stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0\n", + name, num, inhnum, min, max, N_LSYM); +} + +/* + * Add a new local type to the hash table. + * The search key is the (type, df, sue) triple. + */ +struct stabtype * +addtype(TWORD t, union dimfun *df, struct attr *ap) +{ + struct stabtype *st; + + st = permalloc(sizeof(struct stabtype)); + st->type = t; + st->df = df; + st->ap = ap; + st->num = ++ntypes; + st->next = stabhash[t & (STABHASH-1)]; + stabhash[t & (STABHASH-1)] = st; + return st; +} + +/* + * Search for a given type and return a type pointer (or NULL). + */ +struct stabtype * +findtype(TWORD t, union dimfun *df, struct attr *ap) +{ + struct stabtype *st; + union dimfun *dw, *dx; + TWORD tw; + + st = stabhash[t & (STABHASH-1)]; + for (; st; st = st->next) { + if (t != st->type || ap != st->ap) + continue; + /* Ok, type and sue matches, check dimensions */ + if (st->df == NULL) + return st; /* no arrays, got match */ + dw = st->df; + dx = df; + tw = t; + for (; tw > BTMASK; tw = DECREF(tw)) { + if (ISARY(tw)) { + if (dw->ddim == dx->ddim) + dw++, dx++; + else + break; + } + } + if (tw <= BTMASK) + return st; + } + return NULL; +} + +/* + * Print current line number. + */ +void +stabs_line(int line) +{ + if (inftn == 0) + return; /* ignore */ +#ifdef STAB_LINE_ABSOLUTE + cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", + N_SLINE, line, stablbl, stablbl); +#else + cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", + N_SLINE, line, stablbl, curfun, stablbl); +#endif + stablbl++; +} + +/* + * Start of block. + */ +void +stabs_lbrac(int blklvl) +{ +#ifdef STAB_LINE_ABSOLUTE + cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", + N_LBRAC, blklvl, stablbl, stablbl); +#else + cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", + N_LBRAC, blklvl, stablbl, curfun, stablbl); +#endif + stablbl++; +} + +/* + * End of block. + */ +void +stabs_rbrac(int blklvl) +{ +#ifdef STAB_LINE_ABSOLUTE + cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", + N_RBRAC, blklvl, stablbl, stablbl); +#else + cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", + N_RBRAC, blklvl, stablbl, curfun, stablbl); +#endif + stablbl++; +} + +static char *mainfile; + +/* + * Print current file and set mark. + */ +void +stabs_file(char *fname) +{ + if (mainfile == NULL) + mainfile = fname; /* first call */ + cprint(inftn, "\t.stabs \"%s\",%d,0,0," STABLBL "\n" STABLBL ":\n", + fname, fname == mainfile ? N_SO : N_SOL, stablbl, stablbl); + stablbl++; +} + +/* + * Print end mark + */ +void +stabs_efile(char *fname) +{ + cprint(inftn, "\t.stabs \"\",%d,0,0," STABLBL "\n" STABLBL ":\n", + fname == mainfile ? N_SO : N_SOL, stablbl, stablbl); + stablbl++; +} + +/* + * Print beginning of function. + */ +void +stabs_func(struct symtab *s) +{ + char str[MAXPSTR]; + + if ((curfun = s->soname) == NULL) + curfun = addname(exname(s->sname)); + printtype(s, str, sizeof(str)); + cprint(1, "\t.stabs \"%s:%c%s\",%d,0,%d,%s\n", + curfun, s->sclass == STATIC ? 'f' : 'F', str, + N_FUN, 0, curfun); +} + +/* + * Print a (complex) type. + * Will also create subtypes. + * Printed string is like "20=*21=*1". + */ +void +printtype(struct symtab *s, char *ostr, int len) +{ + struct stabtype *st; + union dimfun *df = s->sdf; + struct attr *ap = s->sap; + TWORD t = s->stype; + int op = 0; + + /* Print out not-yet-found types */ + if (ISFTN(t)) + t = DECREF(t); + st = findtype(t, df, ap); + while (st == NULL && t > BTMASK) { + st = addtype(t, df, ap); + op+=snprintf(ostr+op, len - op, "%d=", st->num); + if (ISFTN(t)) + ostr[op++] = 'f'; + else if (ISPTR(t)) + ostr[op++] = '*'; + else if (ISARY(t)) { + op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1); + } else + cerror("printtype: notype"); + if (ISARY(t)) + df++; + t = DECREF(t); + st = findtype(t, df, ap); + if (op > MAXPSTR-10) + cerror("printtype: too difficult expression"); + } + /* print out basic type. may have to be entered in case of sue */ + snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num); + /* snprintf here null-terminated the string */ +} + +void +stabs_newsym(struct symtab *s) +{ + extern int fun_inline; + char *sname; + char ostr[MAXPSTR]; + OFFSZ suesize, sz; + + if (ISFTN(s->stype)) + return; /* functions are handled separate */ + + if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS || + s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE || + s->sclass == TYPEDEF || (s->sclass & FIELD) || ISSOU(s->stype)) + return; /* XXX - fix structs */ + + if ((sname = s->soname) == NULL) + sname = exname(s->sname); + sz = tsize(s->stype, s->sdf, s->sap); + suesize = BIT2BYTE(sz); + if (suesize > 32767) + suesize = 32767; + else if (suesize < -32768) + suesize = -32768; + + printtype(s, ostr, sizeof(ostr)); + switch (s->sclass) { + case PARAM: + cprint(0, "\t.stabs \"%s:p%s\",%d,0," CONFMT ",%d\n", + sname, ostr, N_PSYM, (CONSZ)suesize, BIT2BYTE(s->soffset)); + break; + + case AUTO: + cprint(0, "\t.stabs \"%s:%s\",%d,0," CONFMT ",%d\n", + sname, ostr, N_LSYM, (CONSZ)suesize, BIT2BYTE(s->soffset)); + break; + + case STATIC: + if (blevel) + cprint(0, "\t.stabs \"%s:V%s\",%d,0," CONFMT "," LABFMT "\n", + sname, ostr, N_LCSYM, (CONSZ)suesize, s->soffset); + else + cprint(0, "\t.stabs \"%s:S%s\",%d,0," CONFMT ",%s\n", + sname, ostr, N_LCSYM, (CONSZ)suesize, sname); + break; + + case EXTERN: + case EXTDEF: + cprint(0, "\t.stabs \"%s:G%s\",%d,0," CONFMT ",0\n", + sname, ostr, N_GSYM, (CONSZ)suesize); + break; + + case REGISTER: + cprint(0, "\t.stabs \"%s:r%s\",%d,0,%d,%d\n", + sname, ostr, N_RSYM, 1, s->soffset); + break; + + case SNULL: + if (fun_inline) + break; + /* FALLTHROUGH */ + default: + cerror("fix stab_newsym; class %d", s->sclass); + } +} + +void +stabs_chgsym(struct symtab *s) +{ +} + +/* + * define a struct. + */ +void +stabs_struct(struct symtab *p, struct attr *ap) +{ +} + +struct stabsv { + SLIST_ENTRY(stabsv) next; + char *str; +} ; +static SLIST_HEAD(, stabsv) stpole = { NULL, &stpole.q_forw }; + +/* + * Global variable debug info is printed out directly. + * For functions and their declarations, both the labels and + * the debug info is put into ASM nodes and follows their statements + * into pass2. + * Due to the possible unsync between pass1 and 2 and where the + * stabs info for text is sent over the following syncing is used: + * curfun == 0 + * print out everything; only data will be. + * curfun != 0 && inftn == 0 + * save in linked list + * curfun != 0 && inftn != 0 + * print linked list first, empty it, then arg. + */ +void +cprint(int p2, char *fmt, ...) +{ +#define CPBSZ 200 + char buf[CPBSZ]; + struct stabsv *w; + va_list ap; + char *str; + + if (isinlining) + return; /* XXX do not save any inline functions currently */ + + va_start(ap, fmt); + if (p2) { + if (vsnprintf(buf, CPBSZ, fmt, ap) >= CPBSZ) + werror("stab symbol line too long, truncating"); + str = tmpstrdup(buf); + if (inftn == 0) { + w = tmpalloc(sizeof(struct stabsv)); + w->str = str; + SLIST_INSERT_LAST(&stpole, w, next); + } else { + if (stpole.q_last != &stpole.q_forw) { + SLIST_FOREACH(w, &stpole, next) { + send_passt(IP_ASM, w->str); + } + SLIST_INIT(&stpole); + } + send_passt(IP_ASM, str); + } + } else + vprintf(fmt, ap); + va_end(ap); +} + +#endif diff --git a/lang/pcc/pcc/cc/cxxcom/symtabs.c b/lang/pcc/pcc/cc/cxxcom/symtabs.c new file mode 100644 index 000000000..4f4adce1a --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/symtabs.c @@ -0,0 +1,469 @@ +/* $Id: symtabs.c,v 1.4 2015/09/15 20:01:10 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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 "pass1.h" + +/* + * These definitions are used in the patricia tree that stores + * the strings. + */ +#define LEFT_IS_LEAF 0x80000000 +#define RIGHT_IS_LEAF 0x40000000 +#define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0) +#define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0) +#define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF)) +#define CHECKBITS 8 + +struct tree { + int bitno; + struct tree *lr[2]; +}; + +static struct tree *firstname; +int nametabs, namestrlen; +static struct tree *firststr; +int strtabs, strstrlen; +static char *symtab_add(char *key, struct tree **, int *, int *); +int lastloc = NOSEG; + +#define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1 +#define getree() permalloc(sizeof(struct tree)) + +char * +addname(char *key) +{ + return symtab_add(key, &firstname, &nametabs, &namestrlen); +} + +char * +addstring(char *key) +{ + return symtab_add(key, &firststr, &strtabs, &strstrlen); +} + +/* + * Add a name to the name stack (if its non-existing), + * return its address. + * This is a simple patricia implementation. + */ +static char * +symtab_add(char *key, struct tree **first, int *tabs, int *stlen) +{ + struct tree *w, *new, *last; + int cix, bit, fbit, svbit, ix, bitno, len; + char *m, *k, *sm; + + /* Count full string length */ + for (k = key, len = 0; *k; k++, len++) + ; + + switch (*tabs) { + case 0: + *first = (struct tree *)newstring(key, len); + *stlen += (len + 1); + (*tabs)++; + return (char *)*first; + + case 1: + m = (char *)*first; + svbit = 0; /* XXX why? */ + break; + + default: + w = *first; + bitno = len * CHECKBITS; + for (;;) { + bit = BITNO(w->bitno); + fbit = bit > bitno ? 0 : P_BIT(key, bit); + svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : + IS_LEFT_LEAF(w->bitno); + w = w->lr[fbit]; + if (svbit) { + m = (char *)w; + break; + } + } + } + + sm = m; + k = key; + + /* Check for correct string and return */ + for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS) + ; + if (*m == 0 && *k == 0) + return sm; + + ix = *m ^ *k; + while ((ix & 1) == 0) + ix >>= 1, cix++; + + /* Create new node */ + new = getree(); + bit = P_BIT(key, cix); + new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + new->lr[bit] = (struct tree *)newstring(key, len); + *stlen += (len + 1); + + if ((*tabs)++ == 1) { + new->lr[!bit] = *first; + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + *first = new; + return (char *)new->lr[bit]; + } + + + w = *first; + last = NULL; + for (;;) { + fbit = w->bitno; + bitno = BITNO(w->bitno); + if (bitno == cix) + cerror("bitno == cix"); + if (bitno > cix) + break; + svbit = P_BIT(key, bitno); + last = w; + w = w->lr[svbit]; + if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) + break; + } + + new->lr[!bit] = w; + if (last == NULL) { + *first = new; + } else { + last->lr[svbit] = new; + last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + } + if (bitno < cix) + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + return (char *)new->lr[bit]; +} + +static struct tree *sympole[NSTYPES]; +static struct symtab *tmpsyms[NSTYPES]; +int numsyms[NSTYPES]; + +/* + * Inserts a symbol into the symbol tree. + * Returns a struct symtab. + */ +struct symtab * +lookup(char *key, int stype) +{ + struct symtab *sym; + struct tree *w, *new, *last; + int cix, bit, fbit, svbit, bitno; + int type, uselvl; + intptr_t ix, match, code = (intptr_t)key; + + type = stype & SMASK; + uselvl = (blevel > 0 && type != SSTRING); + + /* + * The local symbols are kept in a simple linked list. + * Check this list first. + */ + if (blevel > 0) + for (sym = tmpsyms[type]; sym; sym = sym->snext) + if (sym->sname == key) + return sym; + + switch (numsyms[type]) { + case 0: + if (stype & SNOCREAT) + return NULL; + if (uselvl) { + sym = getsymtab(key, stype|STEMP); + sym->snext = tmpsyms[type]; + tmpsyms[type] = sym; + return sym; + } + sympole[type] = (struct tree *)getsymtab(key, stype); + numsyms[type]++; + return (struct symtab *)sympole[type]; + + case 1: + w = (struct tree *)sympole[type]; + svbit = 0; /* XXX why? */ + break; + + default: + w = sympole[type]; + for (;;) { + bit = BITNO(w->bitno); + fbit = (code >> bit) & 1; + svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : + IS_LEFT_LEAF(w->bitno); + w = w->lr[fbit]; + if (svbit) + break; + } + } + + sym = (struct symtab *)w; + match = (intptr_t)sym->sname; + + ix = code ^ match; + if (ix == 0) + return sym; + else if (stype & SNOCREAT) + return NULL; + +#ifdef PCC_DEBUG + if (ddebug) + printf(" adding %s as %s at level %d\n", + key, uselvl ? "temp" : "perm", blevel); +#endif + + /* + * Insert into the linked list, if feasible. + */ + if (uselvl) { + sym = getsymtab(key, stype|STEMP); + sym->snext = tmpsyms[type]; + tmpsyms[type] = sym; + return sym; + } + + /* + * Need a new node. If type is SNORMAL and inside a function + * the node must be allocated as permanent anyway. + * This could be optimized by adding a remove routine, but it + * may be more trouble than it is worth. + */ + if (stype == (STEMP|SNORMAL)) + stype = SNORMAL; + + for (cix = 0; (ix & 1) == 0; ix >>= 1, cix++) + ; + + new = stype & STEMP ? tmpalloc(sizeof(struct tree)) : + permalloc(sizeof(struct tree)); + bit = (code >> cix) & 1; + new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + new->lr[bit] = (struct tree *)getsymtab(key, stype); + if (numsyms[type]++ == 1) { + new->lr[!bit] = sympole[type]; + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + sympole[type] = new; + return (struct symtab *)new->lr[bit]; + } + + + w = sympole[type]; + last = NULL; + for (;;) { + fbit = w->bitno; + bitno = BITNO(w->bitno); + if (bitno == cix) + cerror("bitno == cix"); + if (bitno > cix) + break; + svbit = (code >> bitno) & 1; + last = w; + w = w->lr[svbit]; + if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) + break; + } + + new->lr[!bit] = w; + if (last == NULL) { + sympole[type] = new; + } else { + last->lr[svbit] = new; + last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); + } + if (bitno < cix) + new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); + return (struct symtab *)new->lr[bit]; +} + +void +symclear(int level) +{ + struct symtab *s; + int i; + +#ifdef PCC_DEBUG + if (ddebug) + printf("symclear(%d)\n", level); +#endif + if (level < 1) { + for (i = 0; i < NSTYPES; i++) { + s = tmpsyms[i]; + tmpsyms[i] = 0; + if (i != SLBLNAME) + continue; + while (s != NULL) { + if (s->soffset < 0) + uerror("label '%s' undefined",s->sname); + s = s->snext; + } + } + } else { + for (i = 0; i < NSTYPES; i++) { + if (i == SLBLNAME) + continue; /* function scope */ + while (tmpsyms[i] != NULL && + tmpsyms[i]->slevel > level) { + tmpsyms[i] = tmpsyms[i]->snext; + } + } + } +} + +struct symtab * +hide(struct symtab *sym) +{ + struct symtab *new; + int typ = sym->sflags & SMASK; + + new = getsymtab(sym->sname, typ|STEMP); + new->snext = tmpsyms[typ]; + tmpsyms[typ] = new; + + warner(Wshadow, sym->sname, sym->slevel ? "local" : "global"); + +#ifdef PCC_DEBUG + if (ddebug) + printf("\t%s hidden at level %d (%p -> %p)\n", + sym->sname, blevel, sym, new); +#endif + return new; +} + +/* + * Extract correct segment for the specified symbol and call + * target routines to print it out. + * If symtab entry is specified, output alignment as well. + */ +void +locctr(int seg, struct symtab *sp) +{ +#ifdef GCC_COMPAT + struct attr *ga; +#endif + + if (seg == NOSEG) { + ; + } else if (sp == NULL) { + if (lastloc != seg) + setseg(seg, NULL); +#ifdef GCC_COMPAT + } else if ((ga = attr_find(sp->sap, GCC_ATYP_SECTION)) != NULL) { + setseg(NMSEG, ga->sarg(0)); + seg = NOSEG; +#endif + } else { + if (seg == DATA) { + if (ISCON(cqual(sp->stype, sp->squal))) + seg = RDATA; + else if (sp->sclass == STATIC) + seg = LDATA; + } + if (sp->sflags & STLS) { + if (seg == DATA || seg == LDATA) + seg = TLSDATA; + if (seg == UDATA) seg = TLSUDATA; + } else if (kflag) { + if (seg == DATA) seg = PICDATA; + if (seg == RDATA) seg = PICRDATA; + if (seg == LDATA) seg = PICLDATA; + } + if (lastloc != seg) + setseg(seg, NULL); + } + lastloc = seg; + + /* setup alignment */ +#ifndef ALFTN +#define ALFTN ALINT +#endif + if (sp) { + int al; + + if (ISFTN(sp->stype)) { + al = ALFTN; + } else + al = talign(sp->stype, sp->sap); + defalign(al); + symdirec(sp); + } +} + +#ifndef MYALIGN +void +defalign(int al) +{ +#ifdef HASP2ALIGN +#define P2ALIGN(x) ispow2(x) +#else +#define P2ALIGN(x) (x) +#endif + if (al != ALCHAR) + printf("\t.align %d\n", P2ALIGN(al/ALCHAR)); +} +#endif + +#ifndef MYDIREC +/* + * Directives given as attributes to symbols. + */ +void +symdirec(struct symtab *sp) +{ +#ifdef GCC_COMPAT + struct attr *ga; + char *name; + + if ((name = sp->soname) == NULL) + name = exname(sp->sname); + if ((ga = attr_find(sp->sap, GCC_ATYP_WEAK)) != NULL) + printf("\t.weak %s\n", name); + if ((ga = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) && + strcmp(ga->sarg(0), "default")) + printf("\t.%s %s\n", ga->sarg(0), name); + if ((ga = attr_find(sp->sap, GCC_ATYP_ALIASWEAK))) { + printf("\t.weak %s\n", ga->sarg(0)); + printf("\t.set %s,%s\n", ga->sarg(0), name); + } +#endif +} +#endif + +char * +getexname(struct symtab *sp) +{ + char *s; + if ((s = sp->soname) == NULL) + s = addname(exname(sp->sname)); + return s; +} diff --git a/lang/pcc/pcc/cc/cxxcom/trees.c b/lang/pcc/pcc/cc/cxxcom/trees.c new file mode 100644 index 000000000..886c2c0e2 --- /dev/null +++ b/lang/pcc/pcc/cc/cxxcom/trees.c @@ -0,0 +1,3322 @@ +/* $Id: trees.c,v 1.21 2016/03/05 15:31:25 ragge Exp $ */ +/* + * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). + * All rights reserved. + * + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ +/* + * Some of the changes from 32V include: + * - Understand "void" as type. + * - Handle enums as ints everywhere. + * - Convert some C-specific ops into branches. + */ + +# include "pass1.h" +# include "pass2.h" + +# include +# include + +static void chkpun(NODE *p); +static int opact(NODE *p); +static int moditype(TWORD); +static NODE *strargs(NODE *); +static void rmcops(NODE *p); +static NODE *tymatch(NODE *p); +void putjops(NODE *, void *); +static void p2tree(NODE *); +static struct symtab *findmember(struct symtab *, char *); +int inftn; /* currently between epilog/prolog */ + +static char *tnames[] = { + "undef", + "farg", + "char", + "unsigned char", + "short", + "unsigned short", + "int", + "unsigned int", + "long", + "unsigned long", + "long long", + "unsigned long long", + "float", + "double", + "long double", + "strty", + "unionty", + "enumty", + "moety", + "void", + "signed", /* pass1 */ + "bool", /* pass1 */ + "fimag", /* pass1 */ + "dimag", /* pass1 */ + "limag", /* pass1 */ + "fcomplex", /* pass1 */ + "dcomplex", /* pass1 */ + "lcomplex", /* pass1 */ + "enumty", /* pass1 */ + "?", "?" +}; + +/* some special actions, used in finding the type of nodes */ +# define NCVT 01 +# define PUN 02 +# define TYPL 04 +# define TYPR 010 +# define TYMATCH 040 +# define LVAL 0100 +# define CVTO 0200 +# define CVTL 0400 +# define CVTR 01000 +# define PTMATCH 02000 +# define OTHER 04000 +# define NCVTR 010000 +# define PROML 020000 /* promote left operand */ + +/* node conventions: + + NAME: rval>0 is stab index for external + rval<0 is -inlabel number + lval is offset in bits + ICON: lval has the value + rval has the STAB index, or - label number, + if a name whose address is in the constant + rval = NONAME means no name + REG: rval is reg. identification cookie + + */ + +extern int negrel[]; + +/* Have some defaults for most common targets */ +#ifndef WORD_ADDRESSED +#define offcon(o,t,d,ap) xbcon((o/SZCHAR), NULL, INTPTR) +#define VBLOCK(p,b,t,d,a) buildtree(DIV, p, b) +#define MBLOCK(p,b,t,d,a) buildtree(MUL, p, b) +#else +#define VBLOCK(p,b,t,d,a) block(PVCONV, p, b, t, d, a) +#define MBLOCK(p,b,t,d,a) block(PMCONV, p, b, t, d, a) +#endif + +NODE * +buildtree(int o, NODE *l, NODE *r) +{ + NODE *p, *q; + int actions; + int opty, n; + struct symtab *sp = NULL; /* XXX gcc */ + NODE *lr, *ll; + +#ifdef PCC_DEBUG + if (bdebug) { + printf("buildtree(%s, %p, %p)\n", copst(o), l, r); + if (l) fwalk(l, eprint, 0); + if (r) fwalk(r, eprint, 0); + } +#endif + opty = coptype(o); + + /* check for constants */ + + if (o == ANDAND || o == OROR || o == NOT) { + if (l->n_op == FCON) { + p = bcon(!FLOAT_ISZERO(FCAST(l->n_dcon))); + nfree(l); + l = p; + } + if (o != NOT && r->n_op == FCON) { + p = bcon(!FLOAT_ISZERO(FCAST(r->n_dcon))); + nfree(r); + r = p; + } + } + + if( opty == UTYPE && l->n_op == ICON ){ + + switch( o ){ + + case NOT: + case UMINUS: + case COMPL: + if( conval( l, o, l ) ) return(l); + break; + } + } else if (o == NOT && l->n_op == FCON) { + l = clocal(block(SCONV, l, NIL, INT, 0, 0)); + } else if( o == UMINUS && l->n_op == FCON ){ + FLOAT_NEG(FCAST(l->n_dcon)); + return(l); + + } else if( o==QUEST && + (l->n_op==ICON || (l->n_op==NAME && ISARY(l->n_type)))) { + CONSZ c = glval(l); + if (l->n_op==NAME) + c = 1; /* will become constant later */ + nfree(l); + if (c) { + walkf(r->n_right, putjops, 0); + tfree(r->n_right); + l = r->n_left; + } else { + walkf(r->n_left, putjops, 0); + tfree(r->n_left); + l = r->n_right; + } + nfree(r); + return(l); + } else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){ + + switch( o ){ + + case PLUS: + case MINUS: + case MUL: + case DIV: + case MOD: + /* + * Do type propagation for simple types here. + * The constant value is correct anyway. + * Maybe this op shortcut should be removed? + */ + if (l->n_sp == NULL && r->n_sp == NULL && + l->n_type < BTMASK && r->n_type < BTMASK) { + if (l->n_type > r->n_type) + r->n_type = l->n_type; + else + l->n_type = r->n_type; + } + /* FALLTHROUGH */ + case ULT: + case UGT: + case ULE: + case UGE: + case LT: + case GT: + case LE: + case GE: + case EQ: + case NE: + case ANDAND: + case OROR: + case AND: + case OR: + case ER: + case LS: + case RS: + if (!ISPTR(l->n_type) && !ISPTR(r->n_type)) { + if( conval( l, o, r ) ) { + nfree(r); + return(l); + } + } + break; + } + } else if (opty == BITYPE && (l->n_op == FCON || l->n_op == ICON) && + (r->n_op == FCON || r->n_op == ICON) && (o == PLUS || o == MINUS || + o == MUL || o == DIV || (o >= EQ && o <= GT) )) { +#define D(x) ((FLT *)x) +#ifndef CC_DIV_0 + if (o == DIV && + ((r->n_op == ICON && glval(r) == 0) || + (r->n_op == FCON && FLOAT_EQ(D(r->n_dcon), FLOAT_ZERO)))) + goto runtime; /* HW dependent */ +#endif + if (l->n_op == ICON) { + if (!concast(l, r->n_type)) + cerror("fail cast const"); + } else if (r->n_op == ICON) { + if (!concast(r, l->n_type)) + cerror("fail cast const"); + } + + switch(o){ + case PLUS: + case MINUS: + case MUL: + case DIV: + switch (o) { + case PLUS: + FLOAT_PLUS(l, r); + break; + case MINUS: + FLOAT_MINUS(l, r); + break; + case MUL: + FLOAT_MUL(l, r); + break; + case DIV: + FLOAT_DIV(l, r); + break; + } + nfree(r); + return(l); + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: + switch (o) { + case EQ: + n = FLOAT_EQ(D(l->n_dcon), D(r->n_dcon)); + break; + case NE: + n = FLOAT_NE(D(l->n_dcon), D(r->n_dcon)); + break; + case LE: + n = FLOAT_LE(D(l->n_dcon), D(r->n_dcon)); + break; + case LT: + n = FLOAT_LT(D(l->n_dcon), D(r->n_dcon)); + break; + case GE: + n = FLOAT_GE(D(l->n_dcon), D(r->n_dcon)); + break; + case GT: + n = FLOAT_GT(D(l->n_dcon), D(r->n_dcon)); + break; + default: + n = 0; /* XXX flow analysis */ + } + nfree(r); + nfree(l); + return bcon(n); + } + } +#ifndef CC_DIV_0 +runtime: +#endif + /* its real; we must make a new node */ + + p = block(o, l, r, INT, 0, 0); + + actions = opact(p); + + if (actions & PROML) + p->n_left = intprom(p->n_left); + + if (actions & LVAL) { /* check left descendent */ + if (notlval(p->n_left)) { + uerror("lvalue required"); + nfree(p); + return l; +#ifdef notyet + } else { + if ((l->n_type > BTMASK && ISCON(l->n_qual)) || + (l->n_type <= BTMASK && ISCON(l->n_qual << TSHIFT))) + if (blevel > 0) + uerror("lvalue is declared const"); +#endif + } + } + + if( actions & NCVTR ){ + p->n_left = pconvert( p->n_left ); + } + else if( !(actions & NCVT ) ){ + switch( opty ){ + + case BITYPE: + p->n_right = pconvert( p->n_right ); + /* FALLTHROUGH */ + case UTYPE: + p->n_left = pconvert( p->n_left ); + + } + } + + if ((actions&PUN) && (o!=CAST)) + chkpun(p); + + if( actions & (TYPL|TYPR) ){ + + q = (actions&TYPL) ? p->n_left : p->n_right; + + p->n_type = q->n_type; + p->n_qual = q->n_qual; + p->n_df = q->n_df; + p->n_ap = q->n_ap; + } + + if( actions & CVTL ) p = convert( p, CVTL ); + if( actions & CVTR ) p = convert( p, CVTR ); + if( actions & TYMATCH ) p = tymatch(p); + if( actions & PTMATCH ) p = ptmatch(p); + + if( actions & OTHER ){ + struct symtab *sp1; + + l = p->n_left; + r = p->n_right; + + switch(o){ + + case NAME: + cerror("buildtree NAME"); + + case STREF: + /* p->x turned into *(p+offset) */ + /* rhs must be a name; check correctness */ + + /* Find member symbol struct */ + if (l->n_type != PTR+STRTY && l->n_type != PTR+UNIONTY){ + uerror("struct or union required"); + break; + } + + if ((sp1 = strmemb(l->n_ap)) == NULL) { + uerror("undefined struct or union"); + break; + } + + if ((sp = findmember(sp1, r->n_name)) == NULL) { + uerror("member '%s' not declared", r->n_name); + break; + } + + r->n_sp = sp; + p = stref(p); + break; + + case UMUL: + if (l->n_op == ADDROF) { + nfree(p); + p = nfree(l); + } + if( !ISPTR(l->n_type))uerror("illegal indirection"); + p->n_type = DECREF(l->n_type); + p->n_qual = DECREF(l->n_qual); + p->n_df = l->n_df; + p->n_ap = l->n_ap; + break; + + case ADDROF: + switch( l->n_op ){ + + case UMUL: + nfree(p); + p = nfree(l); + /* FALLTHROUGH */ + case TEMP: + case NAME: + p->n_type = INCREF(l->n_type); + p->n_qual = INCQAL(l->n_qual); + p->n_df = l->n_df; + p->n_ap = l->n_ap; + break; + + case COMOP: + nfree(p); + lr = buildtree(ADDROF, l->n_right, NIL); + p = buildtree( COMOP, l->n_left, lr ); + nfree(l); + break; + + case QUEST: + lr = buildtree( ADDROF, l->n_right->n_right, NIL ); + ll = buildtree( ADDROF, l->n_right->n_left, NIL ); + nfree(p); nfree(l->n_right); + p = buildtree( QUEST, l->n_left, buildtree( COLON, ll, lr ) ); + nfree(l); + break; + + default: + uerror("unacceptable operand of &: %d", l->n_op ); + break; + } + break; + + case LS: + case RS: /* must make type size at least int... */ + if (p->n_type == CHAR || p->n_type == SHORT) { + p->n_left = makety(l, INT, 0, 0, 0); + } else if (p->n_type == UCHAR || p->n_type == USHORT) { + p->n_left = makety(l, UNSIGNED, 0, 0, 0); + } + l = p->n_left; + p->n_type = l->n_type; + p->n_qual = l->n_qual; + p->n_df = l->n_df; + p->n_ap = l->n_ap; + + /* FALLTHROUGH */ + case LSEQ: + case RSEQ: /* ...but not for assigned types */ + if(tsize(r->n_type, r->n_df, r->n_ap) > SZINT) + p->n_right = makety(r, INT, 0, 0, 0); + break; + + case RETURN: + case ASSIGN: + case CAST: + /* structure assignment */ + /* take the addresses of the two sides; then make an + * operator using STASG and + * the addresses of left and right */ + + if (strmemb(l->n_ap) != strmemb(r->n_ap)) + uerror("assignment of different structures"); + + r = buildtree(ADDROF, r, NIL); + + l = block(STASG, l, r, r->n_type, r->n_df, r->n_ap); + l = clocal(l); + + if( o == RETURN ){ + nfree(p); + p = l; + break; + } + + p->n_op = UMUL; + p->n_left = l; + p->n_right = NIL; + break; + + case QUEST: /* fixup types of : */ + if (r->n_left->n_type != p->n_type) + r->n_left = makety(r->n_left, p->n_type, + p->n_qual, p->n_df, p->n_ap); + if (r->n_right->n_type != p->n_type) + r->n_right = makety(r->n_right, p->n_type, + p->n_qual, p->n_df, p->n_ap); + break; + + case COLON: + /* structure colon */ + + if (strmemb(l->n_ap) != strmemb(r->n_ap)) + uerror( "type clash in conditional" ); + break; + + case CALL: + p->n_right = r = strargs(p->n_right); + p = funcode(p); + /* FALLTHROUGH */ + case UCALL: + if (!ISPTR(l->n_type)) + uerror("illegal function"); + p->n_type = DECREF(l->n_type); + if (!ISFTN(p->n_type)) + uerror("illegal function"); + p->n_type = DECREF(p->n_type); + p->n_df = l->n_df+1; /* add one for prototypes */ + p->n_ap = l->n_ap; + if (p->n_type == STRTY || p->n_type == UNIONTY) { + /* function returning structure */ + /* make function really return ptr to str., with * */ + + p->n_op += STCALL-CALL; + p->n_type = INCREF(p->n_type); + p = clocal(p); /* before recursing */ + p = buildtree(UMUL, p, NIL); + + } + break; + + default: + cerror( "other code %d", o ); + } + + } + + /* + * Allow (void)0 casts. + * XXX - anything on the right side must be possible to cast. + * XXX - remove void types further on. + */ + if (p->n_op == CAST && p->n_type == VOID && + p->n_right->n_op == ICON) + p->n_right->n_type = VOID; + + if (actions & CVTO) + p = oconvert(p); + p = clocal(p); + +#ifdef PCC_DEBUG + if (bdebug) { + printf("End of buildtree:\n"); + fwalk(p, eprint, 0); + } +#endif + + return(p); + + } + +/* Find a member in a struct or union. May be an unnamed member */ +static struct symtab * +findmember(struct symtab *sp, char *s) +{ + struct symtab *sp2, *sp3; + + for (; sp != NULL; sp = sp->snext) { + if (sp->sname[0] == '*') { + /* unnamed member, recurse down */ + if ((sp2 = findmember(strmemb(sp->sap), s))) { + sp3 = tmpalloc(sizeof (struct symtab)); + *sp3 = *sp2; + sp3->soffset += sp->soffset; + return sp3; + } + } else if (sp->sname == s) + return sp; + } + return NULL; +} + + +/* + * Check if there will be a lost label destination inside of a ?: + * It cannot be reached so just print it out. + */ +void +putjops(NODE *p, void *arg) +{ + if (p->n_op == COMOP && p->n_left->n_op == GOTO) + plabel((int)glval(p->n_left->n_left)+1); +} + +/* + * Build a name node based on a symtab entry. + * broken out from buildtree(). + */ +NODE * +nametree(struct symtab *sp) +{ + NODE *p; + + p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap); + p->n_qual = sp->squal; + p->n_sp = sp; + +#ifndef NO_C_BUILTINS + if (sp->sname[0] == '_' && strncmp(sp->sname, "__builtin_", 10) == 0) + return p; /* do not touch builtins here */ + +#endif + + if (sp->sflags & STNODE) { + /* Generated for optimizer */ + p->n_op = TEMP; + p->n_rval = sp->soffset; + } + +#ifdef GCC_COMPAT + /* Get a label name */ + if (sp->sflags == SLBLNAME) { + p->n_type = VOID; + } +#endif + if (sp->stype == UNDEF) { + uerror("%s undefined", sp->sname); + /* make p look reasonable */ + p->n_type = INT; + p->n_df = NULL; + defid(p, SNULL); + } + if (sp->sclass == MOE) { + p->n_op = ICON; + glval(p) = sp->soffset; + p->n_df = NULL; + p->n_sp = NULL; + } + return clocal(p); +} + +/* + * Cast a node to another type by inserting a cast. + * Just a nicer interface to buildtree. + * Returns the new tree. + */ +NODE * +cast(NODE *p, TWORD t, TWORD u) +{ + NODE *q; + + q = block(NAME, NIL, NIL, t, 0, 0); + q->n_qual = u; + q = buildtree(CAST, q, p); + p = q->n_right; + nfree(q->n_left); + nfree(q); + return p; +} + +/* + * Cast and complain if necessary by not inserining a cast. + */ +NODE * +ccast(NODE *p, TWORD t, TWORD u, union dimfun *df, struct attr *ap) +{ + NODE *q; + + /* let buildtree do typechecking (and casting) */ + q = block(NAME, NIL, NIL, t, df, ap); + p = buildtree(ASSIGN, q, p); + nfree(p->n_left); + q = optim(p->n_right); + nfree(p); + return q; +} + +/* + * Do an actual cast of a constant (if possible). + * Routine assumes 2-complement (is there anything else today?) + * Returns 1 if handled, 0 otherwise. + */ +int +concast(NODE *p, TWORD t) +{ + extern short sztable[]; + CONSZ val; + + if (p->n_op != ICON && p->n_op != FCON) /* only constants */ + return 0; + if (p->n_op == ICON && p->n_sp != NULL) { /* no addresses */ + if (t == BOOL) { + glval(p) = 1, p->n_type = BOOL, p->n_sp = NULL; + return 1; + } + return 0; + } + if ((p->n_type & TMASK) || (t & TMASK)) /* no cast of pointers */ + return 0; + +//printf("concast till %d\n", t); +//fwalk(p, eprint, 0); + +#define TYPMSK(y) ((((1LL << (y-1))-1) << 1) | 1) + if (p->n_op == ICON) { + val = glval(p); + + if (t == BOOL) { + if (val) + glval(p) = 1; + } else if (t <= ULONGLONG) { + glval(p) = val & TYPMSK(sztable[t]); + if (!ISUNSIGNED(t)) { + if (val & (1LL << (sztable[t]-1))) + glval(p) |= ~TYPMSK(sztable[t]); + } + } else if (t <= LDOUBLE) { + p->n_op = FCON; + FLOAT_INT2FP(D(p->n_dcon), val, p->n_type); + } + } else { /* p->n_op == FCON */ + if (t == BOOL) { + p->n_op = ICON; + glval(p) = FLOAT_NE(D(p->n_dcon),FLOAT_ZERO); + p->n_sp = NULL; + } else if (t <= ULONGLONG) { + p->n_op = ICON; + glval(p) = ISUNSIGNED(t) ? /* XXX FIXME */ + ((U_CONSZ)D(p->n_dcon)->fp) : D(p->n_dcon)->fp; + p->n_sp = NULL; + } else { + D(p->n_dcon)->fp = t == FLOAT ? (float)D(p->n_dcon)->fp : + t == DOUBLE ? (double)D(p->n_dcon)->fp : D(p->n_dcon)->fp; + } + } + p->n_type = t; +//fwalk(p, eprint, 0); + return 1; +} + +/* + * Do a conditional branch. + */ +void +cbranch(NODE *p, NODE *q) +{ + p = buildtree(CBRANCH, p, q); + if (p->n_left->n_op == ICON) { + if (glval(p->n_left) != 0) { + branch((int)glval(q)); /* branch always */ + reached = 0; + } + tfree(p); + tfree(q); + return; + } + ecomp(p); +} + +NODE * +strargs(register NODE *p) +{ + /* rewrite structure flavored arguments */ + + if( p->n_op == CM ){ + p->n_left = strargs( p->n_left ); + p->n_right = strargs( p->n_right ); + return( p ); + } + + if( p->n_type == STRTY || p->n_type == UNIONTY ){ + p = block(STARG, p, NIL, p->n_type, p->n_df, p->n_ap); + p->n_left = buildtree( ADDROF, p->n_left, NIL ); + p = clocal(p); + } + return( p ); +} + +/* + * apply the op o to the lval part of p; if binary, rhs is val + */ +int +conval(NODE *p, int o, NODE *q) +{ + TWORD tl = p->n_type, tr = q->n_type, td; + int i, u; + CONSZ val; + U_CONSZ v1, v2; + + val = glval(q); + + /* make both sides same type */ + if (tl < BTMASK && tr < BTMASK) { + td = tl > tr ? tl : tr; + if (td < INT) + td = INT; + u = ISUNSIGNED(td); + if (tl != td) + p = makety(p, td, 0, 0, 0); + if (tr != td) + q = makety(q, td, 0, 0, 0); + } else + u = ISUNSIGNED(tl) || ISUNSIGNED(tr); + if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE); + + if (p->n_sp != NULL && q->n_sp != NULL) + return(0); + if (q->n_sp != NULL && o != PLUS) + return(0); + if (p->n_sp != NULL && o != PLUS && o != MINUS) + return(0); + + v1 = glval(p); + v2 = glval(q); + if (v2 == 0 && (cdope(o) & DIVFLG)) + return 0; /* leave division by zero to runtime */ + switch( o ){ + + case PLUS: + glval(p) += val; + if (p->n_sp == NULL) { + p->n_right = q->n_right; + p->n_type = q->n_type; + } + break; + case MINUS: + glval(p) -= val; + break; + case MUL: + glval(p) *= val; + break; + case DIV: + if (u) { + v1 /= v2; + glval(p) = v1; + } else + glval(p) /= val; + break; + case MOD: + if (u) { + v1 %= v2; + glval(p) = v1; + } else + glval(p) %= val; + break; + case AND: + glval(p) &= val; + break; + case OR: + glval(p) |= val; + break; + case ER: + glval(p) ^= val; + break; + case LS: + i = (int)val; + glval(p) = glval(p) << i; + break; + case RS: + i = (int)val; + if (u) { + v1 = v1 >> i; + glval(p) = v1; + } else + glval(p) = glval(p) >> i; + break; + + case UMINUS: + glval(p) = - glval(p); + break; + case COMPL: + glval(p) = ~glval(p); + break; + case NOT: + glval(p) = !glval(p); + break; + case LT: + glval(p) = glval(p) < val; + break; + case LE: + glval(p) = glval(p) <= val; + break; + case GT: + glval(p) = glval(p) > val; + break; + case GE: + glval(p) = glval(p) >= val; + break; + case ULT: + glval(p) = v1 < v2; + break; + case ULE: + glval(p) = v1 <= v2; + break; + case UGT: + glval(p) = v1 > v2; + break; + case UGE: + glval(p) = v1 >= v2; + break; + case EQ: + glval(p) = glval(p) == val; + break; + case NE: + glval(p) = glval(p) != val; + break; + case ANDAND: + glval(p) = glval(p) && val; + break; + case OROR: + glval(p) = glval(p) || val; + break; + default: + return(0); + } + /* Do the best in making everything type correct after calc */ + if (p->n_sp == NULL && q->n_sp == NULL) + glval(p) = valcast(glval(p), p->n_type); + return(1); + } + +/* + * Ensure that v matches the type t; sign- or zero-extended + * as suitable to CONSZ. + * Only to be used for integer types. + */ +CONSZ +valcast(CONSZ v, TWORD t) +{ + CONSZ r; + int sz; + + if (t < CHAR || t > ULONGLONG) + return v; /* cannot cast */ + + if (t >= LONGLONG) + return v; /* already largest */ + +#define M(x) ((((1ULL << ((x)-1)) - 1) << 1) + 1) +#define NOTM(x) (~M(x)) +#define SBIT(x) (1ULL << ((x)-1)) + + sz = (int)tsize(t, NULL, NULL); + r = v & M(sz); + if (!ISUNSIGNED(t) && (SBIT(sz) & r)) + r = r | NOTM(sz); + return r; +} + +/* + * Checks p for the existence of a pun. This is called when the op of p + * is ASSIGN, RETURN, CAST, COLON, or relational. + * One case is when enumerations are used: this applies only to lint. + * In the other case, one operand is a pointer, the other integer type + * we check that this integer is in fact a constant zero... + * in the case of ASSIGN, any assignment of pointer to integer is illegal + * this falls out, because the LHS is never 0. + * XXX - check for COMOPs in assignment RHS? + */ +void +chkpun(NODE *p) +{ + union dimfun *d1, *d2; + NODE *q; + int t1, t2; + + t1 = p->n_left->n_type; + t2 = p->n_right->n_type; + + switch (p->n_op) { + case RETURN: + /* return of void allowed but nothing else */ + if (t1 == VOID && t2 == VOID) + return; + if (t1 == VOID) { + werror("returning value from void function"); + return; + } + if (t2 == VOID) { + uerror("using void value"); + return; + } + break; + case COLON: + if (t1 == VOID && t2 == VOID) + return; + break; + default: + if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) { + uerror("value of void expression used"); + return; + } + break; + } + + /* allow void pointer assignments in any direction */ + if (BTYPE(t1) == VOID && (t2 & TMASK)) + return; + if (BTYPE(t2) == VOID && (t1 & TMASK)) + return; + + /* boolean have special syntax */ + if (t1 == BOOL) { + if (!ISARY(t2)) /* Anything scalar */ + return; + } + + if (ISPTR(t1) || ISARY(t1)) + q = p->n_right; + else + q = p->n_left; + + if (!ISPTR(q->n_type) && !ISARY(q->n_type)) { + if (q->n_op != ICON || glval(q) != 0) + werror("illegal combination of pointer and integer"); + } else { + if (t1 == t2) { + if (ISSOU(BTYPE(t1)) && + !suemeq(p->n_left->n_ap, p->n_right->n_ap)) + werror("illegal structure pointer combination"); + return; + } + d1 = p->n_left->n_df; + d2 = p->n_right->n_df; + for (;;) { + if (ISARY(t1) || ISPTR(t1)) { + if (!ISARY(t2) && !ISPTR(t2)) + break; + if (ISARY(t1) && ISARY(t2) && d1->ddim != d2->ddim) { + werror("illegal array size combination"); + return; + } + if (ISARY(t1)) + ++d1; + if (ISARY(t2)) + ++d2; + } else if (ISFTN(t1)) { + if (chkftn(d1->dfun, d2->dfun)) { + werror("illegal function " + "pointer combination"); + return; + } + ++d1; + ++d2; + } else + break; + t1 = DECREF(t1); + t2 = DECREF(t2); + } + if (DEUNSIGN(t1) != DEUNSIGN(t2)) + warner(Wpointer_sign); + } +} + +static NODE * +offplus(NODE *p, int off, TWORD t, TWORD q, union dimfun *d, struct attr *ap) { + if (off != 0) { + p = block(PLUS, p, offcon(off, t, d, ap), t, d, ap); + p->n_qual = q; + p = optim(p); + } + + return buildtree(UMUL, p, NIL); +} + +NODE * +stref(NODE *p) +{ + NODE *r; + struct attr *ap, *xap, *yap; + union dimfun *d; + TWORD t, q; + int dsc; + OFFSZ off; + struct symtab *s; + + /* make p->x */ + /* this is also used to reference automatic variables */ + + s = p->n_right->n_sp; + nfree(p->n_right); + r = nfree(p); +#ifdef GCC_COMPAT + xap = attr_find(r->n_ap, GCC_ATYP_PACKED); +#endif + + p = pconvert(r); + + /* make p look like ptr to x */ + + if (!ISPTR(p->n_type)) + p->n_type = PTR+UNIONTY; + + t = INCREF(s->stype); + q = INCQAL(s->squal); + d = s->sdf; + ap = s->sap; +#ifdef GCC_COMPAT + if ((yap = attr_find(ap, GCC_ATYP_PACKED)) != NULL) + xap = yap; + else if (xap != NULL) + ap = attr_add(ap, attr_dup(xap)); +#else + xap = yap = NULL; +#endif + /* xap set if packed struct */ + + p = makety(p, t, q, d, ap); + if (ISFTN(s->stype)) { + /* direct class call */ + p = block(NMLIST, p, nametree(s), INT, 0, 0); + return p; + } + + /* compute the offset to be added */ + + off = s->soffset; + dsc = s->sclass; + + if (dsc & FIELD) { + TWORD ftyp = s->stype; + int fal = talign(ftyp, ap); + off = (off/fal)*fal; + p = offplus(p, off, t, q, d, ap); + p = block(FLD, p, NIL, ftyp, 0, ap); + p->n_qual = q; + p->n_rval = PKFIELD(dsc&FLDSIZ, s->soffset%fal); + } else { + p = offplus(p, off, t, q, d, ap); +#ifndef CAN_UNALIGN + /* if target cannot handle unaligned addresses, fix here */ +#endif + } + + p = clocal(p); + return p; +} + +int +notlval(register NODE *p) +{ + /* return 0 if p an lvalue, 1 otherwise */ + + again: + + switch( p->n_op ){ + + case FLD: + p = p->n_left; + goto again; + + case NAME: + case OREG: + case UMUL: + if( ISARY(p->n_type) || ISFTN(p->n_type) ) return(1); + case TEMP: + case REG: + return(0); + + default: + return(1); + } +} + +/* make a constant node with value i */ +NODE * +bcon(int i) +{ + return xbcon(i, NULL, INT); +} + +NODE * +xbcon(CONSZ val, struct symtab *sp, TWORD type) +{ + NODE *p; + + p = block(ICON, NIL, NIL, type, 0, 0); + glval(p) = val; + p->n_sp = sp; + return clocal(p); +} + +NODE * +bpsize(NODE *p) +{ + int isdyn(struct symtab *sp); + struct symtab s; + NODE *q, *r; + TWORD t; + int sz; + + s.stype = DECREF(p->n_type); + s.sdf = p->n_df; + if (isdyn(&s)) { + q = bcon(1); + for (t = s.stype; t > BTMASK; t = DECREF(t)) { + if (ISPTR(t)) + return buildtree(MUL, q, bcon(SZPOINT(t))); + if (ISARY(t)) { + if (s.sdf->ddim < 0) + r = tempnode(-s.sdf->ddim, INT, 0, 0); + else + r = bcon(s.sdf->ddim/SZCHAR); + q = buildtree(MUL, q, r); + s.sdf++; + } + } + sz = (int)tsize(p->n_type, p->n_df, p->n_ap); + p = buildtree(MUL, q, bcon(sz/SZCHAR)); + } else + p = (offcon(psize(p), p->n_type, p->n_df, p->n_ap)); + return p; +} + +/* + * p is a node of type pointer; psize returns the + * size of the thing pointed to + */ +OFFSZ +psize(NODE *p) +{ + + if (!ISPTR(p->n_type)) { + uerror("pointer required"); + return(SZINT); + } + /* note: no pointers to fields */ + return(tsize(DECREF(p->n_type), p->n_df, p->n_ap)); +} + +/* + * convert an operand of p + * f is either CVTL or CVTR + * operand has type int, and is converted by the size of the other side + * convert is called when an integer is to be added to a pointer, for + * example in arrays or structures. + */ +NODE * +convert(NODE *p, int f) +{ + union dimfun *df; + TWORD ty, ty2; + NODE *q, *r, *s, *rv; + + if (f == CVTL) { + q = p->n_left; + s = p->n_right; + } else { + q = p->n_right; + s = p->n_left; + } + ty2 = ty = DECREF(s->n_type); + while (ISARY(ty)) + ty = DECREF(ty); + + r = offcon(tsize(ty, s->n_df, s->n_ap), s->n_type, s->n_df, s->n_ap); + ty = ty2; + rv = bcon(1); + df = s->n_df; + while (ISARY(ty)) { + rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) : + tempnode(-df->ddim, INT, 0, 0)); + df++; + ty = DECREF(ty); + } + rv = clocal(MBLOCK(rv, r, INT, 0, 0)); + rv = optim(rv); + + r = MBLOCK(q, rv, INT, 0, 0); + r = clocal(r); + /* + * Indexing is only allowed with integer arguments, so insert + * SCONV here if arg is not an integer. + * XXX - complain? + */ + if (r->n_type != INTPTR) + r = clocal(makety(r, INTPTR, 0, 0, 0)); + if (f == CVTL) + p->n_left = r; + else + p->n_right = r; + return(p); +} + +NODE * +pconvert(register NODE *p) +{ + /* if p should be changed into a pointer, do so */ + + if( ISARY( p->n_type) ){ + p->n_type = DECREF( p->n_type ); + ++p->n_df; + return( buildtree( ADDROF, p, NIL ) ); + } + if( ISFTN( p->n_type) ) + return( buildtree( ADDROF, p, NIL ) ); + + return( p ); +} + +NODE * +oconvert(register NODE *p) +{ + /* convert the result itself: used for pointer and unsigned */ + + switch(p->n_op) { + + case LE: + case LT: + case GE: + case GT: + if(ISUNSIGNED(p->n_left->n_type) || + ISUNSIGNED(p->n_right->n_type) || + ISPTR(p->n_left->n_type) || + ISPTR(p->n_right->n_type)) + p->n_op += (ULE-LE); + /* FALLTHROUGH */ + case EQ: + case NE: + return( p ); + + case MINUS: + p->n_type = INTPTR; + p->n_ap = NULL; + return(clocal(VBLOCK(p, bpsize(p->n_left), INT, 0, 0))); + } + + cerror( "illegal oconvert: %d", p->n_op ); + + return(p); +} + +/* + * makes the operands of p agree; they are + * either pointers or integers, by this time + * with MINUS, the sizes must be the same + * with COLON, the types must be the same + */ +NODE * +ptmatch(NODE *p) +{ + struct attr *ap, *ap2; + union dimfun *d, *d2; + TWORD t1, t2, t, q1, q2, q; + int o; + + o = p->n_op; + t = t1 = p->n_left->n_type; + q = q1 = p->n_left->n_qual; + t2 = p->n_right->n_type; + q2 = p->n_right->n_qual; + d = p->n_left->n_df; + d2 = p->n_right->n_df; + ap = p->n_left->n_ap; + ap2 = p->n_right->n_ap; + + switch( o ){ + + case ASSIGN: + case RETURN: + { break; } + + case CAST: + if (t == VOID) { + /* just paint over */ + p->n_right = block(SCONV, p->n_right, NIL, VOID, 0, 0); + return p; + } + break; + + case MINUS: { + int isdyn(struct symtab *sp); + struct symtab s1, s2; + + s1.stype = DECREF(t); + s1.sdf = d; + s2.stype = DECREF(t2); + s2.sdf = d2; + if (isdyn(&s1) || isdyn(&s2)) + ; /* We don't know */ + else if (psize(p->n_left) != psize(p->n_right)) + uerror("illegal pointer subtraction"); + break; + } + + case COLON: + if (t1 != t2) { + /* + * Check for void pointer types. They are allowed + * to cast to/from any pointers. + */ + if (ISPTR(t1) && ISPTR(t2) && + (BTYPE(t1) == VOID || BTYPE(t2) == VOID)) + break; + uerror("illegal types in :"); + } + break; + + default: /* must work harder: relationals or comparisons */ + + if( !ISPTR(t1) ){ + t = t2; + q = q2; + d = d2; + ap = ap2; + break; + } + if( !ISPTR(t2) ){ + break; + } + + /* both are pointers */ + if( talign(t2,ap2) < talign(t,ap) ){ + t = t2; + q = q2; + ap = ap2; + } + break; + } + + p->n_left = makety( p->n_left, t, q, d, ap ); + p->n_right = makety( p->n_right, t, q, d, ap ); + if( o!=MINUS && !clogop(o) ){ + + p->n_type = t; + p->n_qual = q; + p->n_df = d; + p->n_ap = ap; + } + + return(clocal(p)); +} + +/* + * Satisfy the types of various arithmetic binary ops. + * + * rules are: + * if assignment, type of LHS + * if any doubles, make double + * else if any float make float + * else if any longlongs, make long long + * else if any longs, make long + * else etcetc. + * + * If the op with the highest rank is unsigned, this is the resulting type. + * See: 6.3.1.1 rank order equal of signed and unsigned types + * 6.3.1.8 Usual arithmetic conversions + */ +static NODE * +tymatch(NODE *p) +{ + TWORD tl, tr, t; + NODE *l, *r; + int o; + + o = p->n_op; + r = p->n_right; + l = p->n_left; + + tl = l->n_type; + tr = r->n_type; + + if (tl == BOOL) tl = BOOL_TYPE; + if (tr == BOOL) tr = BOOL_TYPE; + + if (casgop(o)) { + if (r->n_op != ICON && tl < FLOAT && tr < FLOAT && + DEUNSIGN(tl) < DEUNSIGN(tr) && o != CAST) + warner(Wtruncate, tnames[tr], tnames[tl]); + p->n_right = makety(p->n_right, l->n_type, 0, 0, 0); + t = p->n_type = l->n_type; + p->n_ap = l->n_ap; + } else { + t = tl > tr ? tl : tr; /* MAX */ + /* This depends on ctype() called early */ + if (o != COLON && t < INT) + t = INT; + if (tl != t) p->n_left = makety(p->n_left, t, 0, 0, 0); + if (tr != t) p->n_right = makety(p->n_right, t, 0, 0, 0); + if (o == COLON && l->n_type == BOOL && r->n_type == BOOL) + t = p->n_type = BOOL; + else if (!clogop(o)) + p->n_type = t; + } +#ifdef PCC_DEBUG + if (tdebug) { + printf("tymatch(%p): ", p); + tprint(tl, 0); + printf(" %s ", copst(o)); + tprint(tr, 0); + printf(" => "); + tprint(t, 0); + printf("\n"); + fwalk(p, eprint, 0); + } +#endif + return p; +} + +/* + * make p into type t by inserting a conversion + */ +NODE * +makety(NODE *p, TWORD t, TWORD q, union dimfun *d, struct attr *ap) +{ + + if (t == p->n_type) { + p->n_df = d; + p->n_ap = ap; + p->n_qual = q; + return(p); + } + + if (ISITY(t) || ISCTY(t) || ISITY(p->n_type) || ISCTY(p->n_type)) + cerror("makety"); + + if (concast(p, t)) + return clocal(p); + + p = block(t & TMASK ? PCONV : SCONV, p, NIL, t, d, ap); + p->n_qual = q; + return clocal(p); +} + +NODE * +block(int o, NODE *l, NODE *r, TWORD t, union dimfun *d, struct attr *ap) +{ + register NODE *p; + + p = talloc(); + p->n_rval = 0; + p->n_op = o; + glval(p) = 0; /* Protect against large lval */ + p->n_left = l; + p->n_right = r; + p->n_type = t; + p->n_qual = 0; + p->n_df = d; + p->n_ap = ap; +#if !defined(MULTIPASS) + /* p->n_reg = */p->n_su = 0; + p->n_regw = 0; +#endif + return(p); +} + +/* + * Return the constant value from an ICON. + */ +CONSZ +icons(NODE *p) +{ + /* if p is an integer constant, return its value */ + CONSZ val; + + if (p->n_op != ICON || p->n_sp != NULL) { + uerror( "constant expected"); + val = 1; + } else + val = glval(p); + tfree(p); + return(val); +} + +/* + * the intent of this table is to examine the + * operators, and to check them for + * correctness. + * + * The table is searched for the op and the + * modified type (where this is one of the + * types INT (includes char and short), LONG, + * DOUBLE (includes FLOAT), and POINTER + * + * The default action is to make the node type integer + * + * The actions taken include: + * PUN check for puns + * CVTL convert the left operand + * CVTR convert the right operand + * TYPL the type is determined by the left operand + * TYPR the type is determined by the right operand + * TYMATCH force type of left and right to match,by inserting conversions + * PTMATCH like TYMATCH, but for pointers + * LVAL left operand must be lval + * CVTO convert the op + * NCVT do not convert the operands + * OTHER handled by code + * NCVTR convert the left operand, not the right... + * + */ + +# define MINT 01 /* integer */ +# define MDBI 02 /* integer or double */ +# define MSTR 04 /* structure */ +# define MPTR 010 /* pointer */ +# define MPTI 020 /* pointer or integer */ + +int +opact(NODE *p) +{ + int mt12, mt1, mt2, o; + + mt1 = mt2 = mt12 = 0; + + switch (coptype(o = p->n_op)) { + case BITYPE: + mt12=mt2 = moditype(p->n_right->n_type); + /* FALLTHROUGH */ + case UTYPE: + mt12 &= (mt1 = moditype(p->n_left->n_type)); + break; + } + + switch( o ){ + + case NAME : + case ICON : + case FCON : + case CALL : + case UCALL: + case UMUL: + { return( OTHER ); } + case UMINUS: + if( mt1 & MDBI ) return( TYPL+PROML ); + break; + + case COMPL: + if( mt1 & MINT ) return( TYPL+PROML ); + break; + + case ADDROF: + return( NCVT+OTHER ); + case NOT: + return( PROML ); + +/* case INIT: */ + case CM: + case CBRANCH: + case ANDAND: + case OROR: + return( 0 ); + + case MUL: + case DIV: + if( mt12 & MDBI ) return( TYMATCH ); + break; + + case MOD: + case AND: + case OR: + case ER: + if( mt12 & MINT ) return( TYMATCH ); + break; + + case LS: + case RS: + if( mt12 & MINT ) return( TYPL+OTHER ); + break; + + case EQ: + case NE: + case LT: + case LE: + case GT: + case GE: + if( mt12 & MDBI ) return( TYMATCH+CVTO ); + else if( mt12 & MPTR ) return( PTMATCH+PUN+CVTO ); + else if( mt12 & MPTI ) return( PTMATCH+PUN ); + else break; + + case QUEST: + return( TYPR+OTHER ); + case COMOP: + return( TYPR ); + + case STREF: + return( NCVTR+OTHER ); + + case FORCE: + return( TYPL ); + + case COLON: + if( mt12 & MDBI ) return( TYMATCH ); + else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN ); + else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN ); + else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN ); + else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER ); + break; + + case ASSIGN: + case RETURN: + if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER ); + case CAST: + if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); + else if( mt1 & MPTR) return( LVAL+PTMATCH+PUN ); + else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); + break; + + case LSEQ: + case RSEQ: + if( mt12 & MINT ) return( TYPL+LVAL+OTHER ); + break; + + case MULEQ: + case DIVEQ: + if( mt12 & MDBI ) return( LVAL+TYMATCH ); + break; + + case MODEQ: + case ANDEQ: + case OREQ: + case EREQ: + if (mt12 & MINT) + return(LVAL+TYMATCH); + break; + + case PLUSEQ: + case MINUSEQ: + case INCR: + case DECR: + if (mt12 & MDBI) + return(TYMATCH+LVAL); + else if ((mt1&MPTR) && (mt2&MINT)) + return(TYPL+LVAL+CVTR); + break; + + case MINUS: + if (mt12 & MPTR) + return(CVTO+PTMATCH+PUN); + if (mt2 & MPTR) + break; + /* FALLTHROUGH */ + case PLUS: + if (mt12 & MDBI) + return(TYMATCH); + else if ((mt1&MPTR) && (mt2&MINT)) + return(TYPL+CVTR); + else if ((mt1&MINT) && (mt2&MPTR)) + return(TYPR+CVTL); + + } + uerror("operands of %s have incompatible types", copst(o)); + return(NCVT); +} + +int +moditype(TWORD ty) +{ + switch (ty) { + + case STRTY: + case UNIONTY: + return( MSTR ); + + case BOOL: + case CHAR: + case SHORT: + case UCHAR: + case USHORT: + case UNSIGNED: + case ULONG: + case ULONGLONG: + case INT: + case LONG: + case LONGLONG: + return( MINT|MDBI|MPTI ); + case FLOAT: + case DOUBLE: + case LDOUBLE: +#ifndef NO_COMPLEX + case FCOMPLEX: + case COMPLEX: + case LCOMPLEX: + case FIMAG: + case IMAG: + case LIMAG: +#endif + return( MDBI ); + default: + return( MPTR|MPTI ); + + } +} + +int tvaloff = MAXREGS+NPERMREG > 100 ? MAXREGS+NPERMREG + 100 : 100; + +/* + * Returns a TEMP node with temp number nr. + * If nr == 0, return a node with a new number. + */ +NODE * +tempnode(int nr, TWORD type, union dimfun *df, struct attr *ap) +{ + NODE *r; + + if (tvaloff == -NOOFFSET) + tvaloff++; /* Skip this for array indexing */ + r = block(TEMP, NIL, NIL, type, df, ap); + regno(r) = nr ? nr : tvaloff; + tvaloff += szty(type); + return r; +} + +/* + * Do sizeof on p. + */ +NODE * +doszof(NODE *p) +{ + extern NODE *arrstk[10]; + extern int arrstkp; + union dimfun *df; + TWORD ty; + NODE *rv, *q; + int astkp; + + if (p->n_op == FLD) + uerror("can't apply sizeof to bit-field"); + + /* + * Arrays may be dynamic, may need to make computations. + */ + + rv = bcon(1); + df = p->n_df; + ty = p->n_type; + astkp = 0; + while (ISARY(ty)) { + if (df->ddim == NOOFFSET) + uerror("sizeof of incomplete type"); + if (df->ddim < 0) { + if (arrstkp) + q = arrstk[astkp++]; + else + q = tempnode(-df->ddim, INT, 0, 0); + } else + q = bcon(df->ddim); + rv = buildtree(MUL, rv, q); + df++; + ty = DECREF(ty); + } + rv = buildtree(MUL, rv, + xbcon(tsize(ty, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR)); + tfree(p); + arrstkp = 0; /* XXX - may this fail? */ + return rv; +} + +#ifdef PCC_DEBUG +void +eprint(NODE *p, int down, int *a, int *b) +{ + int ty; + + *a = *b = down+1; + while( down > 1 ){ + printf( "\t" ); + down -= 2; + } + if( down ) printf( " " ); + + ty = coptype( p->n_op ); + + printf("%p) %s, ", p, copst(p->n_op)); + if (p->n_op == XARG || p->n_op == XASM) + printf("id '%s', ", p->n_name); + if (ty == LTYPE) { + printf(CONFMT, glval(p)); + if (p->n_op == NAME || p->n_op == ICON) + printf(", %p, ", p->n_sp); + else + printf(", %d, ", p->n_rval); + } + tprint(p->n_type, p->n_qual); + printf( ", %p, ", p->n_df); +#ifdef GCC_COMPAT + dump_attr(p->n_ap); +#endif +} +# endif + +/* + * Emit everything that should be emitted on the left side + * of a comma operator, and remove the operator. + * Do not traverse through QUEST, ANDAND and OROR. + * Enable this for all targets when stable enough. + */ +static void +comops(NODE *p) +{ + int o; + NODE *q; + + while (p->n_op == COMOP) { + /* XXX hack for GCC ({ }) ops */ + if (p->n_left->n_op == GOTO) { + int v = (int)glval(p->n_left->n_left); + ecomp(p->n_left); + plabel(v+1); + } else + ecomp(p->n_left); /* will recurse if more COMOPs */ + q = p->n_right; + *p = *q; + nfree(q); + } + o = coptype(p->n_op); + if (p->n_op == QUEST || p->n_op == ANDAND || p->n_op == OROR) + o = UTYPE; + if (o != LTYPE) + comops(p->n_left); + if (o == BITYPE) + comops(p->n_right); +} + +/* + * Walk up through the tree from the leaves, + * removing constant operators. + */ +static void +logwalk(NODE *p) +{ + int o = coptype(p->n_op); + NODE *l, *r; + + l = p->n_left; + r = p->n_right; + switch (o) { + case LTYPE: + return; + case BITYPE: + logwalk(r); + /* FALLTHROUGH */ + case UTYPE: + logwalk(l); + } + if (!clogop(p->n_op)) + return; + if (p->n_op == NOT && l->n_op == ICON) { + glval(p) = glval(l) == 0; + nfree(l); + p->n_op = ICON; + } + if (l->n_op == ICON && r->n_op == ICON) { + if (conval(l, p->n_op, r) == 0) { + /* + * people sometimes tend to do really odd compares, + * like "if ("abc" == "def")" etc. + * do it runtime instead. + */ + } else { + glval(p) = glval(l); + p->n_op = ICON; + nfree(l); + nfree(r); + } + } +} + +/* + * Removes redundant logical operators for branch conditions. + */ +static void +fixbranch(NODE *p, int label) +{ + + logwalk(p); + + if (p->n_op == ICON) { + if (glval(p) != 0) + branch(label); + nfree(p); + } else { + if (!clogop(p->n_op)) /* Always conditional */ + p = buildtree(NE, p, bcon(0)); + ecode(buildtree(CBRANCH, p, bcon(label))); + } +} + +/* + * Write out logical expressions as branches. + */ +static void +andorbr(NODE *p, int true, int false) +{ + NODE *q; + int o, lab; + + lab = -1; + switch (o = p->n_op) { + case EQ: + case NE: + /* + * Remove redundant EQ/NE nodes. + */ + while (((o = p->n_left->n_op) == EQ || o == NE) && + p->n_right->n_op == ICON) { + o = p->n_op; + q = p->n_left; + if (glval(p->n_right) == 0) { + nfree(p->n_right); + *p = *q; + nfree(q); + if (o == EQ) + p->n_op = negrel[p->n_op - EQ]; +#if 0 + p->n_op = NE; /* toggla */ +#endif + } else if (glval(p->n_right) == 1) { + nfree(p->n_right); + *p = *q; + nfree(q); + if (o == NE) + p->n_op = negrel[p->n_op - EQ]; +#if 0 + p->n_op = EQ; /* toggla */ +#endif + } else + break; /* XXX - should always be false */ + + } + /* FALLTHROUGH */ + case LE: + case LT: + case GE: + case GT: +calc: if (true < 0) { + p->n_op = negrel[p->n_op - EQ]; + true = false; + false = -1; + } + + rmcops(p->n_left); + rmcops(p->n_right); + fixbranch(p, true); + if (false >= 0) + branch(false); + break; + + case ULE: + case UGT: + /* Convert to friendlier ops */ + if (nncon(p->n_right) && glval(p->n_right) == 0) + p->n_op = o == ULE ? EQ : NE; + goto calc; + + case UGE: + case ULT: + /* Already true/false by definition */ + if (nncon(p->n_right) && glval(p->n_right) == 0) { + if (true < 0) { + o = o == ULT ? UGE : ULT; + true = false; + } + rmcops(p->n_left); + ecode(p->n_left); + rmcops(p->n_right); + ecode(p->n_right); + nfree(p); + if (o == UGE) /* true */ + branch(true); + break; + } + goto calc; + + case ANDAND: + lab = false<0 ? getlab() : false ; + andorbr(p->n_left, -1, lab); + comops(p->n_right); + andorbr(p->n_right, true, false); + if (false < 0) + plabel( lab); + nfree(p); + break; + + case OROR: + lab = true<0 ? getlab() : true; + andorbr(p->n_left, lab, -1); + comops(p->n_right); + andorbr(p->n_right, true, false); + if (true < 0) + plabel( lab); + nfree(p); + break; + + case NOT: + andorbr(p->n_left, false, true); + nfree(p); + break; + + default: + rmcops(p); + if (true >= 0) + fixbranch(p, true); + if (false >= 0) { + if (true >= 0) + branch(false); + else + fixbranch(buildtree(EQ, p, bcon(0)), false); + } + } +} + +/* + * Create a node for either TEMP or on-stack storage. + */ +NODE * +cstknode(TWORD t, union dimfun *df, struct attr *ap) +{ + struct symtab *sp; + + /* create a symtab entry suitable for this type */ + sp = getsymtab("0hej", STEMP); + sp->stype = t; + sp->sdf = df; + sp->sap = ap; + sp->sclass = AUTO; + sp->soffset = NOOFFSET; + oalloc(sp, &autooff); + return nametree(sp); + +} + +/* + * Massage the output trees to remove C-specific nodes: + * COMOPs are split into separate statements. + * QUEST/COLON are rewritten to branches. + * ANDAND/OROR/NOT are rewritten to branches for lazy-evaluation. + * CBRANCH conditions are rewritten for lazy-evaluation. + */ +static void +rmcops(NODE *p) +{ + TWORD type; + NODE *q, *r, *tval; + int o, ty, lbl, lbl2; + + tval = NIL; + o = p->n_op; + ty = coptype(o); + if (BTYPE(p->n_type) == ENUMTY) { /* fixup enum */ + struct symtab *sp = strmemb(p->n_ap); + MODTYPE(p->n_type, sp->stype); + /* + * XXX may fail if these are true: + * - variable-sized enums + * - non-byte-addressed targets. + */ + if (BTYPE(p->n_type) == ENUMTY && ISPTR(p->n_type)) + MODTYPE(p->n_type, INT); /* INT ok? */ + } + switch (o) { + case QUEST: + + /* + * Create a branch node from ?: + * || and && must be taken special care of. + */ + type = p->n_type; + andorbr(p->n_left, -1, lbl = getlab()); + + /* Make ASSIGN node */ + /* Only if type is not void */ + q = p->n_right->n_left; + comops(q); + if (type != VOID) { + tval = cstknode(q->n_type, q->n_df, q->n_ap); + q = buildtree(ASSIGN, ccopy(tval), q); + } + rmcops(q); + ecode(q); /* Done with assign */ + branch(lbl2 = getlab()); + plabel( lbl); + + q = p->n_right->n_right; + comops(q); + if (type != VOID) { + q = buildtree(ASSIGN, ccopy(tval), q); + } + rmcops(q); + ecode(q); /* Done with assign */ + + plabel( lbl2); + + nfree(p->n_right); + if (p->n_type != VOID) { + *p = *tval; + nfree(tval); + } else { + p->n_op = ICON; + glval(p) = 0; + p->n_sp = NULL; + } + break; + + case ULE: + case ULT: + case UGE: + case UGT: + case EQ: + case NE: + case LE: + case LT: + case GE: + case GT: + case ANDAND: + case OROR: + case NOT: +#ifdef SPECIAL_CCODES +#error fix for private CCODES handling +#else + r = talloc(); + *r = *p; + andorbr(r, -1, lbl = getlab()); + + tval = cstknode(p->n_type, p->n_df, p->n_ap); + + ecode(buildtree(ASSIGN, ccopy(tval), bcon(1))); + branch(lbl2 = getlab()); + plabel( lbl); + ecode(buildtree(ASSIGN, ccopy(tval), bcon(0))); + plabel( lbl2); + + *p = *tval; + nfree(tval); + +#endif + break; + case CBRANCH: + andorbr(p->n_left, glval(p->n_right), -1); + nfree(p->n_right); + p->n_op = ICON; p->n_type = VOID; + break; + case COMOP: + cerror("COMOP error"); + + default: + if (ty == LTYPE) + return; + rmcops(p->n_left); + if (ty == BITYPE) + rmcops(p->n_right); + } +} + +/* + * Return 1 if an assignment is found. + */ +static int +has_se(NODE *p) +{ + if (cdope(p->n_op) & ASGFLG) + return 1; + if (coptype(p->n_op) == LTYPE) + return 0; + if (has_se(p->n_left)) + return 1; + if (coptype(p->n_op) == BITYPE) + return has_se(p->n_right); + return 0; +} + +/* + * Find and convert asgop's to separate statements. + * Be careful about side effects. + * assign tells whether ASSIGN should be considered giving + * side effects or not. + */ +static NODE * +delasgop(NODE *p) +{ + NODE *q, *r; + int tval; + + if (p->n_op == INCR || p->n_op == DECR) { + /* + * Rewrite x++ to (x += 1) -1; and deal with it further down. + * Pass2 will remove -1 if unnecessary. + */ + q = ccopy(p); + tfree(p->n_left); + q->n_op = (p->n_op==INCR)?PLUSEQ:MINUSEQ; + p->n_op = (p->n_op==INCR)?MINUS:PLUS; + p->n_left = delasgop(q); + + } else if ((cdope(p->n_op)&ASGOPFLG) && + p->n_op != RETURN && p->n_op != CAST) { + NODE *l = p->n_left; + NODE *ll = l->n_left; + + if (has_se(l)) { + q = tempnode(0, ll->n_type, ll->n_df, ll->n_ap); + tval = regno(q); + r = tempnode(tval, ll->n_type, ll->n_df,ll->n_ap); + l->n_left = q; + /* Now the left side of node p has no side effects. */ + /* side effects on the right side must be obeyed */ + p = delasgop(p); + + r = buildtree(ASSIGN, r, ll); + r = delasgop(r); + ecode(r); + } else { +#if 0 /* Cannot call buildtree() here, it would invoke double add shifts */ + p->n_right = buildtree(UNASG p->n_op, ccopy(l), + p->n_right); +#else + p->n_right = block(UNASG p->n_op, ccopy(l), + p->n_right, p->n_type, p->n_df, p->n_ap); +#endif + p->n_op = ASSIGN; + p->n_right = delasgop(p->n_right); + p->n_right = clocal(p->n_right); + } + + } else { + if (coptype(p->n_op) == LTYPE) + return p; + p->n_left = delasgop(p->n_left); + if (coptype(p->n_op) == BITYPE) + p->n_right = delasgop(p->n_right); + } + return p; +} + +#ifndef FIELDOPS + +/* avoid promotion to int */ +#define TYPMOD(o, p, n, t) clocal(block(o, p, n, t, 0, 0)) +#define TYPLS(p, n, t) TYPMOD(LS, p, n, t) +#define TYPRS(p, n, t) TYPMOD(RS, p, n, t) +#define TYPOR(p, q, t) TYPMOD(OR, p, q, t) +#define TYPAND(p, q, t) TYPMOD(AND, p, q, t) + +/* + * Read an unaligned bitfield from position pointed to by p starting at + * off and size fsz and return a tree of type t with resulting data. + */ +static NODE * +rdualfld(NODE *p, TWORD t, TWORD ct, int off, int fsz) +{ + int t2f, inbits, tsz, ctsz; + NODE *q, *r; + + ct = ENUNSIGN(ct); + ctsz = (int)tsize(ct, 0, 0); + + /* traverse until first data byte */ + for (t2f = 0; off > ctsz; t2f++, off -= ctsz) + ; +#ifdef UNALIGNED_ACCESS + /* try to squeeze it into an int */ + if (off + fsz > ctsz && off + fsz <= SZINT) { + ct = UNSIGNED; + ctsz = SZINT; + } +#endif + p = makety(p, PTR|ct, 0, 0, 0); + if (off + fsz <= ctsz) { + /* only one operation needed */ + q = buildtree(UMUL, buildtree(PLUS, p, bcon(t2f)), 0); + if (!ISUNSIGNED(t)) { + ct = DEUNSIGN(ct); + q = makety(q, ct, 0, 0, 0); + } + q = TYPLS(q, bcon(ctsz-fsz-off), ct); + q = TYPRS(q, bcon(ctsz-fsz), ct); + q = makety(q, t, 0, 0, 0); + } else { + q = buildtree(UMUL, buildtree(PLUS, ccopy(p), bcon(t2f)), 0); + q = makety(TYPRS(q, bcon(off), ct), t, 0, 0, 0); + inbits = ctsz - off; + t2f++; + + while (fsz > inbits) { + r = buildtree(UMUL, + buildtree(PLUS, ccopy(p), bcon(t2f)), 0); + r = makety(r, t, 0, 0, 0); + r = TYPLS(r, bcon(inbits), t); + q = TYPOR(q, r, t); + inbits += ctsz; + t2f++; + } + /* sign/zero extend XXX - RS must sign extend */ + tsz = (int)tsize(t, 0, 0); + if (!ISUNSIGNED(t)) { + t = DEUNSIGN(t); + q = makety(q, t, 0, 0, 0); + } + q = TYPLS(q, bcon(tsz-fsz), t); + q = TYPRS(q, bcon(tsz-fsz), t); + tfree(p); + } + + return q; +} + +/* + * Write val to a (unaligned) bitfield with length fsz positioned off bits + * from d. Bitfield type is t, and type to use when writing is ct. + * neither f nor d should have any side effects if copied. + * Multiples of ct are supposed to be written without problems. + * Both val and d are free'd after use. + */ +static NODE * +wrualfld(NODE *val, NODE *d, TWORD t, TWORD ct, int off, int fsz) +{ + NODE *p, *q, *r, *rn, *s; + int ctsz, t2f, inbits; + + ctsz = (int)tsize(ct, 0, 0); + + ct = ENUNSIGN(ct); + d = makety(d, PTR|ct, 0, 0, 0); + + for (t2f = 0; off > ctsz; t2f++, off -= ctsz) + ; + + if (off + fsz <= ctsz) { + r = tempnode(0, ct, 0, 0); + + /* only one operation needed */ + d = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0); + p = ccopy(d); + p = TYPAND(p, xbcon(~(SZMASK(fsz) << off), 0, ct), ct); + + val = makety(val, ct, 0, 0, 0); + q = TYPAND(val, xbcon(SZMASK(fsz), 0, ct), ct); + q = buildtree(ASSIGN, ccopy(r), q); + + q = TYPLS(q, bcon(off), ct); + p = TYPOR(p, q, ct); + p = makety(p, t, 0, 0, 0); + rn = buildtree(ASSIGN, d, p); + rn = buildtree(COMOP, rn, makety(r, t, 0, 0, 0)); + } else { + s = makety(ccopy(val), t, 0, 0, 0); + s = TYPAND(s, xbcon(SZMASK(fsz), 0, t), t); + + r = buildtree(UMUL, buildtree(PLUS, ccopy(d), bcon(t2f)), 0); + p = ccopy(r); + p = TYPAND(p, xbcon(SZMASK(off), 0, ct), ct); + q = ccopy(val); + q = TYPLS(q, bcon(off), t); + q = makety(q, ct, 0, 0, 0); + p = TYPOR(p, q, ct); + rn = buildtree(ASSIGN, r, p); + inbits = ctsz - off; + t2f++; + + while (fsz > inbits+ctsz) { + r = buildtree(UMUL, + buildtree(PLUS, ccopy(d), bcon(t2f)), 0); + q = ccopy(val); + q = TYPRS(q, bcon(inbits), t); + q = makety(q, ct, 0, 0, 0); + rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, q)); + t2f++; + inbits += ctsz; + } + + r = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0); + p = ccopy(r); + p = TYPAND(p, makety(xbcon(~SZMASK(fsz-inbits), 0, ct), + ct, 0, 0, 0), ct); + q = TYPRS(val, bcon(inbits), t); + q = TYPAND(q, xbcon(SZMASK(fsz-inbits), 0, t), t); + q = makety(q, ct, 0, 0, 0); + p = TYPOR(p, q, ct); + rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, p)); + rn = buildtree(COMOP, rn, s); + } + return rn; +} + +/* + * Rewrite bitfield operations to shifts. + */ +static NODE * +rmfldops(NODE *p) +{ + TWORD t, ct; + NODE *q, *r, *t1, *t2, *bt, *t3, *t4; + int fsz, foff; + + if (p->n_op == FLD) { + /* Rewrite a field read operation */ + fsz = UPKFSZ(p->n_rval); + foff = UPKFOFF(p->n_rval); + q = buildtree(ADDROF, p->n_left, NIL); + + ct = t = p->n_type; +#ifdef GCC_COMPAT + if (attr_find(p->n_ap, GCC_ATYP_PACKED) && + coptype(q->n_op) != LTYPE) { + t1 = tempnode(0, q->n_type, 0, 0); + bt = buildtree(ASSIGN, ccopy(t1), q); + q = t1; +#ifndef UNALIGNED_ACCESS + ct = UCHAR; +#endif + } else +#endif + bt = bcon(0); + q = rdualfld(q, t, ct, foff, fsz); + p->n_left = bt; + p->n_right = q; + p->n_op = COMOP; + } else if (((cdope(p->n_op)&ASGOPFLG) || p->n_op == ASSIGN || + p->n_op == INCR || p->n_op == DECR) && p->n_left->n_op == FLD) { + /* + * Rewrite a field write operation + * More difficult than a read op since we must care + * about side effects. + */ + q = p->n_left; + fsz = UPKFSZ(q->n_rval); + foff = UPKFOFF(q->n_rval); + t = q->n_left->n_type; +#if TARGET_ENDIAN == TARGET_BE + foff = (int)tsize(t, 0, 0) - fsz - foff; +#endif + bt = NULL; + if (p->n_right->n_op != ICON && p->n_right->n_op != NAME) { + t2 = tempnode(0, p->n_right->n_type, 0, 0); + bt = buildtree(ASSIGN, ccopy(t2), p->n_right); + } else + t2 = p->n_right; + + ct = t; +#ifdef GCC_COMPAT +#ifndef UNALIGNED_ACCESS + if (attr_find(q->n_ap, GCC_ATYP_PACKED)) + ct = UCHAR; +#endif +#endif + /* t2 is what we have to write (RHS of ASSIGN) */ + /* bt is (eventually) something that must be written */ + + + if (q->n_left->n_op == UMUL) { + /* LHS of assignment may have side effects */ + q = q->n_left; + t1 = tempnode(0, q->n_left->n_type, 0, 0); + r = buildtree(ASSIGN, ccopy(t1), q->n_left); + + bt = bt ? block(COMOP, bt, r, INT, 0, 0) : r; + q->n_left = t1; + } + t1 = buildtree(ADDROF, p->n_left->n_left, 0); + + /* t1 is lval where to write (and read) */ + + if (p->n_op == ASSIGN) { + q = wrualfld(t2, t1, t, ct, foff, fsz); + if (bt) + q = block(COMOP, bt, q, t, 0, 0); + nfree(p->n_left); + p->n_left = bcon(0); + p->n_right = q; + p->n_op = COMOP; + } else if ((cdope(p->n_op)&ASGOPFLG)) { + /* And here is the asgop-specific code */ + t3 = tempnode(0, t, 0, 0); + q = rdualfld(ccopy(t1), t, ct, foff, fsz); + q = buildtree(UNASG p->n_op, q, t2); + q = buildtree(ASSIGN, ccopy(t3), q); + r = wrualfld(ccopy(t3), t1, t, ct, foff, fsz); + q = buildtree(COMOP, q, r); + q = buildtree(COMOP, q, t3); + + nfree(p->n_left); + p->n_left = bt ? bt : bcon(0); + p->n_right = q; + p->n_op = COMOP; + } else { + t3 = tempnode(0, t, 0, 0); + t4 = tempnode(0, t, 0, 0); + + q = rdualfld(ccopy(t1), t, ct, foff, fsz); + q = buildtree(ASSIGN, ccopy(t3), q); + r = buildtree(p->n_op==INCR?PLUS:MINUS, ccopy(t3), t2); + r = buildtree(ASSIGN, ccopy(t4), r); + q = buildtree(COMOP, q, r); + r = wrualfld(t4, t1, t, ct, foff, fsz); + q = buildtree(COMOP, q, r); + + if (bt) + q = block(COMOP, bt, q, t, 0, 0); + nfree(p->n_left); + p->n_left = q; + p->n_right = t3; + p->n_op = COMOP; + } + } + if (coptype(p->n_op) != LTYPE) + p->n_left = rmfldops(p->n_left); + if (coptype(p->n_op) == BITYPE) + p->n_right = rmfldops(p->n_right); + return p; +} +#endif + +void +ecomp(NODE *p) +{ + +#ifdef PCC_DEBUG + if (edebug) + fwalk(p, eprint, 0); +#endif + if (!reached) { + warner(Wunreachable_code); + reached = 1; + } + p = optim(p); +#ifndef FIELDOPS + p = rmfldops(p); +#endif + comops(p); + rmcops(p); + p = delasgop(p); + if (p->n_op == ICON && p->n_type == VOID) + tfree(p); + else + ecode(p); +} + + +#if defined(MULTIPASS) +void +p2tree(NODE *p) +{ + struct symtab *q; + int ty; + + myp2tree(p); /* local action can be taken here */ + + ty = coptype(p->n_op); + + printf("%d\t", p->n_op); + + if (ty == LTYPE) { + printf(CONFMT, glval(p)); + printf("\t"); + } + if (ty != BITYPE) { + if (p->n_op == NAME || p->n_op == ICON) + printf("0\t"); + else + printf("%d\t", p->n_rval); + } + + printf("%o\t", p->n_type); + + /* handle special cases */ + + switch (p->n_op) { + + case NAME: + case ICON: + /* print external name */ + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0)) { + printf(LABFMT, q->soffset); + } else + printf("%s\n", + q->soname ? q->soname : exname(q->sname)); + } else + printf("\n"); + break; + + case STARG: + case STASG: + case STCALL: + case USTCALL: + /* print out size */ + /* use lhs size, in order to avoid hassles + * with the structure `.' operator + */ + + /* note: p->left not a field... */ + printf(CONFMT, (CONSZ)tsize(STRTY, p->n_left->n_df, + p->n_left->n_ap)); + printf("\t%d\t\n", talign(STRTY, p->n_left->n_ap)); + break; + + case XARG: + case XASM: + break; + + default: + printf( "\n" ); + } + + if (ty != LTYPE) + p2tree(p->n_left); + if (ty == BITYPE) + p2tree(p->n_right); +} +#else +static char * +sptostr(struct symtab *sp) +{ + char *cp = inlalloc(32); + int n = sp->soffset; + if (n < 0) + n = -n; + snprintf(cp, 32, LABFMT, n); + return cp; +} + +void +p2tree(NODE *p) +{ + struct attr *oap, *ap; + struct symtab *q; + int ty; + + myp2tree(p); /* local action can be taken here */ + + /* Fix left imaginary types */ + if (ISITY(BTYPE(p->n_type))) + MODTYPE(p->n_type, p->n_type - (FIMAG-FLOAT)); + + /* cleanup attributes. + * copy those that are supposed to go into pass2 */ + oap = p->n_ap; + p->n_ap = NULL; + for (ap = oap; ap; ap = ap->next) + if (ap->atype < ATTR_MI_MAX) + p->n_ap = attr_add(p->n_ap, attr_dup(ap)); + /* XXX store size of attr in itself */ + + ty = coptype(p->n_op); + + switch( p->n_op ){ + + case NAME: + case ICON: + if ((q = p->n_sp) != NULL) { + if ((q->sclass == STATIC && q->slevel > 0) +#ifdef GCC_COMPAT + || q->sflags == SLBLNAME +#endif + ) { + p->n_name = sptostr(q); + } else { + if ((p->n_name = q->soname) == NULL) + p->n_name = addname(exname(q->sname)); + } + } else + p->n_name = ""; + break; + + case STASG: + case STARG: + case STCALL: + case USTCALL: + /* STASG used for stack array init */ + if (p->n_op == STASG && ISARY(p->n_type)) { + int size1 = (int)tsize(p->n_type, p->n_left->n_df, + p->n_left->n_ap)/SZCHAR; + ap->iarg(0) = (int)tsize(p->n_type, p->n_right->n_df, + p->n_right->n_ap)/SZCHAR; + if (size1 < ap->iarg(0)) + ap->iarg(0) = size1; + ap->iarg(1) = talign(p->n_type, + p->n_left->n_ap)/SZCHAR; + break; + } + /* set up size parameters */ + ap->iarg(0) = (int)((tsize(STRTY, p->n_left->n_df, + p->n_left->n_ap)+SZCHAR-1)/SZCHAR); + ap->iarg(1) = talign(STRTY,p->n_left->n_ap)/SZCHAR; + if (ap->iarg(1) == 0) + ap->iarg(1) = 1; /* At least char for packed structs */ + break; + + case XARG: + case XASM: + break; + + default: + p->n_name = ""; + } + + if( ty != LTYPE ) p2tree( p->n_left ); + if( ty == BITYPE ) p2tree( p->n_right ); + } + +#endif + +/* + * Change void data types into char. + */ +static void +delvoid(NODE *p, void *arg) +{ + /* Convert "PTR undef" (void *) to "PTR uchar" */ + if (BTYPE(p->n_type) == VOID) + p->n_type = (p->n_type & ~BTMASK) | UCHAR; + if (BTYPE(p->n_type) == BOOL) { + if (p->n_op == SCONV && p->n_type == BOOL) { + /* create a jump and a set */ + NODE *r; + int l, l2; + + r = tempnode(0, BOOL_TYPE, NULL, 0); + cbranch(buildtree(EQ, p->n_left, bcon(0)), + bcon(l = getlab())); + *p = *r; + ecode(buildtree(ASSIGN, tcopy(r), bcon(1))); + branch(l2 = getlab()); + plabel(l); + ecode(buildtree(ASSIGN, r, bcon(0))); + plabel(l2); + } else + p->n_type = (p->n_type & ~BTMASK) | BOOL_TYPE; + } + +} + +/* + * Change calls inside calls to separate statement. + */ +static NODE * +deldcall(NODE *p, int split) +{ + NODE *q, *r; + int o = p->n_op; + + if (cdope(o) & CALLFLG) { + if (split) { + q = cstknode(p->n_type, p->n_df, p->n_ap); + r = ccopy(q); + q = block(ASSIGN, q, p, p->n_type, p->n_df, p->n_ap); + ecode(q); + return r; + } + split++; + } + if (coptype(o) == BITYPE) + p->n_right = deldcall(p->n_right, split); + if (coptype(o) != LTYPE) + p->n_left = deldcall(p->n_left, split); + return p; +} + +#ifndef WORD_ADDRESSED + +static NODE * +pprop(NODE *p, TWORD t, struct attr *ap) +{ + int o = p->n_op; + TWORD t2; + +#ifdef PCC_DEBUG + if (p->n_op == TEMP && p->n_type != t && + !(ISPTR(p->n_type) && ISPTR(t))) { + cerror("TEMP type change: %x -> %x", p->n_type, t); + } +#endif + + p->n_type = t; + p->n_ap = ap; + switch (o) { + case UMUL: + t = INCREF(t); + break; + case ADDROF: + t2 = p->n_left->n_type; + if (p->n_left->n_op == TEMP) { + /* Will be converted to memory in pass2 */ + if (!ISPTR(t2) && DECREF(t) != t2) + ; /* XXX cannot convert this */ + else + p->n_left->n_type = DECREF(t); + return p; + } + if (ISPTR(t2) && !ISPTR(DECREF(t))) + break; /* not quite correct */ + t = DECREF(t); + break; + case PCONV: + return p; + + case PLUSEQ: + case PLUS: + case INCR: + case DECR: + if (!ISPTR(p->n_left->n_type)) { + if (!ISPTR(p->n_right->n_type)) + cerror("no * in PLUS"); + p->n_right = pprop(p->n_right, t, ap); + } else + p->n_left = pprop(p->n_left, t, ap); + return p; + + case MINUSEQ: + case MINUS: + if (ISPTR(p->n_left->n_type)) { + if (ISPTR(p->n_right->n_type)) + break; /* change both */ + p->n_left = pprop(p->n_left, t, ap); + } else + p->n_right = pprop(p->n_right, t, ap); + return p; + + case CALL: + case UCALL: + case STCALL: /* may end up here if struct passed in regs */ + case USTCALL: + return p; + + case STASG: /* if struct is cast to pointer */ + return p; + + case ASSIGN: + break; + + default: + if (coptype(o) == LTYPE) + break; + +#ifdef PCC_DEBUG + fwalk(p, eprint, 0); +#endif + cerror("pprop op error %d\n", o); + } + if (coptype(o) == BITYPE) + p->n_right = pprop(p->n_right, t, ap); + if (coptype(o) != LTYPE) + p->n_left = pprop(p->n_left, t, ap); + return p; +} + +/* + * Search for PCONV's that can be removed while still keeping + * the type correctness. + */ +NODE * +rmpconv(NODE *p) +{ + struct symtab *sp; + int o = p->n_op; + int ot = coptype(o); + NODE *q, *l; + + if (ot != LTYPE) + p->n_left = rmpconv(p->n_left); + if (ot == BITYPE) + p->n_right = rmpconv(p->n_right); + if (o != PCONV) + return p; + l = p->n_left; + if (nncon(l) || (cdope(l->n_op) & CALLFLG)) + ; /* Let any nonamed constant be cast to pointer directly */ + else if (l->n_type >= INTPTR && l->n_op == ICON) { + /* named constants only if >= pointer size */ + /* create INTPTR type */ + sp = l->n_sp; + l->n_sp = NULL; + concast(l, INTPTR); + l->n_sp = sp; + } else if (!ISPTR(l->n_type)) + return p; + q = pprop(p->n_left, p->n_type, p->n_ap); + nfree(p); + return q; +} +#endif + +void +ecode(NODE *p) +{ + /* walk the tree and write out the nodes.. */ + + if (nerrors) + return; + +#ifdef GCC_COMPAT + { + NODE *q = p; + + if (q->n_op == UMUL) + q = p->n_left; + if (cdope(q->n_op)&CALLFLG && + attr_find(q->n_ap, GCC_ATYP_WARN_UNUSED_RESULT)) + werror("return value ignored"); + } +#endif +#ifndef WORD_ADDRESSED + p = rmpconv(p); +#endif + p = optim(p); + p = delasgop(p); + p = deldcall(p, 0); + walkf(p, delvoid, 0); +#ifdef PCC_DEBUG + if (xdebug) { + printf("Fulltree:\n"); + fwalk(p, eprint, 0); + } +#endif + p2tree(p); +#if !defined(MULTIPASS) + send_passt(IP_NODE, p); +#endif +} + +/* + * Send something further on to the next pass. + */ +void +send_passt(int type, ...) +{ + struct interpass *ip; + struct interpass_prolog *ipp; + extern int crslab; + va_list ap; + int sz; + + va_start(ap, type); + if (cftnsp == NULL && type != IP_ASM) { +#ifdef notyet + cerror("no function"); +#endif + if (type == IP_NODE) + tfree(va_arg(ap, NODE *)); + return; + } + if (type == IP_PROLOG || type == IP_EPILOG) + sz = sizeof(struct interpass_prolog); + else + sz = sizeof(struct interpass); + + ip = inlalloc(sz); + ip->type = type; + ip->lineno = lineno; + switch (type) { + case IP_NODE: + ip->ip_node = va_arg(ap, NODE *); + if (ip->ip_node->n_op == LABEL) { + NODE *p = ip->ip_node; + ip->ip_lbl = glval(p->n_left); + ip->type = IP_DEFLAB; + nfree(nfree(p)); + } + break; + case IP_EPILOG: + if (!isinlining) { + locctr(PROG, cftnsp); + defloc(cftnsp); + } + /* FALLTHROUGH */ + case IP_PROLOG: + inftn = type == IP_PROLOG ? 1 : 0; + ipp = (struct interpass_prolog *)ip; + memset(ipp->ipp_regs, (type == IP_PROLOG)? -1 : 0, + sizeof(ipp->ipp_regs)); + ipp->ipp_autos = va_arg(ap, int); + ipp->ipp_name = va_arg(ap, char *); + ipp->ipp_type = va_arg(ap, TWORD); + ipp->ipp_vis = va_arg(ap, int); + ip->ip_lbl = va_arg(ap, int); + ipp->ip_tmpnum = va_arg(ap, int); + ipp->ip_lblnum = crslab; + if (type == IP_PROLOG) + ipp->ip_lblnum--; + break; + case IP_DEFLAB: + ip->ip_lbl = va_arg(ap, int); + break; + case IP_ASM: + if (blevel == 0) { /* outside function */ + printf("%s", va_arg(ap, char *)); + va_end(ap); + locctr(NOSEG, NULL); + return; + } + ip->ip_asm = va_arg(ap, char *); + break; + default: + cerror("bad send_passt type %d", type); + } + va_end(ap); + pass1_lastchance(ip); /* target-specific info */ + if (isinlining) + inline_addarg(ip); + else + pass2_compile(ip); +} + +char * +copst(int op) +{ + if (op <= MAXOP) + return opst[op]; +#define SNAM(x,y) case x: return #y; + switch (op) { + SNAM(QUALIFIER,QUALIFIER) + SNAM(CLASS,CLASS) + SNAM(RB,]) + SNAM(DOT,.) + SNAM(ELLIPSIS,...) + SNAM(LB,[) + SNAM(TYPE,TYPE) + SNAM(COMOP,COMOP) + SNAM(QUEST,?) + SNAM(COLON,:) + SNAM(ANDAND,&&) + SNAM(OROR,||) + SNAM(NOT,!) + SNAM(CAST,CAST) + SNAM(PLUSEQ,+=) + SNAM(MINUSEQ,-=) + SNAM(MULEQ,*=) + SNAM(DIVEQ,/=) + SNAM(MODEQ,%=) + SNAM(ANDEQ,&=) + SNAM(OREQ,|=) + SNAM(EREQ,^=) + SNAM(LSEQ,<<=) + SNAM(RSEQ,>>=) + SNAM(INCR,++) + SNAM(DECR,--) + SNAM(STRING,STRING) + SNAM(SZOF,SIZEOF) + SNAM(ATTRIB,ATTRIBUTE) + SNAM(TYMERGE,TYMERGE) + SNAM(LABEL,LABEL) + SNAM(NEWKW,NEW) + SNAM(NMLIST,::) +#ifdef GCC_COMPAT + SNAM(XREAL,__real__) + SNAM(XIMAG,__imag__) +#endif + default: + cerror("bad copst %d", op); + } + return 0; /* XXX gcc */ +} + +int +cdope(int op) +{ + if (op <= MAXOP) + return dope[op]; + switch (op) { + case CLOP: + case STRING: + case QUALIFIER: + case CLASS: + case RB: + case ELLIPSIS: + case TYPE: + return LTYPE; + case DOT: + case SZOF: + case COMOP: + case QUEST: + case COLON: + case LB: + case TYMERGE: + case NEWKW: + case NMLIST: + return BITYPE; + case XIMAG: + case XREAL: + case ATTRIB: + case LABEL: + return UTYPE; + case ANDAND: + case OROR: + return BITYPE|LOGFLG; + case NOT: + return UTYPE|LOGFLG; + case CAST: + return BITYPE|ASGFLG|ASGOPFLG; + case PLUSEQ: + return BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG; + case MINUSEQ: + return BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG; + case MULEQ: + return BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG; + case OREQ: + case EREQ: + case ANDEQ: + return BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG; + case DIVEQ: + return BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG; + case MODEQ: + return BITYPE|DIVFLG|ASGFLG|ASGOPFLG; + case LSEQ: + case RSEQ: + return BITYPE|SHFFLG|ASGFLG|ASGOPFLG; + case INCR: + case DECR: + return BITYPE|ASGFLG; + } + cerror("cdope missing op %d", op); + return 0; /* XXX gcc */ +} + +/* + * make a fresh copy of p + */ +NODE * +ccopy(NODE *p) +{ + NODE *q; + + q = talloc(); + *q = *p; + + switch (coptype(q->n_op)) { + case BITYPE: + q->n_right = ccopy(p->n_right); + case UTYPE: + q->n_left = ccopy(p->n_left); + } + + return(q); +} + +NODE * +nlabel(int label) +{ + return block(LABEL, bcon(label), NIL, 0, 0, 0); +} + +/* + * set PROG-seg label. + */ +void +plabel(int label) +{ + reached = 1; /* Will this always be correct? */ + send_passt(IP_NODE, nlabel(label)); +} + +/* + * Perform integer promotion on node n. + */ +NODE * +intprom(NODE *n) +{ + if ((n->n_type >= CHAR && n->n_type < INT) || n->n_type == BOOL) { + if ((n->n_type == UCHAR && MAX_UCHAR > MAX_INT) || + (n->n_type == USHORT && MAX_USHORT > MAX_INT)) + return makety(n, UNSIGNED, 0, 0, 0); + return makety(n, INT, 0, 0, 0); + } + return n; +} + +/* + * Return CON/VOL/0, whichever are active for the current type. + */ +int +cqual(TWORD t, TWORD q) +{ + while (ISARY(t)) + t = DECREF(t), q = DECQAL(q); + if (t <= BTMASK) + q <<= TSHIFT; + return q & (CON|VOL); +} + +int crslab = 10; +/* + * Return a number for internal labels. + */ +int +getlab(void) +{ + return crslab++; +} diff --git a/lang/pcc/pcc/cc/driver/Makefile.in b/lang/pcc/pcc/cc/driver/Makefile.in new file mode 100644 index 000000000..69f5a766e --- /dev/null +++ b/lang/pcc/pcc/cc/driver/Makefile.in @@ -0,0 +1,61 @@ +# $Id: Makefile.in,v 1.9 2012/09/25 11:17:17 plunky Exp $ +# +# Makefile.in for the cc driver part of pcc. +# +VPATH=@srcdir@ +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +top_builddir=@top_builddir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +includedir = @includedir@ +datarootdir = @datarootdir@ +mandir = @mandir@ +CC = @CC@ +EXEEXT = @EXEEXT@ +TARGOS = @targos@ +TARGOSVER = @targosver@ +TARGMACH = @targmach@ +TARGET = @target@ +VERSION = @PACKAGE_VERSION@ +PCCLIBDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/lib +PCCINCDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/include +CFLAGS = @CFLAGS@ @ADD_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ -DLIBEXECDIR=\"$(libexecdir)/\" \ + @ADD_CPPFLAGS@ -DINCLUDEDIR=\"$(includedir)/\" \ + -DPCCINCDIR=\"$(PCCINCDIR)/\" -DPCCLIBDIR=\"$(PCCLIBDIR)/\" \ + -DTARGOS=\"$(TARGOS)\" -DTARGOSVER=$(TARGOSVER) -Dos_$(TARGOS) \ + -DTARGMACH=\"$(TARGMACH)\" -Dmach_$(TARGMACH) \ + -I$(top_builddir) -I$(top_srcdir)/os/$(TARGOS) -I$(MIPDIR) -I$(MDIR) +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +OBJS=driver.o platform.o strlist.o xalloc.o +DEST=@BINPREFIX@pcc$(EXEEXT) + +MIPDIR=$(top_srcdir)/mip +MDIR=$(top_srcdir)/arch/$(TARGMACH) + +all: $(DEST) + +$(DEST): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) + +.c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +install: + test -z "$(DESTDIR)$(bindir)" || mkdir -p "$(DESTDIR)$(bindir)" + $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(bindir) + +clean: + rm -f $(OBJS) $(DEST) + +distclean: clean + rm -f Makefile diff --git a/lang/pcc/pcc/cc/driver/driver.c b/lang/pcc/pcc/cc/driver/driver.c new file mode 100644 index 000000000..edbd748d4 --- /dev/null +++ b/lang/pcc/pcc/cc/driver/driver.c @@ -0,0 +1,881 @@ +/* $Id: driver.c,v 1.7 2011/06/03 15:34:01 plunky Exp $ */ + +/*- + * Copyright (c) 2011 Joerg Sonnenberger . + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND 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 + * COPYRIGHT HOLDERS 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "driver.h" +#include "xalloc.h" + +#include "config.h" + +static volatile sig_atomic_t exit_now; +static volatile sig_atomic_t child; + +static void +sigterm_handler(int signum) +{ + exit_now = 1; + if (child) + kill(child, SIGTERM); +} + +static const char versionstr[] = VERSSTR; + +enum phases { DEFAULT, PREPROCESS, COMPILE, ASSEMBLE, LINK } last_phase = + DEFAULT; + +const char *isysroot = NULL; +const char *sysroot = ""; +const char *preprocessor; +const char *compiler; +const char *assembler; +const char *linker; + +struct strlist crtdirs; +static struct strlist user_sysincdirs; +struct strlist sysincdirs; +struct strlist includes; +struct strlist incdirs; +struct strlist libdirs; +struct strlist progdirs; +struct strlist preprocessor_flags; +struct strlist compiler_flags; +struct strlist assembler_flags; +struct strlist early_linker_flags; +struct strlist middle_linker_flags; +struct strlist late_linker_flags; +struct strlist stdlib_flags; +struct strlist early_program_csu_files; +struct strlist late_program_csu_files; +struct strlist early_dso_csu_files; +struct strlist late_dso_csu_files; +struct strlist temp_outputs; + +const char *final_output; +static char *temp_directory; +static struct strlist inputs; + +int pic_mode; /* 0: no PIC, 1: -fpic, 2: -fPIC */ +int save_temps; +int debug_mode; +int profile_mode; +int nostdinc; +int nostdlib; +int nostartfiles; +int static_mode; +int shared_mode; +int use_pthread; +int verbose_mode; + +void +error(const char *fmt, ...) +{ + va_list arg; + va_start(arg, fmt); + vfprintf(stderr, fmt, arg); + putc('\n', stderr); + va_end(arg); + exit(1); +} + +static void +warning(const char *fmt, ...) +{ + va_list arg; + va_start(arg, fmt); + vfprintf(stderr, fmt, arg); + putc('\n', stderr); + va_end(arg); +} + +static void +set_last_phase(enum phases phase) +{ + assert(phase != DEFAULT); + if (last_phase != DEFAULT && phase != last_phase) + error("conflicting compiler options specified"); + last_phase = phase; +} + +static void +expand_sysroot(void) +{ + struct string *s; + struct strlist *lists[] = { &crtdirs, &sysincdirs, &incdirs, + &user_sysincdirs, &libdirs, &progdirs, NULL }; + const char *sysroots[] = { sysroot, isysroot, isysroot, isysroot, + sysroot, sysroot, NULL }; + size_t i, sysroot_len, value_len; + char *path; + + assert(sizeof(lists) / sizeof(lists[0]) == + sizeof(sysroots) / sizeof(sysroots[0])); + + for (i = 0; lists[i] != NULL; ++i) { + STRLIST_FOREACH(s, lists[i]) { + if (s->value[0] != '=') + continue; + sysroot_len = strlen(sysroots[i]); + /* Skipped '=' compensates additional space for '\0' */ + value_len = strlen(s->value); + path = xmalloc(sysroot_len + value_len); + memcpy(path, sysroots[i], sysroot_len); + memcpy(path + sysroot_len, s->value + 1, value_len); + free(s->value); + s->value = path; + } + } +} + +static void +missing_argument(const char *argp) +{ + error("Option `%s' required an argument", argp); +} + +static void +split_and_append(struct strlist *l, char *arg) +{ + char *next; + + for (; arg != NULL; arg = NULL) { + next = strchr(arg, ','); + if (next != NULL) + *next++ = '\0'; + strlist_append(l, arg); + } +} + +static int +strlist_exec(struct strlist *l) +{ + char **argv; + size_t argc; + int result; + + strlist_make_array(l, &argv, &argc); + if (verbose_mode) { + printf("Calling "); + strlist_print(l, stdout); + printf("\n"); + } + + if (exit_now) + return 1; + + switch ((child = fork())) { + case 0: + execvp(argv[0], argv); + result = write(STDERR_FILENO, "Exec of ", 8); + result = write(STDERR_FILENO, argv[0], strlen(argv[0])); + result = write(STDERR_FILENO, "failed\n", 7); + (void)result; + _exit(127); + case -1: + error("fork failed"); + default: + while (waitpid(child, &result, 0) == -1 && errno == EINTR) + /* nothing */(void)0; + result = WEXITSTATUS(result); + if (result) + error("%s terminated with status %d", argv[0], result); + while (argc-- > 0) + free(argv[argc]); + free(argv); + break; + } + return exit_now; +} + +static char * +find_file(const char *file, struct strlist *path, int mode) +{ + struct string *s; + char *f; + size_t lf, lp; + int need_sep; + + lf = strlen(file); + STRLIST_FOREACH(s, path) { + lp = strlen(s->value); + need_sep = (lp && s->value[lp - 1] != '/') ? 1 : 0; + f = xmalloc(lp + lf + need_sep + 1); + memcpy(f, s->value, lp); + if (need_sep) + f[lp] = '/'; + memcpy(f + lp + need_sep, file, lf + 1); + if (access(f, mode) == 0) + return f; + free(f); + } + return xstrdup(file); +} + +static char * +output_name(const char *file, const char *new_suffix, int counter, int last) +{ + const char *old_suffix; + char *name; + size_t lf, ls, len; + int counter_len; + + if (last && final_output) + return xstrdup(final_output); + + old_suffix = strrchr(file, '.'); + if (old_suffix != NULL && strchr(old_suffix, '/') != NULL) + old_suffix = NULL; + if (old_suffix == NULL) + old_suffix = file + strlen(file); + + ls = strlen(new_suffix); + if (save_temps || last) { + lf = old_suffix - file; + name = xmalloc(lf + ls + 1); + memcpy(name, file, lf); + memcpy(name + lf, new_suffix, ls + 1); + return name; + } + if (temp_directory == NULL) { + const char *template; + char *path; + size_t template_len; + int need_sep; + + template = getenv("TMPDIR"); + if (template == NULL) + template = "/tmp"; + template_len = strlen(template); + if (template_len && template[template_len - 1] == '/') + need_sep = 0; + else + need_sep = 1; + path = xmalloc(template_len + need_sep + 6 + 1); + memcpy(path, template, template_len); + if (need_sep) + path[template_len] = '/'; + memcpy(path + template_len + need_sep, "pcc-XXXXXX", 11); + if (mkdtemp(path) == NULL) + error("mkdtemp failed: %s", strerror(errno)); + temp_directory = path; + } + lf = strlen(temp_directory); + counter_len = snprintf(NULL, 0, "%d", counter); + if (counter_len < 1) + error("snprintf failure"); + len = lf + 1 + (size_t)counter_len + ls + 1; + name = xmalloc(len); + snprintf(name, len, "%s/%d%s", temp_directory, counter, new_suffix); + strlist_append(&temp_outputs, name); + return name; +} + +static int +preprocess_input(const char *file, char *input, char **output, + const char *suffix, int counter) +{ + struct strlist args; + struct string *s; + char *out; + int retval; + + strlist_init(&args); + strlist_append_list(&args, &preprocessor_flags); + STRLIST_FOREACH(s, &includes) { + strlist_append(&args, "-i"); + strlist_append(&args, s->value); + } + STRLIST_FOREACH(s, &incdirs) { + strlist_append(&args, "-I"); + strlist_append(&args, s->value); + } + STRLIST_FOREACH(s, &user_sysincdirs) { + strlist_append(&args, "-S"); + strlist_append(&args, s->value); + } + if (!nostdinc) { + STRLIST_FOREACH(s, &sysincdirs) { + strlist_append(&args, "-S"); + strlist_append(&args, s->value); + } + } + strlist_append(&args, input); + if (last_phase == PREPROCESS && final_output == NULL) + out = xstrdup("-"); + else + out = output_name(file, suffix, counter, + last_phase == PREPROCESS); + if (strcmp(out, "-")) + strlist_append(&args, out); + strlist_prepend(&args, find_file(preprocessor, &progdirs, X_OK)); + *output = out; + retval = strlist_exec(&args); + strlist_free(&args); + return retval; +} + +static int +compile_input(const char *file, char *input, char **output, + const char *suffix, int counter) +{ + struct strlist args; + char *out; + int retval; + + strlist_init(&args); + strlist_append_list(&args, &compiler_flags); + if (debug_mode) + strlist_append(&args, "-g"); + if (pic_mode) + strlist_append(&args, "-k"); + if (profile_mode) + warning("-pg is currently ignored"); + strlist_append(&args, input); + out = output_name(file, suffix, counter, last_phase == ASSEMBLE); + strlist_append(&args, out); + strlist_prepend(&args, find_file(compiler, &progdirs, X_OK)); + *output = out; + retval = strlist_exec(&args); + strlist_free(&args); + return retval; +} + +static int +assemble_input(const char *file, char *input, char **output, + const char *suffix, int counter) +{ + struct strlist args; + char *out; + int retval; + + strlist_init(&args); + strlist_append_list(&args, &assembler_flags); + strlist_append(&args, input); + out = output_name(file, ".o", counter, last_phase == COMPILE); + strlist_append(&args, "-o"); + strlist_append(&args, out); + strlist_prepend(&args, find_file(assembler, &progdirs, X_OK)); + *output = out; + retval = strlist_exec(&args); + strlist_free(&args); + return retval; +} + +static int +handle_input(const char *file) +{ + static int counter; + const char *suffix; + char *src; + int handled, retval; + + ++counter; + + if (strcmp(file, "-") == 0) { + /* XXX see -x option */ + suffix = ".c"; + } else { + suffix = strrchr(file, '.'); + if (suffix != NULL && strchr(suffix, '/') != NULL) + suffix = NULL; + if (suffix == NULL) + suffix = ""; + } + + src = xstrdup(file); + if (strcmp(suffix, ".c") == 0) { + suffix = ".i"; + retval = preprocess_input(file, src, &src, suffix, counter); + if (retval) + return retval; + handled = 1; + } else if (strcmp(suffix, ".S") == 0) { + suffix = ".s"; + retval = preprocess_input(file, src, &src, suffix, counter); + if (retval) + return retval; + handled = 1; + } + + if (last_phase == PREPROCESS) + goto done; + + if (strcmp(suffix, ".i") == 0) { + suffix = ".s"; + retval = compile_input(file, src, &src, suffix, counter); + if (retval) + return retval; + handled = 1; + } + if (last_phase == ASSEMBLE) + goto done; + + if (strcmp(suffix, ".s") == 0) { + suffix = ".o"; + retval = assemble_input(file, src, &src, suffix, counter); + if (retval) + return retval; + handled = 1; + } + if (last_phase == COMPILE) + goto done; + if (strcmp(suffix, ".o") == 0) + handled = 1; + strlist_append(&middle_linker_flags, src); +done: + if (handled) + return 0; + if (last_phase == LINK) + warning("unknown suffix %s, passing file down to linker", + suffix); + else + warning("unknown suffix %s, skipped", suffix); + free(src); + return 0; +} + +static int +run_linker(void) +{ + struct strlist linker_flags; + struct strlist *early_csu, *late_csu; + struct string *s; + int retval; + + if (final_output) { + strlist_prepend(&early_linker_flags, final_output); + strlist_prepend(&early_linker_flags, "-o"); + } + if (!nostdlib) + strlist_append_list(&late_linker_flags, &stdlib_flags); + if (!nostartfiles) { + if (shared_mode) { + early_csu = &early_dso_csu_files; + late_csu = &late_dso_csu_files; + } else { + early_csu = &early_program_csu_files; + late_csu = &late_program_csu_files; + } + STRLIST_FOREACH(s, early_csu) + strlist_append_nocopy(&middle_linker_flags, + find_file(s->value, &crtdirs, R_OK)); + STRLIST_FOREACH(s, late_csu) + strlist_append_nocopy(&late_linker_flags, + find_file(s->value, &crtdirs, R_OK)); + } + strlist_init(&linker_flags); + strlist_append_list(&linker_flags, &early_linker_flags); + strlist_append_list(&linker_flags, &middle_linker_flags); + strlist_append_list(&linker_flags, &late_linker_flags); + strlist_prepend(&linker_flags, find_file(linker, &progdirs, X_OK)); + + retval = strlist_exec(&linker_flags); + + strlist_free(&linker_flags); + return retval; +} + +static void +cleanup(void) +{ + struct string *file; + + STRLIST_FOREACH(file, &temp_outputs) { + if (unlink(file->value) == -1) + warning("removal of ``%s'' failed: %s", file->value, + strerror(errno)); + } + if (temp_directory && rmdir(temp_directory) == -1) + warning("removal of ``%s'' failed: %s", temp_directory, + strerror(errno)); +} + +int +main(int argc, char **argv) +{ + struct string *input; + char *argp; + int retval; + + strlist_init(&crtdirs); + strlist_init(&user_sysincdirs); + strlist_init(&sysincdirs); + strlist_init(&incdirs); + strlist_init(&includes); + strlist_init(&libdirs); + strlist_init(&progdirs); + strlist_init(&inputs); + strlist_init(&preprocessor_flags); + strlist_init(&compiler_flags); + strlist_init(&assembler_flags); + strlist_init(&early_linker_flags); + strlist_init(&middle_linker_flags); + strlist_init(&late_linker_flags); + strlist_init(&stdlib_flags); + strlist_init(&early_program_csu_files); + strlist_init(&late_program_csu_files); + strlist_init(&early_dso_csu_files); + strlist_init(&late_dso_csu_files); + strlist_init(&temp_outputs); + + init_platform_specific(TARGOS, TARGMACH); + + while (--argc) { + ++argv; + argp = *argv; + + if (*argp != '-' || strcmp(argp, "-") == 0) { + strlist_append(&inputs, argp); + continue; + } + switch (argp[1]) { + case '-': + if (strcmp(argp, "--param") == 0) { + if (argc == 0) + missing_argument(argp); + --argc; + ++argv; + /* Unused */ + continue; + } + if (strncmp(argp, "--sysroot=", 10) == 0) { + sysroot = argp + 10; + continue; + } + if (strcmp(argp, "--version") == 0) { + printf("%s\n", versionstr); + exit(0); + } + break; + case 'B': + strlist_append(&crtdirs, argp); + strlist_append(&libdirs, argp); + strlist_append(&progdirs, argp); + continue; + case 'C': + if (argp[2] == '\0') { + strlist_append(&preprocessor_flags, argp); + continue; + } + break; + case 'c': + if (argp[2] == '\0') { + set_last_phase(COMPILE); + continue; + } + break; + case 'D': + strlist_append(&preprocessor_flags, argp); + if (argp[2] == '\0') { + if (argc == 0) + missing_argument(argp); + --argc; + ++argv; + strlist_append(&preprocessor_flags, argp); + } + continue; + case 'E': + if (argp[2] == '\0') { + set_last_phase(PREPROCESS); + continue; + } + break; + case 'f': + if (strcmp(argp, "-fpic") == 0) { + pic_mode = 1; + continue; + } + if (strcmp(argp, "-fPIC") == 0) { + pic_mode = 2; + continue; + } + /* XXX GCC options */ + break; + case 'g': + if (argp[2] == '\0') { + debug_mode = 1; + continue; + } + /* XXX allow variants like -g1? */ + break; + case 'I': + if (argp[2] == '\0') { + if (argc == 0) + missing_argument(argp); + --argc; + ++argv; + strlist_append(&incdirs, argp); + continue; + } + strlist_append(&incdirs, argp + 2); + continue; + case 'i': + if (strcmp(argp, "-isystem") == 0) { + if (argc == 0) + missing_argument(argp); + --argc; + ++argv; + strlist_append(&user_sysincdirs, argp); + continue; + } + if (strcmp(argp, "-include") == 0) { + if (argc == 0) + missing_argument(argp); + --argc; + ++argv; + strlist_append(&includes, argp); + continue; + } + if (strcmp(argp, "-isysroot") == 0) { + if (argc == 0) + missing_argument(argp); + --argc; + ++argv; + isysroot = argp; + continue; + } + /* XXX -idirafter */ + /* XXX -iquote */ + break; + case 'k': + if (argp[2] == '\0') { + pic_mode = 1; + continue; + } + break; + case 'M': + if (argp[2] == '\0') { + strlist_append(&preprocessor_flags, argp); + continue; + } + break; + case 'm': + /* XXX implement me */ + break; + case 'n': + if (strcmp(argp, "-nostdinc") == 0) { + nostdinc = 1; + continue; + } + if (strcmp(argp, "-nostdinc++") == 0) + continue; + if (strcmp(argp, "-nostdlib") == 0) { + nostdlib = 1; + nostartfiles = 1; + continue; + } + if (strcmp(argp, "-nostartfiles") == 0) { + nostartfiles = 1; + continue; + } + break; + case 'O': + if (argp[2] != '\0' && argp[3] != '\0') + break; + switch(argp[2]) { + case '2': + case '1': case '\0': + strlist_append(&compiler_flags, "-xtemps"); + strlist_append(&compiler_flags, "-xdeljumps"); + strlist_append(&compiler_flags, "-xinline"); + case '0': + continue; + } + break; + case 'o': + if (argp[2] == '\0') { + if (argc == 0) + missing_argument(argp); + --argc; + ++argv; + if (final_output) + error("Only one `-o' option allowed"); + final_output = *argv; + continue; + } + break; + case 'p': + if (argp[2] == '\0' || strcmp(argp, "-pg") == 0) { + profile_mode = 1; + continue; + } + if (strcmp(argp, "-pedantic") == 0) + continue; + if (strcmp(argp, "-pipe") == 0) + continue; /* XXX implement me */ + if (strcmp(argp, "-pthread") == 0) { + use_pthread = 1; + continue; + } + /* XXX -print-prog-name=XXX */ + /* XXX -print-multi-os-directory */ + break; + case 'r': + if (argp[2] == '\0') { + strlist_append(&middle_linker_flags, argp); + continue; + } + break; + case 'S': + if (argp[2] == '\0') { + set_last_phase(ASSEMBLE); + continue; + } + break; + case 's': + if (strcmp(argp, "-save-temps") == 0) { + save_temps = 1; + continue; + } + if (strcmp(argp, "-shared") == 0) { + shared_mode = 1; + continue; + } + if (strcmp(argp, "-static") == 0) { + static_mode = 1; + continue; + } + if (strncmp(argp, "-std=", 5) == 0) + continue; /* XXX sanitize me */ + break; + case 't': + if (argp[2] == '\0') { + strlist_append(&preprocessor_flags, argp); + continue; + } + case 'U': + strlist_append(&preprocessor_flags, argp); + if (argp[2] == '\0') { + if (argc == 0) + missing_argument(argp); + --argc; + ++argv; + strlist_append(&preprocessor_flags, argp); + } + continue; + case 'v': + if (argp[2] == '\0') { + verbose_mode = 1; + continue; + } + break; + case 'W': + if (strncmp(argp, "-Wa,", 4) == 0) { + split_and_append(&assembler_flags, argp + 4); + continue; + } + if (strncmp(argp, "-Wl,", 4) == 0) { + split_and_append(&middle_linker_flags, argp + 4); + continue; + } + if (strncmp(argp, "-Wp,", 4) == 0) { + split_and_append(&preprocessor_flags, argp + 4); + continue; + } + /* XXX warning flags */ + break; + case 'x': + /* XXX -x c */ + /* XXX -c assembler-with-cpp */ + break; + } + error("unknown flag `%s'", argp); + } + + if (last_phase == DEFAULT) + last_phase = LINK; + + if (verbose_mode) + printf("%s\n", versionstr); + + if (isysroot == NULL) + isysroot = sysroot; + expand_sysroot(); + + if (last_phase != LINK && final_output && !STRLIST_EMPTY(&inputs) && + !STRLIST_NEXT(STRLIST_FIRST(&inputs))) + error("-o specified with more than one input"); + + if (last_phase == PREPROCESS && final_output == NULL) + final_output = "-"; + + if (STRLIST_EMPTY(&inputs)) + error("No input specificed"); + + retval = 0; + + signal(SIGTERM, sigterm_handler); + + STRLIST_FOREACH(input, &inputs) { + if (handle_input(input->value)) + retval = 1; + } + if (!retval && last_phase == LINK) { + if (run_linker()) + retval = 1; + } + + if (exit_now) + warning("Received signal, terminating"); + + cleanup(); + + strlist_free(&crtdirs); + strlist_free(&user_sysincdirs); + strlist_free(&sysincdirs); + strlist_free(&incdirs); + strlist_free(&includes); + strlist_free(&libdirs); + strlist_free(&progdirs); + strlist_free(&inputs); + strlist_free(&preprocessor_flags); + strlist_free(&compiler_flags); + strlist_free(&assembler_flags); + strlist_free(&early_linker_flags); + strlist_free(&middle_linker_flags); + strlist_free(&late_linker_flags); + strlist_free(&stdlib_flags); + strlist_free(&early_program_csu_files); + strlist_free(&late_program_csu_files); + strlist_free(&early_dso_csu_files); + strlist_free(&late_dso_csu_files); + strlist_free(&temp_outputs); + + return retval; +} diff --git a/lang/pcc/pcc/cc/driver/driver.h b/lang/pcc/pcc/cc/driver/driver.h new file mode 100644 index 000000000..cf7ad49eb --- /dev/null +++ b/lang/pcc/pcc/cc/driver/driver.h @@ -0,0 +1,64 @@ +/* $Id: driver.h,v 1.2 2011/05/26 16:48:40 plunky Exp $ */ + +/*- + * Copyright (c) 2011 Joerg Sonnenberger . + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND 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 + * COPYRIGHT HOLDERS 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 DRIVER_H +#define DRIVER_H + +#include "strlist.h" + +extern const char *isysroot; +extern const char *sysroot; +extern const char *preprocessor; +extern const char *compiler; +extern const char *assembler; +extern const char *linker; + +extern struct strlist crtdirs; +extern struct strlist sysincdirs; +extern struct strlist libdirs; +extern struct strlist progdirs; +extern struct strlist preprocessor_flags; +extern struct strlist compiler_flags; +extern struct strlist assembler_flags; +extern struct strlist early_linker_flags; +extern struct strlist middle_linker_flags; +extern struct strlist late_linker_flags; +extern struct strlist stdlib_flags; +extern struct strlist early_program_csu_files; +extern struct strlist late_program_csu_files; +extern struct strlist early_dso_csu_files; +extern struct strlist late_dso_csu_files; + +void error(const char *fmt, ...); + +void init_platform_specific(const char *, const char *); + +#endif /* DRIVER_H */ diff --git a/lang/pcc/pcc/cc/driver/platform.c b/lang/pcc/pcc/cc/driver/platform.c new file mode 100644 index 000000000..54aa253ec --- /dev/null +++ b/lang/pcc/pcc/cc/driver/platform.c @@ -0,0 +1,320 @@ +/* $Id: platform.c,v 1.5 2012/08/09 11:41:28 ragge Exp $ */ + +/*- + * Copyright (c) 2011 Joerg Sonnenberger . + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND 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 + * COPYRIGHT HOLDERS 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 + +#include "driver.h" +#include "config.h" + +#include "ccconfig.h" + +#ifndef NEW_DRIVER_CFG +#define USE_OLD_DRIVER_CFG +#endif + +#define _MKS(x) #x +#define MKS(x) _MKS(x) + +#ifndef PREPROCESSOR +#define PREPROCESSOR "cpp" +#endif + +#ifndef COMPILER +#define COMPILER "ccom" +#endif + +#ifndef ASSEMBLER +#define ASSEMBLER "as" +#endif + +#ifndef LINKER +#define LINKER "ld" +#endif + +enum architecture { + ARCH_ANY, + ARCH_I386, + ARCH_X86_64 +}; + +static const struct { + enum architecture arch; + const char *name; +} arch_mapping[] = { +#ifdef USE_OLD_DRIVER_CFG + { ARCH_ANY, TARGMACH }, +#else + { ARCH_I386, "i386" }, + { ARCH_X86_64, "x86_64" } , +#endif +}; + +enum os { + OS_ANY, + OS_NETBSD, + OS_LINUX +}; + +static const struct { + enum os os; + const char *name; +} os_mapping[] = { +#ifdef USE_OLD_DRIVER_CFG + { OS_ANY, TARGOS }, +#else + { OS_NETBSD, "netbsd" }, + { OS_LINUX, "linux" }, +#endif +}; + +struct platform_specific { + enum architecture arch; + enum os os; + const char * const *values; +}; + +#ifndef USE_OLD_DRIVER_CFG +static const char * const early_program_csu_values0[] = { "crt0.o", NULL }; +static const char * const early_program_csu_values1[] = { "crt1.o", NULL }; +#else +static const char * const early_program_csu_values2[] = { + CRT0FILE, NULL +}; +#endif + +static const struct platform_specific early_program_csu[] = { +#ifdef USE_OLD_DRIVER_CFG + { ARCH_ANY, OS_ANY, early_program_csu_values2 }, +#else + { ARCH_ANY, OS_NETBSD, early_program_csu_values0 }, + { ARCH_ANY, OS_LINUX, early_program_csu_values1 }, +#endif +}; + +static const char * const late_program_csu_values0[] = { + "crtend.o", "crtn.o", NULL +}; +static const struct platform_specific late_program_csu[] = { + { ARCH_ANY, OS_ANY, late_program_csu_values0 }, +}; + +static const char * const early_dso_csu_values0[] = { + "crtio", "crtbeginS.o", NULL +}; +static const struct platform_specific early_dso_csu[] = { + { ARCH_ANY, OS_ANY, early_dso_csu_values0 }, +}; + +static const char * const late_dso_csu_values0[] = { + "crtendS.o", "crtn.o", NULL +}; +static const struct platform_specific late_dso_csu[] = { + { ARCH_ANY, OS_ANY, late_dso_csu_values0 }, +}; + +static const char * const predefined_macros_values0[] = { + "-D__x86_64__", "-D__x86_64", "-D__amd64__", "-D__amd64", NULL +}; +static const char * const predefined_macros_values1[] = { + "-D__NetBSD__", "-D__ELF__", NULL +}; +static const char * const predefined_macros_values2[] = { + "-D__linux__", "-D__ELF__", NULL +}; +static const char * const predefined_macros_values3[] = { + "-D__i386__", NULL +}; +static const char * const predefined_macros_values4[] = { + "-D__PCC__=" MKS(PCC_MAJOR), + "-D__PCC_MINOR__=" MKS(PCC_MINOR), + "-D__PCC_MINORMINOR__=" MKS(PCC_MINORMINOR), + "-D__VERSION__=" MKS(VERSSTR), + "-D__STDC_ISO_10646__=200009L", + NULL +}; +static const char * const predefined_macros_values5[] = { + "-D__GNUC__=4", + "-D__GNUC_MINOR__=3", + "-D__GNUC_PATCHLEVEL__=1", + "-D__GNUC_STDC_INLINE__=1", + NULL +}; +static const struct platform_specific predefined_macros[] = { + { ARCH_X86_64, OS_ANY, predefined_macros_values0 }, + { ARCH_ANY, OS_NETBSD, predefined_macros_values1 }, + { ARCH_ANY, OS_LINUX, predefined_macros_values2 }, + { ARCH_I386, OS_ANY, predefined_macros_values3 }, + { ARCH_ANY, OS_ANY, predefined_macros_values4 }, + { ARCH_ANY, OS_ANY, predefined_macros_values5 }, +}; + +static const char * const early_linker_values0[] = { + "-dynamic-linker", "/libexec/ld.elf_so", NULL +}; +static const char * const early_linker_values1[] = { + "-m", "elf_i386", NULL +}; +static const char * const early_linker_values2[] = { + "-m", "elf_x86_64", NULL +}; +static const char * const early_linker_values3[] = { + "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", NULL +}; +static const char * const early_linker_values4[] = { + "-m", "elf_i386", NULL +}; +static const char * const early_linker_values5[] = { + "-m", "elf_x86_64", NULL +}; +static const struct platform_specific early_linker[] = { + { ARCH_ANY, OS_NETBSD, early_linker_values0 }, + { ARCH_I386, OS_NETBSD, early_linker_values1 }, + { ARCH_X86_64, OS_NETBSD, early_linker_values2 }, + { ARCH_ANY, OS_LINUX, early_linker_values3 }, + { ARCH_I386, OS_LINUX, early_linker_values4 }, + { ARCH_X86_64, OS_LINUX, early_linker_values5 }, +}; + +static const char * const sysincdir_list_values0[] = { + "=/usr/include", NULL +}; +static const char * const sysincdir_list_values1[] = { + /* XXX fix up for libpcc? */ + "=/usr/lib/gcc/x86_64-linux-gnu/4.4/include", NULL +}; +static const struct platform_specific sysincdir_list[] = { + { ARCH_ANY, OS_ANY, sysincdir_list_values0 }, + { ARCH_X86_64, OS_LINUX, sysincdir_list_values1 }, +}; + +static const char * const crtdir_list_values0[] = { + "=/usr/lib/i386", "=/usr/lib", NULL +}; +static const char * const crtdir_list_values1[] = { + "=/usr/lib", NULL +}; +static const char * const crtdir_list_values2[] = { + "=/usr/lib64", "=/usr/lib/gcc/x86_64-linux-gnu/4.4", NULL +}; +static const struct platform_specific crtdir_list[] = { + { ARCH_I386, OS_NETBSD, crtdir_list_values0 }, + { ARCH_X86_64, OS_NETBSD, crtdir_list_values1 }, + { ARCH_X86_64, OS_LINUX, crtdir_list_values2 }, +}; + +static const char * const stdlib_list_values0[] = { + "-L/usr/lib/gcc/x86_64-linux-gnu/4.4", NULL +}; +static const char * const stdlib_list_values1[] = { + "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", + "-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", NULL +}; +static const struct platform_specific stdlib_list[] = { + { ARCH_X86_64, OS_LINUX, stdlib_list_values0 }, + { ARCH_ANY, OS_ANY, stdlib_list_values1 }, +}; + +static const char * const program_dirs_values0[] = { + LIBEXECDIR, NULL +}; +static const struct platform_specific program_dirs[] = { + { ARCH_ANY, OS_ANY, program_dirs_values0 }, +}; + +#define ARRAYLEN(a) (sizeof(a) / sizeof((a)[0])) +#define ARRAYPAIR(a) a, ARRAYLEN(a) + +static const struct { + const struct platform_specific *initializer; + size_t len; + struct strlist *list; +} platform_specific_inits[] = { + { ARRAYPAIR(early_program_csu), &early_program_csu_files }, + { ARRAYPAIR(late_program_csu), &late_program_csu_files }, + { ARRAYPAIR(early_dso_csu), &early_dso_csu_files }, + { ARRAYPAIR(late_dso_csu), &late_dso_csu_files }, + { ARRAYPAIR(predefined_macros), &preprocessor_flags }, + { ARRAYPAIR(early_linker), &early_linker_flags }, + { ARRAYPAIR(sysincdir_list), &sysincdirs }, + { ARRAYPAIR(crtdir_list), &crtdirs }, + { ARRAYPAIR(stdlib_list), &stdlib_flags }, + { ARRAYPAIR(program_dirs), &progdirs }, +}; + +void +init_platform_specific(const char *os_name, const char *arch_name) +{ + enum os os; + enum architecture arch; + size_t i, j, len; + const struct platform_specific *initializer; + struct strlist *l; + + os = OS_ANY; + for (i = 0; i < ARRAYLEN(os_mapping); ++i) { + if (strcmp(os_mapping[i].name, os_name) == 0) { + os = os_mapping[i].os; + break; + } + } + if (os == OS_ANY) + error("unknown Operating System: %s", os_name); + + arch = ARCH_ANY; + for (i = 0; i < ARRAYLEN(arch_mapping); ++i) { + if (strcmp(arch_mapping[i].name, arch_name) == 0) { + arch = arch_mapping[i].arch; + break; + } + } + if (arch == ARCH_ANY) + error("unknown architecture: %s", arch_name); + + for (i = 0; i < ARRAYLEN(platform_specific_inits); ++i) { + initializer = platform_specific_inits[i].initializer; + len = platform_specific_inits[i].len; + l = platform_specific_inits[i].list; + for (j = 0; j < len; ++j) { + if (initializer[j].arch != arch && + initializer[j].arch != ARCH_ANY) + continue; + if (initializer[j].os != os && + initializer[j].os != OS_ANY) + continue; + strlist_append_array(l, initializer[j].values); + } + } + + preprocessor = PREPROCESSOR; + compiler = COMPILER; + assembler = ASSEMBLER; + linker = LINKER; +} diff --git a/lang/pcc/pcc/cc/driver/strlist.c b/lang/pcc/pcc/cc/driver/strlist.c new file mode 100644 index 000000000..dca468cf8 --- /dev/null +++ b/lang/pcc/pcc/cc/driver/strlist.c @@ -0,0 +1,193 @@ +/* $Id: strlist.c,v 1.3 2014/12/24 09:55:32 plunky Exp $ */ + +/*- + * Copyright (c) 2011 Joerg Sonnenberger . + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND 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 + * COPYRIGHT HOLDERS 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 +#include "strlist.h" +#include "xalloc.h" + +void +strlist_init(struct strlist *l) +{ + l->first = l->last = NULL; +} + +void +strlist_free(struct strlist *l) +{ + struct string *s1, *s2; + + STRLIST_FOREACH_MUTABLE(s1, l, s2) { + free(s1->value); + free(s1); + } + l->first = l->last = NULL; +} + +void +strlist_make_array(const struct strlist *l, char ***a, size_t *len) +{ + const struct string *s; + char **i; + + *len = 0; + + STRLIST_FOREACH(s, l) + ++*len; + + *a = xcalloc(*len + 1, sizeof(*i)); + i = *a; + + STRLIST_FOREACH(s, l) + *i++ = xstrdup(s->value); + *i = NULL; +} + +void +strlist_print(const struct strlist *l, FILE *f, int esc) +{ + const struct string *s; + int quote, first = 1; + const char *p; + + STRLIST_FOREACH(s, l) { + if (!first) + putc(' ', f); + quote = 0; + if (esc) { + for (p = s->value; *p; p++) { + if ((*p >= '0' && *p <= '9') + || (*p >= 'a' && *p <= 'z') + || (*p >= 'A' && *p <= 'Z') + || *p == '.' || *p == '/' + || *p == '-' || *p == '_') + continue; + quote = 1; + break; + } + } + if (quote) + putc('"', f); + for (p = s->value; *p; p++) { + if (quote && (*p == '"' || *p == '$' + || *p == '\\' || *p == '`')) + putc('\\', f); + putc(*p, f); + } + if (quote) + putc('"', f); + first = 0; + } +} + +void +strlist_append_nocopy(struct strlist *l, char *val) +{ + struct string *s; + + s = xmalloc(sizeof(*s)); + s->next = NULL; + s->value = val; + if (l->last != NULL) { + l->last->next = s; + l->last = s; + } else { + l->last = s; + l->first = s; + } +} + +void +strlist_append(struct strlist *l, const char *val) +{ + strlist_append_nocopy(l, xstrdup(val)); +} + +void +strlist_append_list(struct strlist *l, const struct strlist *l2) +{ + struct string *s; + + STRLIST_FOREACH(s, l2) + strlist_append(l, s->value); +} + +void +strlist_append_array(struct strlist *l, const char * const *strings) +{ + for (; *strings != NULL; ++strings) + strlist_append(l, *strings); +} + +void +strlist_prepend_nocopy(struct strlist *l, char *val) +{ + struct string *s; + + s = xmalloc(sizeof(*s)); + s->next = l->first; + s->value = val; + l->first = s; + if (l->last == NULL) { + l->last = s; + } +} + +void +strlist_prepend(struct strlist *l, const char *val) +{ + strlist_prepend_nocopy(l, xstrdup(val)); +} + +void +strlist_prepend_list(struct strlist *l, const struct strlist *l2) +{ + struct string *s, *s2, *s3, *s4; + + if (STRLIST_EMPTY(l2)) + return; + + if (STRLIST_EMPTY(l)) { + strlist_append_list(l, l2); + return; + } + + s2 = NULL; + s4 = l->first; + STRLIST_FOREACH(s, l2) { + s3 = xmalloc(sizeof(*s3)); + s3->value = xstrdup(s->value); + s3->next = s4; + if (s2 == NULL) + l->first = s3; + else + s2->next = s3; + } +} diff --git a/lang/pcc/pcc/cc/driver/strlist.h b/lang/pcc/pcc/cc/driver/strlist.h new file mode 100644 index 000000000..9a73dd4fa --- /dev/null +++ b/lang/pcc/pcc/cc/driver/strlist.h @@ -0,0 +1,73 @@ +/* $Id: strlist.h,v 1.3 2014/12/24 09:55:32 plunky Exp $ */ + +/*- + * Copyright (c) 2011 Joerg Sonnenberger . + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND 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 + * COPYRIGHT HOLDERS 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 STRLIST_H +#define STRLIST_H + +#include +#include + +struct string { + struct string *next; + char *value; +}; + +struct strlist { + struct string *first; + struct string *last; +}; + +void strlist_init(struct strlist *); +void strlist_free(struct strlist *); +void strlist_make_array(const struct strlist *, char ***, size_t *); +void strlist_print(const struct strlist *, FILE *, int); + +void strlist_prepend(struct strlist *, const char *); +void strlist_prepend_nocopy(struct strlist *, char *); +void strlist_prepend_list(struct strlist *, const struct strlist *); +void strlist_append(struct strlist *, const char *); +void strlist_append_nocopy(struct strlist *, char *); +void strlist_append_list(struct strlist *, const struct strlist *); +void strlist_append_array(struct strlist *, const char * const *); + +#define STRLIST_FIRST(head) ((head)->first) +#define STRLIST_NEXT(elem) ((elem)->next) +#define STRLIST_FOREACH(var, head) \ + for ((var) = STRLIST_FIRST(head); \ + (var) != NULL; \ + (var) = STRLIST_NEXT(var)) +#define STRLIST_FOREACH_MUTABLE(var, head, var2) \ + for ((var) = STRLIST_FIRST(head); \ + (var) != NULL && ((var2) = STRLIST_NEXT(var), 1); \ + (var) = (var2)) +#define STRLIST_EMPTY(head) (STRLIST_FIRST(head) == NULL) + +#endif /* STRLIST_H */ diff --git a/lang/pcc/pcc/cc/driver/xalloc.c b/lang/pcc/pcc/cc/driver/xalloc.c new file mode 100644 index 000000000..0ca4533cf --- /dev/null +++ b/lang/pcc/pcc/cc/driver/xalloc.c @@ -0,0 +1,83 @@ +/* $Id: xalloc.c,v 1.2 2011/05/26 16:48:40 plunky Exp $ */ + +/*- + * Copyright (c) 2011 Joerg Sonnenberger . + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND 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 + * COPYRIGHT HOLDERS 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 +#include +#include + +#include "xalloc.h" + +static void +error(const char *str) +{ + fprintf(stderr, "%s\n", str); + exit(1); +} + +void * +xcalloc(size_t elem, size_t len) +{ + void *ptr; + + if ((ptr = calloc(elem, len)) == NULL) + error("calloc failed"); + return ptr; +} + +void * +xmalloc(size_t len) +{ + void *ptr; + + if ((ptr = malloc(len)) == NULL) + error("malloc failed"); + return ptr; +} + +void * +xrealloc(void *buf, size_t len) +{ + void *ptr; + + if ((ptr = realloc(buf, len)) == NULL) + error("realloc failed"); + return ptr; +} + +char * +xstrdup(const char *str) +{ + char *buf; + + if ((buf = strdup(str)) == NULL) + error("strdup failed"); + return buf; +} diff --git a/lang/pcc/pcc/cc/driver/xalloc.h b/lang/pcc/pcc/cc/driver/xalloc.h new file mode 100644 index 000000000..b90434d9c --- /dev/null +++ b/lang/pcc/pcc/cc/driver/xalloc.h @@ -0,0 +1,42 @@ +/* $Id: xalloc.h,v 1.2 2011/05/26 16:48:40 plunky Exp $ */ + +/*- + * Copyright (c) 2011 Joerg Sonnenberger . + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND 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 + * COPYRIGHT HOLDERS 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 XALLOC_H +#define XALLOC_H + +#include + +void *xcalloc(size_t, size_t); +void *xmalloc(size_t); +void *xrealloc(void *, size_t); +char *xstrdup(const char *); + +#endif /* XALLOC_H */ diff --git a/lang/pcc/pcc/common/compat.c b/lang/pcc/pcc/common/compat.c new file mode 100644 index 000000000..e341ab314 --- /dev/null +++ b/lang/pcc/pcc/common/compat.c @@ -0,0 +1,842 @@ +/* + * Copyright (c) 1998 Todd C. Miller + * All rights reserved. + * + * 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. + * 3. The name of the author 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 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 AUTHOR 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. + * + * $Id: compat.c,v 1.13 2015/07/24 08:26:05 ragge Exp $ + */ + +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * 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 REGENTS 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. + * + * $NetBSD: gettemp.c,v 1.13 2003/12/05 00:57:36 uebayasi Exp $ + */ + +#include + +#include "config.h" +#include "compat.h" + +#ifndef HAVE_STRLCAT +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(initial dst) + strlen(src); if retval >= siz, + * truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} +#endif + + +#ifndef HAVE_STRLCPY +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} +#endif + +#ifndef HAVE_GETOPT +char *optarg; +int optind = 1; +int +getopt(int argc, char * const argv[], const char *args) +{ + int n; + int nlen = strlen(args); + char cmd; + char rv; + + if (argv[optind] && *argv[optind] == '-') { + cmd = *(argv[optind] + 1); + + for (n = 0; n < nlen; n++) { + if (args[n] == ':') + continue; + if (args[n] == cmd) { + rv = *(argv[optind] + 1); + if (args[n+1] == ':') { + if (*(argv[optind] + 2) != '\0') { + optarg = argv[optind] + 2; + optind += 1; + } else { + optarg = argv[optind + 1]; + optind += 2; + } + if (!optarg) + optarg=""; + return rv; + } else { + optarg = NULL; + optind += 1; + return rv; + } + } + } + } + + return -1; +} +#endif + +#if !defined(HAVE_MKSTEMP) && !defined(_WIN32) +#include /* open() */ +#include /* getpid() */ + +int +mkstemp(char *path) +{ + char *trv; + unsigned int pid; + + /* To guarantee multiple calls generate unique names even if + the file is not created. 676 different possibilities with 7 + or more X's, 26 with 6 or less. */ + static char xtra[2] = "aa"; + int xcnt = 0; + + pid = getpid(); + + /* Move to end of path and count trailing X's. */ + for (trv = path; *trv; ++trv) + if (*trv == 'X') + xcnt++; + else + xcnt = 0; + + /* Use at least one from xtra. Use 2 if more than 6 X's. */ + if (*(trv - 1) == 'X') + *--trv = xtra[0]; + if (xcnt > 6 && *(trv - 1) == 'X') + *--trv = xtra[1]; + + /* Set remaining X's to pid digits with 0's to the left. */ + while (*--trv == 'X') { + *trv = (pid % 10) + '0'; + pid /= 10; + } + + /* update xtra for next call. */ + if (xtra[0] != 'z') + xtra[0]++; + else { + xtra[0] = 'a'; + if (xtra[1] != 'z') + xtra[1]++; + else + xtra[1] = 'a'; + } + + return open(path, O_CREAT | O_EXCL | O_RDWR, 0600); +} +#endif + +#ifndef HAVE_FFS +int +ffs(int x) +{ + int r = 1; + if (!x) return 0; + if (!(x & 0xffff)) { x >>= 16; r += 16; } + if (!(x & 0xff)) { x >>= 8; r += 8; } + if (!(x & 0xf)) { x >>= 4; r += 4; } + if (!(x & 3)) { x >>= 2; r += 2; } + if (!(x & 1)) { x >>= 1; r += 1; } + + return r; +} +#endif + +/* + * Copyright Patrick Powell 1995 + * This code is based on code written by Patrick Powell (papowell@astart.com) + * It may be used for any purpose as long as this notice remains intact + * on all source code distributions + */ + +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) +#include /* isdigit() */ + +static void +dopr(char *buffer, size_t maxlen, const char *format, va_list args); + +static void +fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, + int min, int max); + +static void +fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, + int min, int max, int flags); + +static void +fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, + int min, int max, int flags); + +static void +dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); + +/* + * dopr(): poor man's version of doprintf + */ + +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_CONV 6 +#define DP_S_DONE 7 + +/* format flags - Bits */ +#define DP_F_MINUS (1 << 0) +#define DP_F_PLUS (1 << 1) +#define DP_F_SPACE (1 << 2) +#define DP_F_NUM (1 << 3) +#define DP_F_ZERO (1 << 4) +#define DP_F_UP (1 << 5) +#define DP_F_UNSIGNED (1 << 6) + +/* Conversion Flags */ +#define DP_C_SHORT 1 +#define DP_C_LONG 2 +#define DP_C_LDOUBLE 3 +#define DP_C_LONG_LONG 4 + +#define char_to_int(p) (p - '0') +#define abs_val(p) (p < 0 ? -p : p) + + +static void +dopr(char *buffer, size_t maxlen, const char *format, va_list args) +{ + char *strvalue, ch; + long value; + long double fvalue; + int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0; + size_t currlen = 0; + + ch = *format++; + + while (state != DP_S_DONE) { + if ((ch == '\0') || (currlen >= maxlen)) + state = DP_S_DONE; + + switch(state) { + case DP_S_DEFAULT: + if (ch == '%') + state = DP_S_FLAGS; + else + dopr_outch(buffer, &currlen, maxlen, ch); + ch = *format++; + break; + case DP_S_FLAGS: + switch (ch) { + case '-': + flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + flags |= DP_F_ZERO; + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if (isdigit((unsigned char)ch)) { + min = 10 * min + char_to_int (ch); + ch = *format++; + } else if (ch == '*') { + min = va_arg (args, int); + ch = *format++; + state = DP_S_DOT; + } else + state = DP_S_DOT; + break; + case DP_S_DOT: + if (ch == '.') { + state = DP_S_MAX; + ch = *format++; + } else + state = DP_S_MOD; + break; + case DP_S_MAX: + if (isdigit((unsigned char)ch)) { + if (max < 0) + max = 0; + max = 10 * max + char_to_int(ch); + ch = *format++; + } else if (ch == '*') { + max = va_arg (args, int); + ch = *format++; + state = DP_S_MOD; + } else + state = DP_S_MOD; + break; + case DP_S_MOD: + switch (ch) { + case 'h': + cflags = DP_C_SHORT; + ch = *format++; + break; + case 'l': + cflags = DP_C_LONG; + ch = *format++; + if (ch == 'l') { + cflags = DP_C_LONG_LONG; + ch = *format++; + } + break; + case 'q': + cflags = DP_C_LONG_LONG; + ch = *format++; + break; + case 'L': + cflags = DP_C_LDOUBLE; + ch = *format++; + break; + default: + break; + } + state = DP_S_CONV; + break; + case DP_S_CONV: + switch (ch) { + case 'd': + case 'i': + if (cflags == DP_C_SHORT) + value = va_arg(args, int); + else if (cflags == DP_C_LONG) + value = va_arg(args, long int); + else if (cflags == DP_C_LONG_LONG) + value = va_arg (args, long long); + else + value = va_arg (args, int); + fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'o': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg(args, unsigned int); + else if (cflags == DP_C_LONG) + value = va_arg(args, unsigned long int); + else if (cflags == DP_C_LONG_LONG) + value = va_arg(args, unsigned long long); + else + value = va_arg(args, unsigned int); + fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags); + break; + case 'u': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg(args, unsigned int); + else if (cflags == DP_C_LONG) + value = va_arg(args, unsigned long int); + else if (cflags == DP_C_LONG_LONG) + value = va_arg(args, unsigned long long); + else + value = va_arg(args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'X': + flags |= DP_F_UP; + case 'x': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg(args, unsigned int); + else if (cflags == DP_C_LONG) + value = va_arg(args, unsigned long int); + else if (cflags == DP_C_LONG_LONG) + value = va_arg(args, unsigned long long); + else + value = va_arg(args, unsigned int); + fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags); + break; + case 'f': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, long double); + else + fvalue = va_arg(args, double); + /* um, floating point? */ + fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'E': + flags |= DP_F_UP; + case 'e': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, long double); + else + fvalue = va_arg(args, double); + break; + case 'G': + flags |= DP_F_UP; + case 'g': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, long double); + else + fvalue = va_arg(args, double); + break; + case 'c': + dopr_outch(buffer, &currlen, maxlen, va_arg(args, int)); + break; + case 's': + strvalue = va_arg(args, char *); + if (max < 0) + max = maxlen; /* ie, no max */ + fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max); + break; + case 'p': + strvalue = va_arg(args, void *); + fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); + break; + case 'n': + if (cflags == DP_C_SHORT) { + short int *num; + num = va_arg(args, short int *); + *num = currlen; + } else if (cflags == DP_C_LONG) { + long int *num; + num = va_arg(args, long int *); + *num = currlen; + } else if (cflags == DP_C_LONG_LONG) { + long long *num; + num = va_arg(args, long long *); + *num = currlen; + } else { + int *num; + num = va_arg(args, int *); + *num = currlen; + } + break; + case '%': + dopr_outch(buffer, &currlen, maxlen, ch); + break; + case 'w': /* not supported yet, treat as next char */ + ch = *format++; + break; + default: /* Unknown, skip */ + break; + } + ch = *format++; + state = DP_S_DEFAULT; + flags = cflags = min = 0; + max = -1; + break; + case DP_S_DONE: + break; + default: /* hmm? */ + break; /* some picky compilers need this */ + } + } + if (currlen < maxlen - 1) + buffer[currlen] = '\0'; + else + buffer[maxlen - 1] = '\0'; +} + +static void +fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max) +{ + int cnt = 0, padlen, strln; /* amount to pad */ + + if (value == 0) + value = ""; + + for (strln = 0; value[strln]; ++strln); /* strlen */ + padlen = min - strln; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justify */ + + while ((padlen > 0) && (cnt < max)) { + dopr_outch(buffer, currlen, maxlen, ' '); + --padlen; + ++cnt; + } + while (*value && (cnt < max)) { + dopr_outch(buffer, currlen, maxlen, *value++); + ++cnt; + } + while ((padlen < 0) && (cnt < max)) { + dopr_outch(buffer, currlen, maxlen, ' '); + ++padlen; + ++cnt; + } +} + +/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ + +static void +fmtint(char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags) +{ + unsigned long uvalue; + char convert[20]; + int signvalue = 0, place = 0, caps = 0; + int spadlen = 0; /* amount to space pad */ + int zpadlen = 0; /* amount to zero pad */ + +#define PADMAX(x,y) ((x) > (y) ? (x) : (y)) + + if (max < 0) + max = 0; + + uvalue = value; + + if (!(flags & DP_F_UNSIGNED)) { + if (value < 0) { + signvalue = '-'; + uvalue = -value; + } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + } + + if (flags & DP_F_UP) + caps = 1; /* Should characters be upper case? */ + do { + convert[place++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [uvalue % (unsigned)base]; + uvalue = (uvalue / (unsigned)base ); + } while (uvalue && (place < 20)); + if (place == 20) + place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = min - PADMAX(max, place) - (signvalue ? 1 : 0); + if (zpadlen < 0) + zpadlen = 0; + if (spadlen < 0) + spadlen = 0; + if (flags & DP_F_ZERO) { + zpadlen = PADMAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; /* Left Justifty */ + + /* Spaces */ + while (spadlen > 0) { + dopr_outch(buffer, currlen, maxlen, ' '); + --spadlen; + } + + /* Sign */ + if (signvalue) + dopr_outch(buffer, currlen, maxlen, signvalue); + + /* Zeros */ + if (zpadlen > 0) { + while (zpadlen > 0) { + dopr_outch(buffer, currlen, maxlen, '0'); + --zpadlen; + } + } + + /* Digits */ + while (place > 0) + dopr_outch(buffer, currlen, maxlen, convert[--place]); + + /* Left Justified spaces */ + while (spadlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++spadlen; + } +} + +static long double +ldpow10(int exp) +{ + long double result = 1; + + while (exp) { + result *= 10; + exp--; + } + + return result; +} + +static long +lroundl(long double value) +{ + long intpart = value; + + value -= intpart; + if (value >= 0.5) + intpart++; + + return intpart; +} + +static void +fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, + int min, int max, int flags) +{ + char iconvert[20], fconvert[20]; + int signvalue = 0, iplace = 0, fplace = 0; + int padlen = 0; /* amount to pad */ + int zpadlen = 0, caps = 0; + long intpart, fracpart; + long double ufvalue; + + /* + * AIX manpage says the default is 0, but Solaris says the default + * is 6, and sprintf on AIX defaults to 6 + */ + if (max < 0) + max = 6; + + ufvalue = abs_val(fvalue); + + if (fvalue < 0) + signvalue = '-'; + else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + + intpart = ufvalue; + + /* + * Sorry, we only support 9 digits past the decimal because of our + * conversion method + */ + if (max > 9) + max = 9; + + /* We "cheat" by converting the fractional part to integer by + * multiplying by a factor of 10 + */ + fracpart = lroundl((ldpow10 (max)) * (ufvalue - intpart)); + + if (fracpart >= ldpow10 (max)) { + intpart++; + fracpart -= ldpow10 (max); + } + + /* Convert integer part */ + do { + iconvert[iplace++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [intpart % 10]; + intpart = (intpart / 10); + } while(intpart && (iplace < 20)); + if (iplace == 20) + iplace--; + iconvert[iplace] = 0; + + /* Convert fractional part */ + do { + fconvert[fplace++] = + (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [fracpart % 10]; + fracpart = (fracpart / 10); + } while(fracpart && (fplace < 20)); + if (fplace == 20) + fplace--; + fconvert[fplace] = 0; + + /* -1 for decimal point, another -1 if we are printing a sign */ + padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); + zpadlen = max - fplace; + if (zpadlen < 0) + zpadlen = 0; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justifty */ + + if ((flags & DP_F_ZERO) && (padlen > 0)) { + if (signvalue) { + dopr_outch(buffer, currlen, maxlen, signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) { + dopr_outch(buffer, currlen, maxlen, '0'); + --padlen; + } + } + while (padlen > 0) { + dopr_outch(buffer, currlen, maxlen, ' '); + --padlen; + } + if (signvalue) + dopr_outch(buffer, currlen, maxlen, signvalue); + + while (iplace > 0) + dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); + + /* + * Decimal point. This should probably use locale to find the + * correct char to print out. + */ + dopr_outch(buffer, currlen, maxlen, '.'); + + while (fplace > 0) + dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); + + while (zpadlen > 0) { + dopr_outch(buffer, currlen, maxlen, '0'); + --zpadlen; + } + + while (padlen < 0) { + dopr_outch(buffer, currlen, maxlen, ' '); + ++padlen; + } +} + +static void +dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) +{ + if (*currlen < maxlen) + buffer[(*currlen)++] = c; +} +#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ + +#ifndef HAVE_VSNPRINTF +int +vsnprintf(char *str, size_t count, const char *fmt, va_list args) +{ + str[0] = 0; + dopr(str, count, fmt, args); + + return(strlen(str)); +} +#endif /* !HAVE_VSNPRINTF */ + +#ifndef HAVE_SNPRINTF +int +snprintf(char *str,size_t count,const char *fmt,...) +{ + va_list ap; + + va_start(ap, fmt); + (void) vsnprintf(str, count, fmt, ap); + va_end(ap); + + return(strlen(str)); +} + +#endif /* !HAVE_SNPRINTF */ diff --git a/lang/pcc/pcc/common/compat.h b/lang/pcc/pcc/common/compat.h new file mode 100644 index 000000000..c5330a8b1 --- /dev/null +++ b/lang/pcc/pcc/common/compat.h @@ -0,0 +1,46 @@ +/* $Id: compat.h,v 1.6 2015/07/24 08:26:05 ragge Exp $ */ + +/* + * Just compatibility function prototypes. + * Public domain. + */ + +#ifndef COMPAT_H +#define COMPAT_H + +#ifndef HAVE_STRLCPY +#include /* size_t */ +size_t strlcpy(char *dst, const char *src, size_t siz); +#endif + +#ifndef HAVE_STRLCAT +#include /* size_t */ +size_t strlcat(char *dst, const char *src, size_t siz); +#endif + +#ifndef HAVE_GETOPT +extern char *optarg; +extern int optind; +int getopt(int, char * const [], const char *); +#endif + +#ifndef HAVE_MKSTEMP +int mkstemp(char *); +#endif + +#ifndef HAVE_FFS +int ffs(int); +#endif + +#ifndef HAVE_SNPRINTF +#include /* size_t */ +int snprintf(char *str, size_t count, const char *fmt, ...); +#endif + +#ifndef HAVE_VSNPRINTF +#include /* size_t */ +#include /* va_list */ +int vsnprintf(char *str, size_t count, const char *fmt, va_list args); +#endif + +#endif diff --git a/lang/pcc/pcc/common/softfloat.h b/lang/pcc/pcc/common/softfloat.h new file mode 100644 index 000000000..7bfe7f446 --- /dev/null +++ b/lang/pcc/pcc/common/softfloat.h @@ -0,0 +1,139 @@ +/* $Id: softfloat.h,v 1.3 2016/03/05 15:31:25 ragge Exp $ */ + +/* + * Copyright (c) 2015 Anders Magnusson. All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 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 AUTHOR 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. + */ + +/* + * Definitions for softfloat routines. + */ + + +typedef struct softfloat { + unsigned long long significand; + short exponent; + short kind; +} SF; +typedef SF *SFP; + +#define C(x,y) C2(x,y) +#define C2(x,y) x##y + +#ifdef USE_IEEEFP_32 +#define IEEEFP_32_RADIX 2 +#define IEEEFP_32_DIG 6 +#define IEEEFP_32_EPSILON 1.19209290E-07F +#define IEEEFP_32_MAX_10_EXP +38 +#define IEEEFP_32_MAX_EXP +128 +#define IEEEFP_32_MAX 3.40282347E+38F +#define IEEEFP_32_MIN_10_EXP -37 +#define IEEEFP_32_MIN_EXP -125 +#define IEEEFP_32_MIN 1.17549435E-38F +#define IEEEFP_32_MANT_DIG 24 +#define IEEEFP_32_DECIMAL_DIG 9 + +#define IEEEFP_32_TRUE_MIN 1.40129846E-45F +#define IEEEFP_32_HAS_SUBNORM 1 +#endif +#ifdef IEEEFP_64 +#endif +#ifdef IEEEFP_X80 +#endif +#ifdef IEEEFP_128 +#endif + +#define TARGET_FLT_RADIX C(FLT_FP,_RADIX) + +#ifndef NATIVE_FLOATING_POINT + +/* + * Description of a floating point format, based what is in gdtoa package. + * The first members are the same as in gdtoa, the rest are pcc specific. + */ +typedef struct FPI { + int nbits; + int emin; + int emax; + int rounding; + + int sudden_underflow:1; + int explicit_one:1; /* if MSB is explicitely stored */ + int has_inf_nan:1; /* highest exponent means INF and NaN */ + int has_neg_zero:1; + int has_radix_16:1; + int storage; + int exp_bias; +} FPI; + +/* SF.kind values; same as STRTODG_* values */ +enum { + SF_Zero = 0, + SF_Normal = 1, + SF_Denormal = 2, + SF_Infinite = 3, + SF_NaN = 4, /* default quiet NaN */ + SF_NaNbits = 5, /* (not used) */ + SF_NoNumber = 6, /* signaling NaN */ + SF_kmask = 7, + + /* The following may be or-ed into one of the above values. */ + SF_Neg = 0x80, /* does not affect SFEXCP_Inex(lo|hi) */ + SFEXCP_Inexlo = 0x100, /* returned result rounded toward zero */ + SFEXCP_Inexhi = 0x200, /* returned result rounded away from zero */ + SFEXCP_Inexact = 0x300, + SFEXCP_Underflow= 0x400, + SFEXCP_Overflow = 0x800, + SFEXCP_DivByZero= 0x1000, + SFEXCP_Invalid = 0x2000, + + SFEXCP_Aborted = 0x8000, /* Not IEEE; operation not performed */ + SFEXCP_ALLmask = 0xFF00 /* All exceptions (mask) */ +}; + +/* FPI.rounding values: same as FLT_ROUNDS */ +enum { + FPI_Round_zero = 0, /* same meaning as FE_TOWARDZERO */ + FPI_Round_near = 1, /* same meaning as FE_TONEAREST */ + FPI_Round_up = 2, /* same meaning as FE_UPWARD */ + FPI_Round_down = 3, /* same meaning as FE_DOWNWARD */ +/* Warning: if adding new modes, keep same meaning for 2 low bits. */ + FPI_Round_near_from0 = 5, /* to nearest but ties up (Vax) */ + + FPI_RoundNotSet = -4, /* to implement dynamic rounding */ +}; + +extern FPI * fpis[3]; /* FLOAT, DOUBLE, LDOUBLE, respectively */ + +SF soft_neg(SF); +SF soft_int2fp(CONSZ p, TWORD v); +CONSZ soft_fp2int(SF p, TWORD v); +SF soft_fp2fp(SF p, TWORD v); +SFP soft_cast(CONSZ v, TWORD); +SF soft_plus(SF, SF); +SF soft_minus(SF, SF); +SF soft_mul(SF, SF); +SF soft_div(SF, SF); +int soft_cmp(SF, SF, int); +int soft_isz(SF); +SF strtosf(char *); +#endif diff --git a/lang/pcc/pcc/common/unicode.c b/lang/pcc/pcc/common/unicode.c new file mode 100644 index 000000000..bf8b1382e --- /dev/null +++ b/lang/pcc/pcc/common/unicode.c @@ -0,0 +1,115 @@ +/* $Id: unicode.c,v 1.9 2015/07/19 13:20:37 ragge Exp $ */ +/* + * Copyright (c) 2014 Eric Olson + * Some rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND 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 + * COPYRIGHT HOLDERS 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 +#include +#include "pass1.h" +#include "manifest.h" +#include "unicode.h" + +/* + * decode 32-bit code point from UTF-8 + * move pointer + */ +long +u82cp(char **q) +{ + unsigned char *t = (unsigned char *)*q; + unsigned long c, r; + int i, sz; + + if (*t == '\\') + c = esccon((char **)&t); + else + c = *t++; + + /* always eat the first value */ + *q = (char *)t; + + if (c > 0x7F) { + if ((c & 0xE0) == 0xC0) { + sz = 2; + r = c & 0x1F; + } else if ((c & 0xF0) == 0xE0) { + sz = 3; + r = c & 0x0F; + } else if ((c & 0xF8) == 0xF0) { + sz = 4; + r = c & 0x07; + } else if ((c & 0xFC) == 0xF8) { + sz = 5; + r = c & 0x03; + } else if ((c & 0xFE) == 0xFC) { + sz = 6; + r = c & 0x01; + } else { + u8error("invalid utf-8 prefix"); + return 0xFFFFUL; + } + + for (i = 1; i < sz; i++) { + if (*t == '\\') + c = esccon((char **)&t); + else + c = *t++; + + if ((c & 0xC0) == 0x80) { + r = (r << 6) + (c & 0x3F); + } else { + u8error("utf-8 encoding %d bytes too short", sz - i); + return 0xFFFFUL; + } + } + + *q = (char *)t; + } else { + r = c; + } + + return r; +} + +/* + * Create UTF-16 from unicode number. + * Expects s to point to two words. + */ +void +cp2u16(long num, unsigned short *s) +{ + s[0] = s[1] = 0; + if (num <= 0xd7ff || (num >= 0xe000 && num <= 0xffffL)) { + *s = num; + } else if (num >= 0x010000L && num <= 0x10ffffL) { + num -= 0x010000L; + s[0] = ((num >> 10) + 0xd800); + s[1] = ((num & 0x3ff) + 0xdc00); + } else if (num > 0x10ffffL) + werror("illegal UTF-16 value"); +} diff --git a/lang/pcc/pcc/common/unicode.h b/lang/pcc/pcc/common/unicode.h new file mode 100644 index 000000000..42736d71b --- /dev/null +++ b/lang/pcc/pcc/common/unicode.h @@ -0,0 +1,10 @@ +/* $Id: unicode.h,v 1.5 2015/07/19 13:20:37 ragge Exp $ */ + +#ifndef _UNICODE_H +#define _UNICODE_H + +extern long u82cp(char **q); +extern void u8error(const char *fmt, ...); +extern void cp2u16(long num, unsigned short *s); + +#endif diff --git a/lang/pcc/pcc/config.guess b/lang/pcc/pcc/config.guess new file mode 100644 index 000000000..7bdfbf6d9 --- /dev/null +++ b/lang/pcc/pcc/config.guess @@ -0,0 +1,1421 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2014 Free Software Foundation, Inc. + +timestamp='2014-11-04' + +# This file 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 3 of the License, 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, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2014 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix${UNAME_RELEASE} + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/lang/pcc/pcc/config.h.in b/lang/pcc/pcc/config.h.in new file mode 100644 index 000000000..14a1fef20 --- /dev/null +++ b/lang/pcc/pcc/config.h.in @@ -0,0 +1,188 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Using a.out ABI */ +#undef AOUTABI + +/* Define path to alternate assembler */ +#undef ASSEMBLER + +/* Using Classic 68k ABI */ +#undef CLASSIC68K + +/* Using COFF ABI */ +#undef COFFABI + +/* Define path to alternate compiler */ +#undef COMPILER + +/* Using ECOFF ABI */ +#undef ECOFFABI + +/* Using ELF ABI */ +#undef ELFABI + +/* Define to 1 if printf supports C99 size specifiers */ +#undef HAVE_C99_FORMAT + +/* Define to 1 if you have the `ffs' function. */ +#undef HAVE_FFS + +/* Define to 1 if you have the `getopt' function. */ +#undef HAVE_GETOPT + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBGEN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `mkstemp' function. */ +#undef HAVE_MKSTEMP + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcat' function. */ +#undef HAVE_STRLCAT + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if you have the `strtold' function. */ +#undef HAVE_STRTOLD + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define if host is BIG endian */ +#undef HOST_BIG_ENDIAN + +/* Define if host is LITTLE endian */ +#undef HOST_LITTLE_ENDIAN + +/* Define alternate standard lib directory */ +#undef LIBDIR + +/* Define path to alternate linker */ +#undef LINKER + +/* Using Mach-O ABI */ +#undef MACHOABI + +/* Define target Multi-Arch path */ +#undef MULTIARCH_PATH + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Major version no */ +#undef PCC_MAJOR + +/* Minor version no */ +#undef PCC_MINOR + +/* Minor minor version no */ +#undef PCC_MINORMINOR + +/* Using PE/COFF ABI */ +#undef PECOFFABI + +/* Define path to alternate preprocessor */ +#undef PREPROCESSOR + +/* Enable STABS debugging output */ +#undef STABS + +/* Enable DWARF debugging output */ +#undef DWARF + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define alternate standard include directory */ +#undef STDINC + +/* Define if target defaults to BIG endian */ +#undef TARGET_BIG_ENDIAN + +/* Define if target defaults to LITTLE endian */ +#undef TARGET_LITTLE_ENDIAN + +/* Enable thread-local storage (TLS). */ +#undef TLS + +/* Version string */ +#undef VERSSTR + +/* Size of wide-character type in chars */ +#undef WCHAR_SIZE + +/* Type to use for wide characters */ +#undef WCHAR_TYPE + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER diff --git a/lang/pcc/pcc/config.sub b/lang/pcc/pcc/config.sub new file mode 100644 index 000000000..e7cd3f59d --- /dev/null +++ b/lang/pcc/pcc/config.sub @@ -0,0 +1,1813 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2015 Free Software Foundation, Inc. + +timestamp='2015-08-20' + +# This file 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 3 of the License, 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, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2015 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m16c | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | nova | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m16c-* | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | nova-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -litebsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/lang/pcc/pcc/configure b/lang/pcc/pcc/configure new file mode 100755 index 000000000..d40b18a29 --- /dev/null +++ b/lang/pcc/pcc/configure @@ -0,0 +1,6506 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for Portable C Compiler 1.2.0.DEVEL. +# +# Report bugs to . +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: pcc@lists.ludd.ltu.se about your system, including any +$0: error possibly output before this message. Then install +$0: a modern shell, or manually run the script under such a +$0: shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='Portable C Compiler' +PACKAGE_TARNAME='pcc' +PACKAGE_VERSION='1.2.0.DEVEL' +PACKAGE_STRING='Portable C Compiler 1.2.0.DEVEL' +PACKAGE_BUGREPORT='pcc@lists.ludd.ltu.se' +PACKAGE_URL='http://pcc.ludd.ltu.se/' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +CF1 +CF0 +CCNAMES +ADD_CPPFLAGS +ADD_CFLAGS +hostos +targmach +targosver +targos +ALLOCA +LEXLIB +LEX_OUTPUT_ROOT +LEX +YFLAGS +YACC +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +SET_MAKE +EGREP +GREP +CPP +CC_FOR_BUILD +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +BINPREFIX +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_multiarch +with_incdir +with_libdir +with_assembler +with_linker +enable_tls +enable_Werror +enable_gcc_compat +enable_pcc_debug +enable_twopass +enable_stripping +enable_nativefp +with_yasm +enable_native +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +YACC +YFLAGS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures Portable C Compiler 1.2.0.DEVEL to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/pcc] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of Portable C Compiler 1.2.0.DEVEL:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-multiarch=yes/no/auto/ + Enable use of Linux Multi-Arch paths (default: auto) + --enable-tls Enable Thread-local storage (TLS). + --enable-Werror Enable use of compiler -Werror flag + --disable-gcc-compat Disable GCC compatibility + --disable-pcc-debug Disable PCC debugging + --enable-twopass Link PCC as a two-pass compiler + --disable-stripping Disable stripping of symbols in installed binaries + --disable-nativefp Disable use of compiler host floating point. + --enable-native Build the compiler as a native rather than + cross-build compiler + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-incdir= Specify the default include path. + --with-libdir= Specify the default library path. + --with-assembler= Specify alternate assember. + --with-linker= Specify alternate linker. + --use-yasm Use yasm assembler + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + YACC The `Yet Another Compiler Compiler' implementation to use. + Defaults to the first program found out of: `bison -y', `byacc', + `yacc'. + YFLAGS The list of arguments that will be passed by default to $YACC. + This script will default YFLAGS to the empty string to avoid a + default value of `-d' given by some make applications. + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +Portable C Compiler home page: . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +Portable C Compiler configure 1.2.0.DEVEL +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## ------------------------------------ ## +## Report this to pcc@lists.ludd.ltu.se ## +## ------------------------------------ ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by Portable C Compiler $as_me 1.2.0.DEVEL, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers config.h" + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if ${ac_cv_target+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +abi=unknown +endian=little +targosver=0 +tls=no +gcccompat=yes +pccdebug=yes +stripping=yes +native=no +nativefp=yes +useyasm=no +stabs=no +dwarf=no +# allowed: UNSIGNED (4-char u_int), INT (4-char int), SHORT (2-char u_short) +wchar_type=INT + +case "$target_os" in + + apple) + targos=apple + abi=classic68k + stabs=yes + case "$target_cpu" in + m68k) targmach=m68k endian=big ;; + esac + ;; + + bsd) + targos=bsd + abi=aout + case "$target_cpu" in + pdp11) targmach=pdp11 ;; + nova) targmach=nova ;; + esac + wchar_type=USHORT + ;; + + darwin*) + targos=darwin + abi=macho + stabs=yes + case "$target_os" in + *10.*) targosver=10 ;; + *9.*) targosver=9 ;; + *8.*) targosver=8 ;; + *7.*) targosver=7 ;; + esac + case "$target_cpu" in + i?86) targmach=i386 ;; + powerpc) targmach=powerpc endian=big ;; + x86_64) targmach=amd64 ;; + esac + ;; + + dragonfly*) + targos=dragonfly + abi=elf + stabs=yes + tls=yes + case "$target_cpu" in + i?86) targmach=i386 ;; + x86_64) targmach=amd64 ;; + esac + ;; + + freebsd*) + targos=freebsd + abi=elf + stabs=yes + case "$target_os" in + *10.*) targosver=10 ;; + *9.*) targosver=9 ;; + *8.*) targosver=8 ;; + *7.*) targosver=7 ;; + *6.*) targosver=6 ;; + *5.*) targosver=5 ;; + *4.*) targosver=4 ;; + esac + case "$target_cpu" in + i386) targmach=i386 ;; + sparc64) targmach=sparc64 endian=big ;; + x86_64) targmach=amd64 ;; + esac + ;; + + linux-android*) + targos=android + abi=elf + stabs=yes + case "$target_cpu" in + arm*) targmach=arm ;; + i?86) targmach=i386 ;; + x86_64) targmach=amd64 ;; + mipseb) targmach=mips endian=big ;; + mips*) targmach=mips ;; + esac + ;; + + linux*) + targos=linux + abi=elf + stabs=yes + case "$target_cpu" in + arm*) targmach=arm ;; + i?86) targmach=i386 ;; + powerpc*) targmach=powerpc endian=big ;; + x86_64) targmach=amd64 ;; + mipseb) targmach=mips endian=big ;; + mips*) targmach=mips ;; + esac + case "$target_os" in + *-musl*) ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_MUSL" ;; + esac + ;; + + litebsd*) + targos=litebsd + abi=elf + wchar_type=USHORT + case "$target_cpu" in + mips*) targmach=mips ;; + esac + ;; + + midnightbsd*) + targos=midnightbsd + abi=elf + stabs=yes + case "$target_cpu" in + i?86) targmach=i386 ;; + sparc64) targmach=sparc64 endian=big ;; + esac + ;; + + mingw*) + targos=win32 + abi=pecoff + wchar_type=USHORT + targmach=i386 + altincdir="c:/mingw/include" + altlibdir="c:/mingw/lib" + ;; + + minix*) + targos=minix + stabs=yes + case "$target_os" in + minix3) abi=aout ;; + minix3.*) abi=elf ;; + # default to ELF + *) abi=elf ;; + esac + case "$target_cpu" in + i86) targmach=i86 ;; + i?86) targmach=i386 ;; + arm*) targmach=arm ;; + x86_64) targmach=amd64 ;; + esac + ;; + + mirbsd*) + targos=mirbsd + abi=elf + stabs=yes + wchar_type=USHORT + case "$target_cpu" in + i?86) targmach=i386 ;; + esac + ;; + + netbsd*) + targos=netbsd + abi=elf + stabs=yes + case "$target_os" in + *7.*) targosver=7 ;; + *6.*) targosver=6 ;; + *5.*) targosver=5 ;; + *4.*) targosver=4 ;; + *3.*) targosver=3 ;; + *2.*) targosver=2 ;; + *1.*) targosver=1 ;; + esac + case "$target_cpu" in + armeb) targmach=arm endian=big ;; + arm*) targmach=arm ;; + i?86) targmach=i386 ;; + m68k*) targmach=m68k endian=big ;; + mipseb) targmach=mips endian=big ;; + mips*) targmach=mips ;; + pdp10) targmach=pdp10 ;; + powerpc) targmach=powerpc endian=big ;; + riscv32) targmach=riscv32 ;; + riscv64) targmach=riscv64 ;; + sparc64) targmach=sparc64 endian=big ;; + vax) targmach=vax ;; + x86_64) targmach=amd64 ;; + esac + ;; + + nextstep*) + targos=nextstep + abi=macho + stabs=yes + case "$target_cpu" in + i?86) targmach=i386 ;; + sparc) targmach=sparc endian=big ;; + hppa) targmach=hppa endian=big ;; + esac + ;; + + openbsd*) + targos=openbsd + abi=elf + stabs=yes + case "$target_cpu" in + i?86) targmach=i386 ;; + vax) targmach=vax ;; + powerpc) targmach=powerpc endian=big ;; + sparc64) targmach=sparc64 endian=big ;; + m68k) targmach=m68k endian=big ;; + x86_64) targmach=amd64 ;; + esac + ;; + + sysv4*) + targos=sysv4 + abi=elf + case "$target_cpu" in + i?86) targmach=i386 ;; + esac + ;; + + sunos*|solaris*) + targos=sunos + abi=elf + stabs=yes + case "$target_cpu" in + i?86) targmach=i386 ;; + sparc*) targmach=sparc64 endian=big ;; + esac + ;; + + windows*|pe*) + target_alias=i386-pe + targos=win32 + abi=pecoff + wchar_type=USHORT + targmach=i386 + ;; + + *) + targos="$target_os" + case "$target_cpu" in + m16c) targmach=m16c ;; + nova) targmach=nova ;; + i86) targmach=i86 ;; + esac + ;; +esac + +if test "X$targos" = X -o "X$targmach" = X ; then + as_fn_error $? "'$target' is not (yet) supported by pcc." "$LINENO" 5 +fi + +case "$host_os" in + + apple) + hostos=apple + ;; + bsd) + hostos=bsd + ;; + darwin*) + hostos=darwin + ;; + dragonfly*) + hostos=dragonfly + ;; + freebsd*) + hostos=freebsd + ;; + linux*) + ADD_CPPFLAGS="$ADD_CPPFLAGS -D_BSD_SOURCE" + hostos=linux + ;; + litebsd*) + hostos=litebsd + ;; + midnightbsd*) + hostos=midnightbsd + ;; + mingw*) + hostos=win32 + ;; + minix*) + hostos=minix + ;; + mirbsd*) + hostos=mirbsd + ;; + netbsd*) + hostos=netbsd + ;; + nextstep*) + hostos=nextstep + ;; + openbsd*) + hostos=openbsd + ;; + sunos*|solaris*) + ADD_CPPFLAGS="$ADD_CPPFLAGS -D_XOPEN_SOURCE=600" + hostos=sunos + ;; + pe*|windows*) + # quick hack for cross-build to win32 host + hostos=win32 + if "$prefix" = NONE; then + prefix="c:/pcc" + assembler="yasm.exe -p gnu -f win32" + linker="link.exe /nologo" + ADD_CPPFLAGS="$ADD_CPPFLAGS -DMSLINKER" + fi + ;; + +esac + +if test "X$endian" = "Xbig" ; then + +$as_echo "#define TARGET_BIG_ENDIAN 1" >>confdefs.h + +else + +$as_echo "#define TARGET_LITTLE_ENDIAN 1" >>confdefs.h + +fi + +case "$abi" in + elf*) +$as_echo "#define ELFABI 1" >>confdefs.h + ;; + aout) +$as_echo "#define AOUTABI 1" >>confdefs.h + ;; + macho) +$as_echo "#define MACHOABI 1" >>confdefs.h + ;; + coff) +$as_echo "#define COFFABI 1" >>confdefs.h + ;; + ecoff) +$as_echo "#define ECOFFABI 1" >>confdefs.h + ;; + pecoff) +$as_echo "#define PECOFFABI 1" >>confdefs.h + ;; + classic68k) +$as_echo "#define CLASSIC68K 1" >>confdefs.h + ;; +esac + +if test "$stabs" = "yes"; then + +$as_echo "#define STABS 1" >>confdefs.h + +fi + +if test "$dwarf" = "yes"; then + +$as_echo "#define DWARF 1" >>confdefs.h + +fi + +# Specify alternate assembler, linker, include and lib paths +# Check whether --enable-multiarch was given. +if test "${enable_multiarch+set}" = set; then : + enableval=$enable_multiarch; multiarch=$enableval +else + multiarch=auto +fi + + +# Check whether --with-incdir was given. +if test "${with_incdir+set}" = set; then : + withval=$with_incdir; altincdir=$withval +fi + + +# Check whether --with-libdir was given. +if test "${with_libdir+set}" = set; then : + withval=$with_libdir; altlibdir=$withval +fi + + +# Check whether --with-assembler was given. +if test "${with_assembler+set}" = set; then : + withval=$with_assembler; assembler=$withval +fi + + +# Check whether --with-linker was given. +if test "${with_linker+set}" = set; then : + withval=$with_linker; linker=$withval +fi + +# Check whether --enable-tls was given. +if test "${enable_tls+set}" = set; then : + enableval=$enable_tls; tls=$enableval +fi + +if test "$tls" = "yes"; then + +$as_echo "#define TLS 1" >>confdefs.h + +fi +# Check whether --enable-Werror was given. +if test "${enable_Werror+set}" = set; then : + enableval=$enable_Werror; werror=$enableval +fi + +if test "$werror" = "yes"; then + ADD_CFLAGS="$ADD_CFLAGS -Werror" +fi +# Check whether --enable-gcc-compat was given. +if test "${enable_gcc_compat+set}" = set; then : + enableval=$enable_gcc_compat; gcccompat=$enableval +fi + +if test "$gcccompat" = "yes"; then + ADD_CPPFLAGS="$ADD_CPPFLAGS -DGCC_COMPAT"; +fi +# Check whether --enable-pcc-debug was given. +if test "${enable_pcc_debug+set}" = set; then : + enableval=$enable_pcc_debug; pccdebug=$enableval +fi + +if test "$pccdebug" = "yes"; then + ADD_CPPFLAGS="$ADD_CPPFLAGS -DPCC_DEBUG"; +fi +# Check whether --enable-twopass was given. +if test "${enable_twopass+set}" = set; then : + enableval=$enable_twopass; twopass=$enableval +fi + +if test "$twopass" = "yes"; then + ADD_CPPFLAGS="$ADD_CPPFLAGS -DTWOPASS"; + CCNAMES='$(BINPREFIX)cc0$(EXEEXT) $(BINPREFIX)cc1$(EXEEXT)' + CF0='-DPASS1' + CF1='-DPASS2' +else + CCNAMES='$(BINPREFIX)ccom$(EXEEXT)' +fi + +# Check whether --enable-stripping was given. +if test "${enable_stripping+set}" = set; then : + enableval=$enable_stripping; stripping=$enableval +fi + +if test "$stripping" = "yes"; then + if test -z "$INSTALL_PROGRAM"; then + INSTALL_PROGRAM='${INSTALL} -s' + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Installed binaries may be unstripped" >&5 +$as_echo "$as_me: WARNING: Installed binaries may be unstripped" >&2;} + fi +fi + +# Check whether --enable-nativefp was given. +if test "${enable_nativefp+set}" = set; then : + enableval=$enable_nativefp; nfp=$enableval +fi + +if test "$nfp" = "no"; then + nativefp=no +fi +if test "$nativefp" = "yes"; then + ADD_CPPFLAGS="$ADD_CPPFLAGS -DNATIVE_FLOATING_POINT" +fi + + +# Check whether --with-yasm was given. +if test "${with_yasm+set}" = set; then : + withval=$with_yasm; useyasm=$withval +fi + +if test "$useyasm" = "yes"; then + assembler="yasm" + ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_YASM" +fi +# Check whether --enable-native was given. +if test "${enable_native+set}" = set; then : + enableval=$enable_native; native=$enableval +fi + + +# Setup for ubuntu multiarch +multiarch_path= +case x$multiarch in +xno) + ;; +xyes) + multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path= + case $multiarch_path in + *-*-*) ;; + *) + as_fn_error $? "Cannot determine Multi-Arch path '$multiarch_path'!" "$LINENO" 5 + ;; + esac + ;; +xauto|x) + multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path= + case x$multiarch_path in + x*-*-*) ;; + x) ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring unrecognised Multi-Arch path '$multiarch_path'!" >&5 +$as_echo "$as_me: WARNING: Ignoring unrecognised Multi-Arch path '$multiarch_path'!" >&2;} + multiarch_path= + ;; + esac + ;; +x*-*-*) + multiarch_path=$multiarch + ;; +*) + as_fn_error $? "Ignoring unrecognised Multi-Arch path '$multiarch_path'!" "$LINENO" 5 + ;; +esac +if test -n "$multiarch_path"; then + +cat >>confdefs.h <<_ACEOF +#define MULTIARCH_PATH "$multiarch_path" +_ACEOF + + multiarch="\"$multiarch_path\"" +else + multiarch="(no)" +fi +# setup for building a cross-compiler +if test "X$native" = "Xyes" -o "X$target_alias" = "X$host_alias" -o "X$target_alias" = "X"; then + BINPREFIX="" +else + BINPREFIX="${target_alias}-" + test "X$prefix" = XNONE && prefix="$ac_default_prefix" + test "X$exec_prefix" = XNONE && exec_prefix="${prefix}" + if test -z "$altincdir"; then + altincdir=${exec_prefix}/${target_alias}/include + fi + if test -z "$altlibdir"; then + altlibdir=${exec_prefix}/${target_alias}/lib + fi + if test -z "$assembler"; then + assembler=${BINPREFIX}as + fi + if test -z "$linker"; then + linker=${BINPREFIX}ld + fi + preprocessor="${BINPREFIX}cpp" + compiler="${BINPREFIX}ccom" +fi + + +if test -n "$altincdir"; then + +cat >>confdefs.h <<_ACEOF +#define STDINC "$altincdir" +_ACEOF + +fi +if test -n "$altlibdir"; then + +cat >>confdefs.h <<_ACEOF +#define LIBDIR "${altlibdir}/" +_ACEOF + +fi +if test -n "$assembler"; then + +cat >>confdefs.h <<_ACEOF +#define ASSEMBLER "$assembler" +_ACEOF + +fi +if test -n "$linker"; then + +cat >>confdefs.h <<_ACEOF +#define LINKER "$linker" +_ACEOF + +fi +if test -n "$preprocessor"; then + +cat >>confdefs.h <<_ACEOF +#define PREPROCESSOR "$preprocessor" +_ACEOF + +fi +if test -n "$compiler"; then + +cat >>confdefs.h <<_ACEOF +#define COMPILER "$compiler" +_ACEOF + +fi + +case $wchar_type in +USHORT) wchar_size=2 ;; +UNSIGNED|INT) wchar_size=4 ;; +*) as_fn_error $? "Unknown wchar_t '$wchar_type'." "$LINENO" 5 ;; +esac + + +cat >>confdefs.h <<_ACEOF +#define WCHAR_TYPE $wchar_type +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define WCHAR_SIZE $wchar_size +_ACEOF + + +# check for additional compiler flags +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +DESIRED_FLAGS="-Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wsign-compare -Wtruncate" +for flag in $DESIRED_FLAGS +do + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts $flag" >&5 +$as_echo_n "checking whether $CC accepts $flag... " >&6; } + cflags="$CFLAGS" + CFLAGS="$CFLAGS $flag -Werror" + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +int +main () +{ + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + use_flag=yes + +else + + use_flag=no + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$cflags" + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_flag" >&5 +$as_echo "$use_flag" >&6; } + if test $use_flag = yes; then + ADD_CFLAGS="$ADD_CFLAGS $flag" + fi +done + +# setup for cross-compiling mkext +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a C compiler for mkext" >&5 +$as_echo_n "checking for a C compiler for mkext... " >&6; } +if test $cross_compiling = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross compiling" >&5 +$as_echo "cross compiling" >&6; } + for ac_prog in pcc gcc cc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC_FOR_BUILD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC_FOR_BUILD"; then + ac_cv_prog_CC_FOR_BUILD="$CC_FOR_BUILD" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC_FOR_BUILD="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC_FOR_BUILD=$ac_cv_prog_CC_FOR_BUILD +if test -n "$CC_FOR_BUILD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC_FOR_BUILD" >&5 +$as_echo "$CC_FOR_BUILD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC_FOR_BUILD" && break +done + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not cross compiling" >&5 +$as_echo "not cross compiling" >&6; } + CC_FOR_BUILD=${CC-cc} + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C99 printf size specifiers" >&5 +$as_echo_n "checking for C99 printf size specifiers... " >&6; } +if ${ac_cv_have_c99_format+:} false; then : + $as_echo_n "(cached) " >&6 +else + + if test "$cross_compiling" = yes; then : + ac_cv_have_c99_format=yes +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $ac_includes_default +int +main () +{ + + char buf[64]; + if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5) + exit(1); + else if (strcmp(buf, "12345")) + exit(2); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_have_c99_format=yes +else + ac_cv_have_c99_format=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_c99_format" >&5 +$as_echo "$ac_cv_have_c99_format" >&6; } +if test $ac_cv_have_c99_format = yes; then + +$as_echo "#define HAVE_C99_FORMAT 1" >>confdefs.h + +fi + +# Byteorder of host + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if ${ac_cv_c_bigendian+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + +$as_echo "#define HOST_BIG_ENDIAN 1" >>confdefs.h +;; #( + no) + +$as_echo "#define HOST_LITTLE_ENDIAN 1" >>confdefs.h + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + + +# Checks for programs. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_YACC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_YACC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 +$as_echo "$YACC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +for ac_prog in flex lex +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LEX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LEX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LEX=$ac_cv_prog_LEX +if test -n "$LEX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 +$as_echo "$LEX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$LEX" && break +done +test -n "$LEX" || LEX=":" + +if test "x$LEX" != "x:"; then + cat >conftest.l <<_ACEOF +%% +a { ECHO; } +b { REJECT; } +c { yymore (); } +d { yyless (1); } +e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ + yyless ((input () != 0)); } +f { unput (yytext[0]); } +. { BEGIN INITIAL; } +%% +#ifdef YYTEXT_POINTER +extern char *yytext; +#endif +int +main (void) +{ + return ! yylex () + ! yywrap (); +} +_ACEOF +{ { ac_try="$LEX conftest.l" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$LEX conftest.l") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 +$as_echo_n "checking lex output file root... " >&6; } +if ${ac_cv_prog_lex_root+:} false; then : + $as_echo_n "(cached) " >&6 +else + +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 +$as_echo "$ac_cv_prog_lex_root" >&6; } +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +if test -z "${LEXLIB+set}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 +$as_echo_n "checking lex library... " >&6; } +if ${ac_cv_lib_lex+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS=$LIBS + ac_cv_lib_lex='none needed' + for ac_lib in '' -lfl -ll; do + LIBS="$ac_lib $ac_save_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_lex=$ac_lib +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + test "$ac_cv_lib_lex" != 'none needed' && break + done + LIBS=$ac_save_LIBS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 +$as_echo "$ac_cv_lib_lex" >&6; } + test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 +$as_echo_n "checking whether yytext is a pointer... " >&6; } +if ${ac_cv_prog_lex_yytext_pointer+:} false; then : + $as_echo_n "(cached) " >&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +ac_save_LIBS=$LIBS +LIBS="$LEXLIB $ac_save_LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #define YYTEXT_POINTER 1 +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_prog_lex_yytext_pointer=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_save_LIBS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 +$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } +if test $ac_cv_prog_lex_yytext_pointer = yes; then + +$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h + +fi +rm -f conftest.l $LEX_OUTPUT_ROOT.c + +fi + +# Checks for libraries. + +# Checks for header files. +# AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h]) +for ac_header in string.h malloc.h libgen.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 +$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } +if ${ac_cv_header_sys_wait_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +int +main () +{ + int s; + wait (&s); + s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_sys_wait_h=yes +else + ac_cv_header_sys_wait_h=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 +$as_echo "$ac_cv_header_sys_wait_h" >&6; } +if test $ac_cv_header_sys_wait_h = yes; then + +$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h + +fi + + +# Checks for library functions. +## AC_FUNC_STRTOD +# AC_FUNC_VPRINTF +# AC_CHECK_FUNCS([memset strchr strdup strrchr strtol]) +for ac_func in strtold vsnprintf snprintf mkstemp strlcat strlcpy getopt ffs vfork +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 +$as_echo_n "checking for working alloca.h... " >&6; } +if ${ac_cv_working_alloca_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +char *p = (char *) alloca (2 * sizeof (int)); + if (p) return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_working_alloca_h=yes +else + ac_cv_working_alloca_h=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 +$as_echo "$ac_cv_working_alloca_h" >&6; } +if test $ac_cv_working_alloca_h = yes; then + +$as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 +$as_echo_n "checking for alloca... " >&6; } +if ${ac_cv_func_alloca_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include +# define alloca _alloca +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +void *alloca (size_t); +# endif +# endif +# endif +# endif +#endif + +int +main () +{ +char *p = (char *) alloca (1); + if (p) return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_func_alloca_works=yes +else + ac_cv_func_alloca_works=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 +$as_echo "$ac_cv_func_alloca_works" >&6; } + +if test $ac_cv_func_alloca_works = yes; then + +$as_echo "#define HAVE_ALLOCA 1" >>confdefs.h + +else + # The SVR3 libPW and SVR4 libucb both contain incompatible functions +# that cause trouble. Some versions do not even contain alloca or +# contain a buggy version. If you still want to use their alloca, +# use ar to extract alloca.o from them instead of compiling alloca.c. + +ALLOCA=\${LIBOBJDIR}alloca.$ac_objext + +$as_echo "#define C_ALLOCA 1" >>confdefs.h + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 +$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } +if ${ac_cv_os_cray+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined CRAY && ! defined CRAY2 +webecray +#else +wenotbecray +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "webecray" >/dev/null 2>&1; then : + ac_cv_os_cray=yes +else + ac_cv_os_cray=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 +$as_echo "$ac_cv_os_cray" >&6; } +if test $ac_cv_os_cray = yes; then + for ac_func in _getb67 GETB67 getb67; do + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + +cat >>confdefs.h <<_ACEOF +#define CRAY_STACKSEG_END $ac_func +_ACEOF + + break +fi + + done +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 +$as_echo_n "checking stack direction for C alloca... " >&6; } +if ${ac_cv_c_stack_direction+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_c_stack_direction=0 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +find_stack_direction (int *addr, int depth) +{ + int dir, dummy = 0; + if (! addr) + addr = &dummy; + *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; + dir = depth ? find_stack_direction (addr, depth - 1) : 0; + return dir + dummy; +} + +int +main (int argc, char **argv) +{ + return find_stack_direction (0, argc + !argv + 20) < 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_stack_direction=1 +else + ac_cv_c_stack_direction=-1 +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 +$as_echo "$ac_cv_c_stack_direction" >&6; } +cat >>confdefs.h <<_ACEOF +#define STACK_DIRECTION $ac_cv_c_stack_direction +_ACEOF + + +fi + + + + + + + + + + + + + + + + + + + +pcc_major=`echo $PACKAGE_VERSION | awk -F. '{print $1}'` +pcc_minor=`echo $PACKAGE_VERSION | awk -F. '{print $2}'` +pcc_minorminor=`echo $PACKAGE_VERSION | awk -F. '{print $3}'` +test -n "$MPVERSION" && MPVERSION=", $MPVERSION" +versstr="\"$PACKAGE_STRING `cat $srcdir/DATESTAMP` for $target$MPVERSION\"" + + +cat >>confdefs.h <<_ACEOF +#define PCC_MAJOR $pcc_major +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PCC_MINOR $pcc_minor +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PCC_MINORMINOR $pcc_minorminor +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSSTR $versstr +_ACEOF + + +ac_config_files="$ac_config_files Makefile cc/Makefile cc/cc/Makefile cc/cpp/Makefile cc/ccom/Makefile cc/cxxcom/Makefile cc/driver/Makefile f77/Makefile f77/f77/Makefile f77/fcom/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by Portable C Compiler $as_me 1.2.0.DEVEL, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to . +Portable C Compiler home page: ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +Portable C Compiler config.status 1.2.0.DEVEL +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "cc/Makefile") CONFIG_FILES="$CONFIG_FILES cc/Makefile" ;; + "cc/cc/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cc/Makefile" ;; + "cc/cpp/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cpp/Makefile" ;; + "cc/ccom/Makefile") CONFIG_FILES="$CONFIG_FILES cc/ccom/Makefile" ;; + "cc/cxxcom/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cxxcom/Makefile" ;; + "cc/driver/Makefile") CONFIG_FILES="$CONFIG_FILES cc/driver/Makefile" ;; + "f77/Makefile") CONFIG_FILES="$CONFIG_FILES f77/Makefile" ;; + "f77/f77/Makefile") CONFIG_FILES="$CONFIG_FILES f77/f77/Makefile" ;; + "f77/fcom/Makefile") CONFIG_FILES="$CONFIG_FILES f77/fcom/Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi + ;; + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +eval "exec_prefix=$exec_prefix" +eval "bindir=$bindir" +eval "libexecdir=$libexecdir" + +echo +echo "Target CPU is .................... ${targmach}" +echo "Target ABI is .................... ${abi}" +echo "Target OS is ..................... ${targos}" +echo "Compiler is called ............... ${BINPREFIX}pcc${EXEEXT}" +echo "Installing compiler into ......... ${bindir}" +echo "Installing pre-processor into .... ${libexecdir}" +echo "Using assembler .................. ${assembler-}" +echo "Using linker ..................... ${linker-}" +echo "Using Multi-Arch path ............ ${multiarch}" +echo "Using include path ............... ${altincdir-}" +echo "Using library path ............... ${altlibdir-}" +echo "Has TLS support .................. $tls" +echo "Has native floating point ........ $nativefp" +echo "Has GCC compatibility ............ $gcccompat" +echo "Has PCC debugging ................ $pccdebug" +echo "Type of wchar_t is ............... ${wchar_type} (${wchar_size} chars)" +echo +echo "Configure finished. Do 'make && make install' to compile and install. +" diff --git a/lang/pcc/pcc/configure.ac b/lang/pcc/pcc/configure.ac new file mode 100644 index 000000000..6affe9080 --- /dev/null +++ b/lang/pcc/pcc/configure.ac @@ -0,0 +1,702 @@ + -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.59) +AC_INIT([Portable C Compiler], [1.2.0.DEVEL], [pcc@lists.ludd.ltu.se], [pcc], [http://pcc.ludd.ltu.se/]) +AC_CONFIG_HEADER([config.h]) + +AC_CANONICAL_TARGET + +abi=unknown +endian=little +targosver=0 +tls=no +gcccompat=yes +pccdebug=yes +stripping=yes +native=no +nativefp=yes +useyasm=no +stabs=no +dwarf=no +# allowed: UNSIGNED (4-char u_int), INT (4-char int), SHORT (2-char u_short) +wchar_type=INT + +case "$target_os" in + + apple) + targos=apple + abi=classic68k + stabs=yes + case "$target_cpu" in + m68k) targmach=m68k endian=big ;; + esac + ;; + + bsd) + targos=bsd + abi=aout + case "$target_cpu" in + pdp11) targmach=pdp11 ;; + nova) targmach=nova ;; + esac + wchar_type=USHORT + ;; + + darwin*) + targos=darwin + abi=macho + stabs=yes + case "$target_os" in + *10.*) targosver=10 ;; + *9.*) targosver=9 ;; + *8.*) targosver=8 ;; + *7.*) targosver=7 ;; + esac + case "$target_cpu" in + i?86) targmach=i386 ;; + powerpc) targmach=powerpc endian=big ;; + x86_64) targmach=amd64 ;; + esac + ;; + + dragonfly*) + targos=dragonfly + abi=elf + stabs=yes + tls=yes + case "$target_cpu" in + i?86) targmach=i386 ;; + x86_64) targmach=amd64 ;; + esac + ;; + + freebsd*) + targos=freebsd + abi=elf + stabs=yes + case "$target_os" in + *10.*) targosver=10 ;; + *9.*) targosver=9 ;; + *8.*) targosver=8 ;; + *7.*) targosver=7 ;; + *6.*) targosver=6 ;; + *5.*) targosver=5 ;; + *4.*) targosver=4 ;; + esac + case "$target_cpu" in + i386) targmach=i386 ;; + sparc64) targmach=sparc64 endian=big ;; + x86_64) targmach=amd64 ;; + esac + ;; + + linux-android*) + targos=android + abi=elf + stabs=yes + case "$target_cpu" in + arm*) targmach=arm ;; + i?86) targmach=i386 ;; + x86_64) targmach=amd64 ;; + mipseb) targmach=mips endian=big ;; + mips*) targmach=mips ;; + esac + ;; + + linux*) + targos=linux + abi=elf + stabs=yes + case "$target_cpu" in + arm*) targmach=arm ;; + i?86) targmach=i386 ;; + powerpc*) targmach=powerpc endian=big ;; + x86_64) targmach=amd64 ;; + mipseb) targmach=mips endian=big ;; + mips*) targmach=mips ;; + esac + case "$target_os" in + *-musl*) ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_MUSL" ;; + esac + ;; + + litebsd*) + targos=litebsd + abi=elf + wchar_type=USHORT + case "$target_cpu" in + mips*) targmach=mips ;; + esac + ;; + + midnightbsd*) + targos=midnightbsd + abi=elf + stabs=yes + case "$target_cpu" in + i?86) targmach=i386 ;; + sparc64) targmach=sparc64 endian=big ;; + esac + ;; + + mingw*) + targos=win32 + abi=pecoff + wchar_type=USHORT + targmach=i386 + altincdir="c:/mingw/include" + altlibdir="c:/mingw/lib" + ;; + + minix*) + targos=minix + stabs=yes + case "$target_os" in + minix3) abi=aout ;; + minix3.*) abi=elf ;; + # default to ELF + *) abi=elf ;; + esac + case "$target_cpu" in + i86) targmach=i86 ;; + i?86) targmach=i386 ;; + arm*) targmach=arm ;; + x86_64) targmach=amd64 ;; + esac + ;; + + mirbsd*) + targos=mirbsd + abi=elf + stabs=yes + wchar_type=USHORT + case "$target_cpu" in + i?86) targmach=i386 ;; + esac + ;; + + netbsd*) + targos=netbsd + abi=elf + stabs=yes + case "$target_os" in + *7.*) targosver=7 ;; + *6.*) targosver=6 ;; + *5.*) targosver=5 ;; + *4.*) targosver=4 ;; + *3.*) targosver=3 ;; + *2.*) targosver=2 ;; + *1.*) targosver=1 ;; + esac + case "$target_cpu" in + armeb) targmach=arm endian=big ;; + arm*) targmach=arm ;; + i?86) targmach=i386 ;; + m68k*) targmach=m68k endian=big ;; + mipseb) targmach=mips endian=big ;; + mips*) targmach=mips ;; + pdp10) targmach=pdp10 ;; + powerpc) targmach=powerpc endian=big ;; + riscv32) targmach=riscv32 ;; + riscv64) targmach=riscv64 ;; + sparc64) targmach=sparc64 endian=big ;; + vax) targmach=vax ;; + x86_64) targmach=amd64 ;; + esac + ;; + + nextstep*) + targos=nextstep + abi=macho + stabs=yes + case "$target_cpu" in + i?86) targmach=i386 ;; + sparc) targmach=sparc endian=big ;; + hppa) targmach=hppa endian=big ;; + esac + ;; + + openbsd*) + targos=openbsd + abi=elf + stabs=yes + case "$target_cpu" in + i?86) targmach=i386 ;; + vax) targmach=vax ;; + powerpc) targmach=powerpc endian=big ;; + sparc64) targmach=sparc64 endian=big ;; + m68k) targmach=m68k endian=big ;; + x86_64) targmach=amd64 ;; + esac + ;; + + sysv4*) + targos=sysv4 + abi=elf + case "$target_cpu" in + i?86) targmach=i386 ;; + esac + ;; + + sunos*|solaris*) + targos=sunos + abi=elf + stabs=yes + case "$target_cpu" in + i?86) targmach=i386 ;; + sparc*) targmach=sparc64 endian=big ;; + esac + ;; + + windows*|pe*) + target_alias=i386-pe + targos=win32 + abi=pecoff + wchar_type=USHORT + targmach=i386 + ;; + + *) + targos="$target_os" + case "$target_cpu" in + m16c) targmach=m16c ;; + nova) targmach=nova ;; + i86) targmach=i86 ;; + esac + ;; +esac + +if test "X$targos" = X -o "X$targmach" = X ; then + AC_MSG_ERROR(['$target' is not (yet) supported by pcc.]) +fi + +case "$host_os" in + + apple) + hostos=apple + ;; + bsd) + hostos=bsd + ;; + darwin*) + hostos=darwin + ;; + dragonfly*) + hostos=dragonfly + ;; + freebsd*) + hostos=freebsd + ;; + linux*) + ADD_CPPFLAGS="$ADD_CPPFLAGS -D_BSD_SOURCE" + hostos=linux + ;; + litebsd*) + hostos=litebsd + ;; + midnightbsd*) + hostos=midnightbsd + ;; + mingw*) + hostos=win32 + ;; + minix*) + hostos=minix + ;; + mirbsd*) + hostos=mirbsd + ;; + netbsd*) + hostos=netbsd + ;; + nextstep*) + hostos=nextstep + ;; + openbsd*) + hostos=openbsd + ;; + sunos*|solaris*) + ADD_CPPFLAGS="$ADD_CPPFLAGS -D_XOPEN_SOURCE=600" + hostos=sunos + ;; + pe*|windows*) + # quick hack for cross-build to win32 host + hostos=win32 + if "$prefix" = NONE; then + prefix="c:/pcc" + assembler="yasm.exe -p gnu -f win32" + linker="link.exe /nologo" + ADD_CPPFLAGS="$ADD_CPPFLAGS -DMSLINKER" + fi + ;; + +esac + +if test "X$endian" = "Xbig" ; then + AC_DEFINE(TARGET_BIG_ENDIAN, 1, + [Define if target defaults to BIG endian]) +else + AC_DEFINE(TARGET_LITTLE_ENDIAN, 1, + [Define if target defaults to LITTLE endian]) +fi + +case "$abi" in + elf*) AC_DEFINE(ELFABI, 1, [Using ELF ABI]) ;; + aout) AC_DEFINE(AOUTABI, 1, [Using a.out ABI]) ;; + macho) AC_DEFINE(MACHOABI, 1, [Using Mach-O ABI]) ;; + coff) AC_DEFINE(COFFABI, 1, [Using COFF ABI]) ;; + ecoff) AC_DEFINE(ECOFFABI, 1, [Using ECOFF ABI]) ;; + pecoff) AC_DEFINE(PECOFFABI, 1, [Using PE/COFF ABI]) ;; + classic68k) AC_DEFINE(CLASSIC68K, 1, [Using Classic 68k ABI]) ;; +esac + +if test "$stabs" = "yes"; then + AC_DEFINE(STABS, 1, [Enable STABS debugging output]) +fi + +if test "$dwarf" = "yes"; then + AC_DEFINE(DWARF, 1, [Enable DWARF debugging output]) +fi + +# Specify alternate assembler, linker, include and lib paths +AC_ARG_ENABLE(multiarch, + AS_HELP_STRING([--enable-multiarch=yes/no/auto/], + [Enable use of Linux Multi-Arch paths (default: auto)]), + [multiarch=$enableval], [multiarch=auto]) +AC_ARG_WITH(incdir, + AS_HELP_STRING([--with-incdir=], + [Specify the default include path.]), + altincdir=$withval, + []) +AC_ARG_WITH(libdir, + AS_HELP_STRING([--with-libdir=], + [Specify the default library path.]), + altlibdir=$withval, + []) +AC_ARG_WITH(assembler, + AS_HELP_STRING([--with-assembler=], + [Specify alternate assember.]), + assembler=$withval, + []) +AC_ARG_WITH(linker, + AS_HELP_STRING([--with-linker=], + [Specify alternate linker.]), + linker=$withval, + []) +AC_ARG_ENABLE(tls, + AS_HELP_STRING([--enable-tls], + [Enable Thread-local storage (TLS).]), + [tls=$enableval], []) +if test "$tls" = "yes"; then + AC_DEFINE(TLS, 1, [Enable thread-local storage (TLS).]) +fi +AC_ARG_ENABLE(Werror, + AS_HELP_STRING([--enable-Werror], + [Enable use of compiler -Werror flag]), + [werror=$enableval], []) +if test "$werror" = "yes"; then + ADD_CFLAGS="$ADD_CFLAGS -Werror" +fi +AC_ARG_ENABLE(gcc-compat, + AS_HELP_STRING([--disable-gcc-compat], + [Disable GCC compatibility]), + [gcccompat=$enableval], []) +if test "$gcccompat" = "yes"; then + ADD_CPPFLAGS="$ADD_CPPFLAGS -DGCC_COMPAT"; +fi +AC_ARG_ENABLE(pcc-debug, + AS_HELP_STRING([--disable-pcc-debug], + [Disable PCC debugging]), + [pccdebug=$enableval], []) +if test "$pccdebug" = "yes"; then + ADD_CPPFLAGS="$ADD_CPPFLAGS -DPCC_DEBUG"; +fi +AC_ARG_ENABLE(twopass, + AS_HELP_STRING([--enable-twopass], + [Link PCC as a two-pass compiler]), + [twopass=$enableval], []) +if test "$twopass" = "yes"; then + ADD_CPPFLAGS="$ADD_CPPFLAGS -DTWOPASS"; + CCNAMES='$(BINPREFIX)cc0$(EXEEXT) $(BINPREFIX)cc1$(EXEEXT)' + CF0='-DPASS1' + CF1='-DPASS2' +else + CCNAMES='$(BINPREFIX)ccom$(EXEEXT)' +fi + +AC_ARG_ENABLE(stripping, + AS_HELP_STRING([--disable-stripping], + [Disable stripping of symbols in installed binaries]), + [stripping=$enableval], []) +if test "$stripping" = "yes"; then + if test -z "$INSTALL_PROGRAM"; then + INSTALL_PROGRAM='${INSTALL} -s' + else + AC_MSG_WARN([Installed binaries may be unstripped]) + fi +fi + +AC_ARG_ENABLE(nativefp, + AS_HELP_STRING([--disable-nativefp], + [Disable use of compiler host floating point.]), + [nfp=$enableval], []) +if test "$nfp" = "no"; then + nativefp=no +fi +if test "$nativefp" = "yes"; then + ADD_CPPFLAGS="$ADD_CPPFLAGS -DNATIVE_FLOATING_POINT" +fi + +AC_ARG_WITH(yasm, + AS_HELP_STRING([--use-yasm], [Use yasm assembler]), + useyasm=$withval, + []) +if test "$useyasm" = "yes"; then + assembler="yasm" + ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_YASM" +fi +AC_ARG_ENABLE(native, + AS_HELP_STRING([--enable-native], + [Build the compiler as a native rather than cross-build compiler]), + [native=$enableval], []) + +# Setup for ubuntu multiarch +multiarch_path= +case x$multiarch in +xno) + ;; +xyes) + multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path= + case $multiarch_path in + *-*-*) ;; + *) + AC_MSG_ERROR([Cannot determine Multi-Arch path '$multiarch_path'!]) + ;; + esac + ;; +xauto|x) + multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path= + case x$multiarch_path in + x*-*-*) ;; + x) ;; + *) + AC_MSG_WARN([Ignoring unrecognised Multi-Arch path '$multiarch_path'!]) + multiarch_path= + ;; + esac + ;; +x*-*-*) + multiarch_path=$multiarch + ;; +*) + AC_MSG_ERROR([Ignoring unrecognised Multi-Arch path '$multiarch_path'!]) + ;; +esac +if test -n "$multiarch_path"; then + AC_DEFINE_UNQUOTED([MULTIARCH_PATH], ["$multiarch_path"], + [Define target Multi-Arch path]) + multiarch="\"$multiarch_path\"" +else + multiarch="(no)" +fi +# setup for building a cross-compiler +if test "X$native" = "Xyes" -o "X$target_alias" = "X$host_alias" -o "X$target_alias" = "X"; then + BINPREFIX="" +else + BINPREFIX="${target_alias}-" + test "X$prefix" = XNONE && prefix="$ac_default_prefix" + test "X$exec_prefix" = XNONE && exec_prefix="${prefix}" + if test -z "$altincdir"; then + altincdir=${exec_prefix}/${target_alias}/include + fi + if test -z "$altlibdir"; then + altlibdir=${exec_prefix}/${target_alias}/lib + fi + if test -z "$assembler"; then + assembler=${BINPREFIX}as + fi + if test -z "$linker"; then + linker=${BINPREFIX}ld + fi + preprocessor="${BINPREFIX}cpp" + compiler="${BINPREFIX}ccom" +fi +AC_SUBST(BINPREFIX) + +if test -n "$altincdir"; then + AC_DEFINE_UNQUOTED(STDINC, "$altincdir", + [Define alternate standard include directory]) +fi +if test -n "$altlibdir"; then + AC_DEFINE_UNQUOTED(LIBDIR, "${altlibdir}/", + [Define alternate standard lib directory]) +fi +if test -n "$assembler"; then + AC_DEFINE_UNQUOTED(ASSEMBLER, "$assembler", + [Define path to alternate assembler]) +fi +if test -n "$linker"; then + AC_DEFINE_UNQUOTED(LINKER, "$linker", + [Define path to alternate linker]) +fi +if test -n "$preprocessor"; then + AC_DEFINE_UNQUOTED(PREPROCESSOR, "$preprocessor", + [Define path to alternate preprocessor]) +fi +if test -n "$compiler"; then + AC_DEFINE_UNQUOTED(COMPILER, "$compiler", + [Define path to alternate compiler]) +fi + +case $wchar_type in +USHORT) wchar_size=2 ;; +UNSIGNED|INT) wchar_size=4 ;; +*) AC_MSG_ERROR([Unknown wchar_t '$wchar_type'.]) ;; +esac + +AC_DEFINE_UNQUOTED(WCHAR_TYPE, $wchar_type, [Type to use for wide characters]) +AC_DEFINE_UNQUOTED(WCHAR_SIZE, $wchar_size, [Size of wide-character type in chars]) + +# check for additional compiler flags +AC_PROG_CC +DESIRED_FLAGS="-Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wsign-compare -Wtruncate" +for flag in $DESIRED_FLAGS +do + AC_MSG_CHECKING([whether $CC accepts $flag]) + cflags="$CFLAGS" + CFLAGS="$CFLAGS $flag -Werror" + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[]], [[]]) + ], [ + use_flag=yes + ], [ + use_flag=no + ]) + CFLAGS="$cflags" + + AC_MSG_RESULT([$use_flag]) + if test $use_flag = yes; then + ADD_CFLAGS="$ADD_CFLAGS $flag" + fi +done + +# setup for cross-compiling mkext +AC_MSG_CHECKING([for a C compiler for mkext]) +if test $cross_compiling = yes; then + AC_MSG_RESULT([cross compiling]) + AC_CHECK_PROGS(CC_FOR_BUILD, [pcc gcc cc]) +else + AC_MSG_RESULT([not cross compiling]) + CC_FOR_BUILD=${CC-cc} + AC_SUBST(CC_FOR_BUILD) +fi + +AC_CACHE_CHECK([for C99 printf size specifiers], ac_cv_have_c99_format, [ + AC_RUN_IFELSE([ + AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], [[ + char buf[64]; + if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5) + exit(1); + else if (strcmp(buf, "12345")) + exit(2); + ]])], + [ ac_cv_have_c99_format=yes ], + [ ac_cv_have_c99_format=no ], + [ ac_cv_have_c99_format=yes ]) +]) +if test $ac_cv_have_c99_format = yes; then + AC_DEFINE([HAVE_C99_FORMAT], 1, + [Define to 1 if printf supports C99 size specifiers]) +fi + +# Byteorder of host +AC_C_BIGENDIAN([AC_DEFINE(HOST_BIG_ENDIAN, 1, [Define if host is BIG endian])], + [AC_DEFINE(HOST_LITTLE_ENDIAN, 1, [Define if host is LITTLE endian])], + []) + +# Checks for programs. +AC_PROG_MAKE_SET +AC_PROG_INSTALL +AC_PROG_YACC +AC_PROG_LEX + +# Checks for libraries. + +# Checks for header files. +# AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h]) +AC_CHECK_HEADERS([string.h malloc.h libgen.h]) +AC_HEADER_SYS_WAIT + +# Checks for library functions. +## AC_FUNC_STRTOD +# AC_FUNC_VPRINTF +# AC_CHECK_FUNCS([memset strchr strdup strrchr strtol]) +AC_CHECK_FUNCS([strtold vsnprintf snprintf mkstemp strlcat strlcpy getopt ffs vfork]) +AC_FUNC_ALLOCA + +AC_EXEEXT + +AC_SUBST(targos) +AC_SUBST(targosver) +AC_SUBST(targmach) +AC_SUBST(hostos) +AC_SUBST(prefix) +AC_SUBST(exec_prefix) +AC_SUBST(libexecdir) +AC_SUBST(includedir) +AC_SUBST(PACKAGE_VERSION) +AC_SUBST(ADD_CFLAGS) +AC_SUBST(ADD_CPPFLAGS) +AC_SUBST(CCNAMES) +AC_SUBST(CF0) +AC_SUBST(CF1) + +pcc_major=`echo $PACKAGE_VERSION | awk -F. '{print $1}'` +pcc_minor=`echo $PACKAGE_VERSION | awk -F. '{print $2}'` +pcc_minorminor=`echo $PACKAGE_VERSION | awk -F. '{print $3}'` +test -n "$MPVERSION" && MPVERSION=", $MPVERSION" +versstr="\"$PACKAGE_STRING `cat $srcdir/DATESTAMP` for $target$MPVERSION\"" + +AC_DEFINE_UNQUOTED(PCC_MAJOR, $pcc_major, [Major version no]) +AC_DEFINE_UNQUOTED(PCC_MINOR, $pcc_minor, [Minor version no]) +AC_DEFINE_UNQUOTED(PCC_MINORMINOR, $pcc_minorminor, [Minor minor version no]) +AC_DEFINE_UNQUOTED(VERSSTR, $versstr, [Version string]) + +AC_CONFIG_FILES([Makefile + cc/Makefile + cc/cc/Makefile + cc/cpp/Makefile + cc/ccom/Makefile + cc/cxxcom/Makefile + cc/driver/Makefile + f77/Makefile + f77/f77/Makefile + f77/fcom/Makefile +]) +AC_OUTPUT + +eval "exec_prefix=$exec_prefix" +eval "bindir=$bindir" +eval "libexecdir=$libexecdir" + +echo +echo "Target CPU is .................... ${targmach}" +echo "Target ABI is .................... ${abi}" +echo "Target OS is ..................... ${targos}" +echo "Compiler is called ............... ${BINPREFIX}pcc${EXEEXT}" +echo "Installing compiler into ......... ${bindir}" +echo "Installing pre-processor into .... ${libexecdir}" +echo "Using assembler .................. ${assembler-}" +echo "Using linker ..................... ${linker-}" +echo "Using Multi-Arch path ............ ${multiarch}" +echo "Using include path ............... ${altincdir-}" +echo "Using library path ............... ${altlibdir-}" +echo "Has TLS support .................. $tls" +echo "Has native floating point ........ $nativefp" +echo "Has GCC compatibility ............ $gcccompat" +echo "Has PCC debugging ................ $pccdebug" +echo "Type of wchar_t is ............... ${wchar_type} (${wchar_size} chars)" +echo +echo "Configure finished. Do 'make && make install' to compile and install. +" diff --git a/lang/pcc/pcc/f77/Makefile.in b/lang/pcc/pcc/f77/Makefile.in new file mode 100644 index 000000000..060aad109 --- /dev/null +++ b/lang/pcc/pcc/f77/Makefile.in @@ -0,0 +1,28 @@ +# $Id: Makefile.in,v 1.7 2011/06/07 13:56:05 plunky Exp $ +# +# Makefile.in for top-level of pcc. +# + +@SET_MAKE@ + +ALL_SUBDIRS= f77 fcom +DIST_SUBDIRS= $(ALL_SUBDIRS) + +all install clean: + @for subdir in $(ALL_SUBDIRS); do \ + _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ + echo "===> $$_nextdir_"; \ + (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ + exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ + echo "<=== $$_nextdir_"; \ + done + +distclean: + @for subdir in $(DIST_SUBDIRS); do \ + _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ + echo "===> $$_nextdir_"; \ + (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ + exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ + echo "<=== $$_nextdir_"; \ + done + rm -f Makefile diff --git a/lang/pcc/pcc/f77/f77/Makefile.in b/lang/pcc/pcc/f77/f77/Makefile.in new file mode 100644 index 000000000..aef692baa --- /dev/null +++ b/lang/pcc/pcc/f77/f77/Makefile.in @@ -0,0 +1,56 @@ +# $Id: Makefile.in,v 1.22 2012/09/25 11:17:17 plunky Exp $ +# +# Makefile.in for the f77 frontend of pcc. +# +VPATH=@srcdir@ +top_srcdir=@top_srcdir@ +top_builddir=@top_builddir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +includedir = @includedir@ +CC = @CC@ +TARGOS = @targos@ +TARGOSVER = @targosver@ +TARGMACH = @targmach@ +TARGET = @target@ +VERSION = @PACKAGE_VERSION@ +PCCLIBDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/lib +PCCINCDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/include +F77LIBDIR=-L$(prefix)/lib +CFLAGS = @CFLAGS@ @ADD_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -DLANG_F77 \ + -DLIBEXECDIR=\"$(libexecdir)\" -DINCLUDEDIR=\"$(includedir)\" \ + -DPCCINCDIR=\"$(PCCINCDIR)/\" -DPCCLIBDIR=\"$(PCCLIBDIR)/\" \ + -DLIBDIR=\"$(F77LIBDIR)\" -Dmach_$(TARGMACH) -Dos_$(TARGOS) \ + -I$(FCOMDIR) -I$(top_builddir) -I$(top_srcdir)/os/$(TARGOS) -I$(MDIR) +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +OBJS=f77.o +DEST=@BINPREFIX@f77 + +MIPDIR=$(top_srcdir)/mip +MDIR=$(top_srcdir)/arch/$(TARGMACH) +FCOMDIR=$(top_srcdir)/f77/fcom + +all: $(DEST) + +$(DEST): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) + +.c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< + +install: + $(INSTALL_PROGRAM) $(DEST) $(bindir) + +clean: + rm -f $(OBJS) $(DEST) + +distclean: clean + rm -f Makefile diff --git a/lang/pcc/pcc/f77/f77/f77.1 b/lang/pcc/pcc/f77/f77/f77.1 new file mode 100644 index 000000000..d947c90ad --- /dev/null +++ b/lang/pcc/pcc/f77/f77/f77.1 @@ -0,0 +1,175 @@ +.\" $Id: f77.1,v 1.2 2008/12/24 17:40:41 sgk Exp $ +.\" +.\" Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" Redistributions of source code and documentation must retain the above +.\" copyright notice, this list of conditions and the following disclaimer. +.\" Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditionsand the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed or owned by Caldera +.\" International, Inc. +.\" Neither the name of Caldera International, Inc. nor the names of other +.\" contributors may be used to endorse or promote products derived from +.\" this software without specific prior written permission. +.\" +.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA +.\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. +.\" +.TH F77 1 +.SH NAME +f77 \- Fortran 77 compiler +.SH SYNOPSIS +.B f77 +[ option ] ... file ... +.SH DESCRIPTION +.I F77 +is the UNIX Fortran 77 compiler. +It accepts several types of arguments: +.PP +Arguments whose names end with `.f' are taken to be +Fortran 77 source programs; +they are compiled, and +each object program is left on the file in the current directory +whose name is that of the source with `.o' substituted +for '.f'. +.PP +Arguments whose names end with `.r' or `.e' are taken to be Ratfor or EFL +source programs, respectively; these are first transformed by the +appropriate preprocessor, then compiled by f77. +.PP +In the same way, +arguments whose names end with `.c' or `.s' are taken to be C or assembly source programs +and are compiled or assembled, producing a `.o' file. +.PP +The following options have the same meaning as in +.IR cc (1). +See +.IR ld (1) +for load-time options. +.TP +.B \-c +Suppress loading and produce `.o' files for each source +file. +.TP +.B \-p +Prepare object files for profiling, see +.IR prof (1). +.TP +.SM +.B \-O +Invoke an +object-code optimizer. +.TP +.SM +.B \-S +Compile the named programs, and leave the +assembler-language output on corresponding files suffixed `.s'. +(No `.o' is created.). +.TP +.B \-f +Use a floating point interpreter (for PDP11's that lack +11/70-style floating point). +.TP +.BR \-o " output" +Name the final output file +.I output +instead of `a.out'. +.PP +The following options are peculiar to +.IR f77 . +.TP +.SM +.BR \-onetrip +Compile DO loops that are performed at least once if reached. +(Fortran 77 DO loops are not performed at all if the upper limit is smaller than the lower limit.) +.TP +.BR \-u +Make the default type of a variable `undefined' rather than using the default Fortran rules. +.TP +.BR \-q +Suppress printing of procedure names during compilation. +.TP +.BR \-C +Compile code to check that subscripts are within declared array bounds. +.TP +.BR \-w +Suppress all warning messages. +If the option is `\-w66', only Fortran 66 compatibility warnings are suppressed. +.TP +.BR \-F +Apply EFL and Ratfor preprocessor to relevant files, put the result in the file +with the suffix changed to `.f', but do not compile. +.TP +.BR \-m +Apply the M4 preprocessor to each `.r' or `.e' file before transforming +it with the Ratfor or EFL preprocessor. +.TP +.TP +.BI \-E x +Use the string +.I x +as an EFL option in processing `.e' files. +.TP +.BI \-R x +Use the string +.I x +as a Ratfor option in processing `.r' files. +.PP +Other arguments +are taken +to be either loader option arguments, or F77-compatible +object programs, typically produced by an earlier +run, +or perhaps libraries of F77-compatible routines. +These programs, together with the results of any +compilations specified, are loaded (in the order +given) to produce an executable program with name +`a.out'. +.SH FILES +.nf +.ta \w'/usr/lib/libF77.a 'u +file.[fresc] input file +file.o object file +a.out loaded output +./fort[pid].? temporary +/usr/lib/f77pass1 compiler +/lib/f1 pass 2 +/lib/c2 optional optimizer +/usr/lib/libF77.a intrinsic function library +/usr/lib/libI77.a Fortran I/O library +/lib/libc.a C library, see section 3 +.fi +.SH "SEE ALSO" +S. I. Feldman, +P. J. Weinberger, +.I +A Portable Fortran 77 Compiler +.br +prof(1), cc(1), ld(1) +.SH DIAGNOSTICS +The diagnostics produced by +.I f77 +itself are intended to be +self-explanatory. +Occasional messages may be produced by the loader. +.SH BUGS +The Fortran 66 subset of the language has been +exercised extensively; +the newer features have not. diff --git a/lang/pcc/pcc/f77/f77/f77.c b/lang/pcc/pcc/f77/f77/f77.c new file mode 100644 index 000000000..d5c79f8de --- /dev/null +++ b/lang/pcc/pcc/f77/f77/f77.c @@ -0,0 +1,799 @@ +/* $Id: f77.c,v 1.22 2011/08/04 08:32:32 mickey Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ + +char xxxvers[] = "FORTRAN 77 DRIVER, VERSION 1.11, 28 JULY 1978\n"; + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ccconfig.h" + +typedef FILE *FILEP; +typedef int flag; +#define YES 1 +#define NO 0 + +FILEP diagfile; + +static int pid; +static int sigivalue = 0; +static int sigqvalue = 0; + +#ifndef FCOM +#define FCOM "fcom" +#endif + +#ifndef ASSEMBLER +#define ASSEMBLER "as" +#endif + +#ifndef LINKER +#define LINKER "ld" +#endif + +static char *fcom = LIBEXECDIR "/" FCOM ; +static char *asmname = ASSEMBLER ; +static char *ldname = LINKER ; +static char *startfiles[] = STARTFILES; +static char *endfiles[] = ENDFILES; +static char *dynlinker[] = DYNLINKER; +static char *crt0file = CRT0FILE; +static char *macroname = "m4"; +static char *shellname = "/bin/sh"; +static char *aoutname = "a.out" ; +static char *libdir = LIBDIR ; +static char *liblist[] = F77LIBLIST; + +static char *infname; +static char asmfname[15]; +static char prepfname[15]; + +#define MAXARGS 100 +int ffmax; +static char *ffary[MAXARGS]; +static char eflags[30] = ""; +static char rflags[30] = ""; +static char lflag[3] = "-x"; +static char *eflagp = eflags; +static char *rflagp = rflags; +static char **loadargs; +static char **loadp; +static int oflag; + +static flag loadflag = YES; +static flag saveasmflag = NO; +static flag profileflag = NO; +static flag optimflag = NO; +static flag debugflag = NO; +static flag verbose = NO; +static flag fortonly = NO; +static flag macroflag = NO; + +static char *setdoto(char *), *lastchar(char *), *lastfield(char *); +static void intrupt(int); +static void enbint(void (*)(int)); +static void crfnames(void); +static void fatal1(char *, ...); +static void done(int), texec(char *, char **); +static char *copyn(int, char *); +static int dotchar(char *), unreadable(char *), sys(char *), dofort(char *); +static int nodup(char *); +static int await(int); +static void rmf(char *), doload(char *[], char *[]), doasm(char *); +static int callsys(char *, char **); +static void errorx(char *, ...); + +static void +addarg(char **ary, int *num, char *arg) +{ + ary[(*num)++] = arg; + if ((*num) == MAXARGS) { + fprintf(stderr, "argument array too small\n"); + exit(1); + } +} + +int +main(int argc, char **argv) +{ + int i, c, status; + char *s; + char fortfile[20], *t; + char buff[100]; + + diagfile = stderr; + + sigivalue = (int) signal(SIGINT, SIG_IGN) & 01; + sigqvalue = (int) signal(SIGQUIT, SIG_IGN) & 01; + enbint(intrupt); + + pid = getpid(); + crfnames(); + + loadargs = (char **)calloc(1, (argc + 20) * sizeof(*loadargs)); + if (!loadargs) + fatal1("out of memory"); + loadp = loadargs; + + --argc; + ++argv; + + while(argc>0 && argv[0][0]=='-' && argv[0][1]!='\0') { + for(s = argv[0]+1 ; *s ; ++s) + switch(*s) { + case 'T': /* use special passes */ + switch(*++s) { + case '1': + fcom = s+1; goto endfor; + case 'a': + asmname = s+1; goto endfor; + case 'l': + ldname = s+1; goto endfor; + case 'm': + macroname = s+1; goto endfor; + default: + fatal1("bad option -T%c", *s); + } + break; + + case 'w': /* F66 warn or no warn */ + addarg(ffary, &ffmax, s-1); + break; + + case 'q': + /* + * Suppress printing of procedure names during + * compilation. + */ + addarg(ffary, &ffmax, s-1); + break; + + copyfflag: + case 'u': + case 'U': + case 'M': + case '1': + case 'C': + addarg(ffary, &ffmax, s-1); + break; + + case 'O': + optimflag = YES; + addarg(ffary, &ffmax, s-1); + break; + + case 'm': + if(s[1] == '4') + ++s; + macroflag = YES; + break; + + case 'S': + saveasmflag = YES; + + case 'c': + loadflag = NO; + break; + + case 'v': + verbose = YES; + break; + + case 'd': + debugflag = YES; + goto copyfflag; + + case 'p': + profileflag = YES; + goto copyfflag; + + case 'o': + if(!strcmp(s, "onetrip")) { + addarg(ffary, &ffmax, s-1); + goto endfor; + } + oflag = 1; + aoutname = *++argv; + --argc; + break; + + case 'F': + fortonly = YES; + loadflag = NO; + break; + + case 'I': + if(s[1]=='2' || s[1]=='4' || s[1]=='s') + goto copyfflag; + fprintf(diagfile, "invalid flag -I%c\n", s[1]); + done(1); + + case 'l': /* letter ell--library */ + s[-1] = '-'; + *loadp++ = s-1; + goto endfor; + + case 'E': /* EFL flag argument */ + while(( *eflagp++ = *++s)) + ; + *eflagp++ = ' '; + goto endfor; + case 'R': + while(( *rflagp++ = *++s )) + ; + *rflagp++ = ' '; + goto endfor; + default: + lflag[1] = *s; + *loadp++ = copyn(strlen(lflag), lflag); + break; + } +endfor: + --argc; + ++argv; + } + + if (verbose) + fprintf(stderr, xxxvers); + + if (argc == 0) + errorx("No input files"); + +#ifdef mach_pdp11 + if(nofloating) + *loadp++ = (profileflag ? NOFLPROF : NOFLFOOT); + else +#endif + + for(i = 0 ; i%s", + macroname, infname, prepfname); + if(sys(buff)) { + rmf(prepfname); + break; + } + infname = prepfname; + } + + if(c == 'e') + snprintf(buff, sizeof(buff), "efl %s %s >%s", + eflags, infname, fortfile); + else + snprintf(buff, sizeof(buff), "ratfor %s %s >%s", + rflags, infname, fortfile); + status = sys(buff); + if(macroflag) + rmf(infname); + if(status) { + loadflag = NO; + rmf(fortfile); + break; + } + + if( ! fortonly ) { + infname = argv[i] = lastfield(argv[i]); + *lastchar(infname) = 'f'; + + if( dofort(argv[i]) ) + loadflag = NO; + else { + if( nodup(t = setdoto(argv[i])) ) + *loadp++ = t; + rmf(fortfile); + } + } + break; + + case 'f': /* Fortran file */ + case 'F': + if( unreadable(argv[i]) ) + break; + if( dofort(argv[i]) ) + loadflag = NO; + else if( nodup(t=setdoto(argv[i])) ) + *loadp++ = t; + break; + + case 'c': /* C file */ + case 's': /* Assembler file */ + if( unreadable(argv[i]) ) + break; + fprintf(diagfile, "%s:\n", argv[i]); + snprintf(buff, sizeof(buff), "cc -c %s", argv[i]); + if( sys(buff) ) + loadflag = NO; + else + if( nodup(t = setdoto(argv[i])) ) + *loadp++ = t; + break; + + case 'o': + if( nodup(argv[i]) ) + *loadp++ = argv[i]; + break; + + default: + if( ! strcmp(argv[i], "-o") ) + aoutname = argv[++i]; + else + *loadp++ = argv[i]; + break; + } + + if(loadflag) + doload(loadargs, loadp); + done(0); + return 0; +} + +#define ADD(x) addarg(params, &nparms, (x)) + +static int +dofort(char *s) +{ + int nparms, i; + char *params[MAXARGS]; + + nparms = 0; + ADD(FCOM); + for (i = 0; i < ffmax; i++) + ADD(ffary[i]); + ADD(s); + ADD(asmfname); + ADD(NULL); + + infname = s; + if (callsys(fcom, params)) + errorx("Error. No assembly."); + doasm(s); + + if (saveasmflag == NO) + rmf(asmfname); + return(0); +} + + +static void +doasm(char *s) +{ + char *obj; + char *params[MAXARGS]; + int nparms; + + if (oflag && loadflag == NO) + obj = aoutname; + else + obj = setdoto(s); + + nparms = 0; + ADD(asmname); + ADD("-o"); + ADD(obj); + ADD(asmfname); + ADD(NULL); + + if (callsys(asmname, params)) + fatal1("assembler error"); + if(verbose) + fprintf(diagfile, "\n"); +} + + +static void +doload(char *v0[], char *v[]) +{ + int nparms, i; + char *params[MAXARGS]; + char **p; + + nparms = 0; + ADD(ldname); + ADD("-X"); + ADD("-d"); + for (i = 0; dynlinker[i]; i++) + ADD(dynlinker[i]); + ADD("-o"); + ADD(aoutname); + ADD(crt0file); + for (i = 0; startfiles[i]; i++) + ADD(startfiles[i]); + *v = NULL; + for(p = v0; *p ; p++) + ADD(*p); + if (libdir) + ADD(libdir); + for(p = liblist ; *p ; p++) + ADD(*p); + for (i = 0; endfiles[i]; i++) + ADD(endfiles[i]); + ADD(NULL); + + if (callsys(ldname, params)) + fatal1("couldn't load %s", ldname); + + if(verbose) + fprintf(diagfile, "\n"); +} + +/* Process control and Shell-simulating routines */ + +/* + * Execute f[] with parameter array v[]. + * Copied from cc. + */ +static int +callsys(char f[], char *v[]) +{ + int t, status = 0; + pid_t p; + char *s; + + if (debugflag || verbose) { + fprintf(stderr, "%s ", f); + for (t = 1; v[t]; t++) + fprintf(stderr, "%s ", v[t]); + fprintf(stderr, "\n"); + } + + if ((p = fork()) == 0) { +#ifdef notyet + if (Bflag) { + size_t len = strlen(Bflag) + 8; + char *a = malloc(len); + if (a == NULL) { + error("callsys: malloc failed"); + exit(1); + } + if ((s = strrchr(f, '/'))) { + strlcpy(a, Bflag, len); + strlcat(a, s, len); + execv(a, v); + } + } +#endif + execvp(f, v); + if ((s = strrchr(f, '/'))) + execvp(s+1, v); + fprintf(stderr, "Can't find %s\n", f); + _exit(100); + } else { + if (p == -1) { + printf("Try again\n"); + return(100); + } + } + while (waitpid(p, &status, 0) == -1 && errno == EINTR) + ; + if (WIFEXITED(status)) + return (WEXITSTATUS(status)); + if (WIFSIGNALED(status)) + done(1); + fatal1("Fatal error in %s", f); + return 0; /* XXX */ +} + + +static int +sys(char *str) +{ + char *s, *t; + char *argv[100], path[100]; + char *inname, *outname; + int append = 0; + int wait_pid; + int argc; + + + if(debugflag) + fprintf(diagfile, "%s\n", str); + inname = NULL; + outname = NULL; + argv[0] = shellname; + argc = 1; + + t = str; + while( isspace((int)*t) ) + ++t; + while(*t) { + if(*t == '<') + inname = t+1; + else if(*t == '>') { + if(t[1] == '>') { + append = YES; + outname = t+2; + } else { + append = NO; + outname = t+1; + } + } else + argv[argc++] = t; + while( !isspace((int)*t) && *t!='\0' ) + ++t; + if(*t) { + *t++ = '\0'; + while( isspace((int)*t) ) + ++t; + } + } + + if(argc == 1) /* no command */ + return(-1); + argv[argc] = 0; + + s = path; + t = "/usr/bin/"; + while(*t) + *s++ = *t++; + for(t = argv[1] ; (*s++ = *t++) ; ) + ; + if((wait_pid = fork()) == 0) { + if(inname) + freopen(inname, "r", stdin); + if(outname) + freopen(outname, (append ? "a" : "w"), stdout); + enbint(SIG_DFL); + + texec(path+9, argv); /* command */ + texec(path+4, argv); /* /bin/command */ + texec(path , argv); /* /usr/bin/command */ + + fatal1("Cannot load %s",path+9); + } + + return( await(wait_pid) ); +} + +/* modified version from the Shell */ +static void +texec(char *f, char **av) +{ + + execv(f, av+1); + + if (errno==ENOEXEC) { + av[1] = f; + execv(shellname, av); + fatal1("No shell!"); + } + if (errno==ENOMEM) + fatal1("%s: too large", f); +} + +/* + * Cleanup and exit with value k. + */ +static void +done(int k) +{ + static int recurs = NO; + + if(recurs == NO) { + recurs = YES; + if (saveasmflag == NO) + rmf(asmfname); + } + exit(k); +} + + +static void +enbint(void (*k)(int)) +{ +if(sigivalue == 0) + signal(SIGINT,k); +if(sigqvalue == 0) + signal(SIGQUIT,k); +} + + + +static void +intrupt(int a) +{ +done(2); +} + + +static int +await(int wait_pid) +{ +int w, status; + +enbint(SIG_IGN); +while ( (w = wait(&status)) != wait_pid) + if(w == -1) + fatal1("bad wait code"); +enbint(intrupt); +if(status & 0377) + { + if(status != SIGINT) + fprintf(diagfile, "Termination code %d", status); + done(3); + } +return(status>>8); +} + +/* File Name and File Manipulation Routines */ + +static int +unreadable(char *s) +{ + FILE *fp; + + if((fp = fopen(s, "r"))) { + fclose(fp); + return(NO); + } else { + fprintf(diagfile, "Error: Cannot read file %s\n", s); + loadflag = NO; + return(YES); + } +} + + +static void +crfnames(void) +{ + snprintf(asmfname, sizeof(asmfname), "fort%d.%s", pid, "s"); + snprintf(prepfname, sizeof(prepfname), "fort%d.%s", pid, "p"); +} + + + +static void +rmf(char *fn) +{ +if(!debugflag && fn!=NULL && *fn!='\0') + unlink(fn); +} + + +static int +dotchar(char *s) +{ +for( ; *s ; ++s) + if(s[0]=='.' && s[1]!='\0' && s[2]=='\0') + return( s[1] ); +return(NO); +} + + +static char * +lastfield(char *s) +{ +char *t; +for(t = s; *s ; ++s) + if(*s == '/') + t = s+1; +return(t); +} + + +static char * +lastchar(char *s) +{ +while(*s) + ++s; +return(s-1); +} + + +static char * +setdoto(char *s) +{ +*lastchar(s) = 'o'; +return( lastfield(s) ); +} + + +static char * +copyn(int n, char *s) +{ + char *p, *q; + + p = q = (char *)calloc(1, (unsigned) n + 1); + if (!p) + fatal1("out of memory"); + + while(n-- > 0) + *q++ = *s++; + return (p); +} + + +static int +nodup(char *s) +{ +char **p; + +for(p = loadargs ; p < loadp ; ++p) + if( !strcmp(*p, s) ) + return(NO); + +return(YES); +} + + +static void +errorx(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(diagfile, fmt, ap); + fprintf(diagfile, "\n"); + va_end(ap); + + if (debugflag) + abort(); + done(1); +} + + +static void +fatal1(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(diagfile, "Compiler error in file %s: ", infname); + vfprintf(diagfile, fmt, ap); + fprintf(diagfile, "\n"); + va_end(ap); + + if (debugflag) + abort(); + done(1); +} diff --git a/lang/pcc/pcc/f77/fcom/Makefile.in b/lang/pcc/pcc/f77/fcom/Makefile.in new file mode 100644 index 000000000..1090cf4ba --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/Makefile.in @@ -0,0 +1,185 @@ +# $Id: Makefile.in,v 1.23 2012/09/25 11:17:17 plunky Exp $ +# +# Makefile for the Fortran 77 compiler +# +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +builddir=@builddir@ +top_builddir=@top_builddir@ +CC = @CC@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ @ADD_CFLAGS@ +CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -DFCOM -DLANG_F77 \ + -Dos_$(TARGOS) -Dmach_$(TARGMACH) \ + -I$(srcdir) -I$(builddir) -I$(top_builddir) \ + -I$(MIPDIR) -I$(MDIR) -I$(top_srcdir)/os/$(TARGOS) +LIBS = @LIBS@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LFLAGS = +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +TARGOS = @targos@ +TARGOSVER = @targosver@ +TARGMACH = @targmach@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +mandir = @mandir@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ + +MDIR=$(top_srcdir)/arch/$(TARGMACH) +MIPDIR=$(top_srcdir)/mip + +DEST=@BINPREFIX@fcom$(EXEEXT) +MKEXT=mkext$(EXEEXT) + +OBJS= common.o compat.o data.o equiv.o error.o exec.o expr.o \ + external.o flocal.o gram.o init.o intr.o io.o lex.o \ + local2.o main.o match.o misc.o optim2.o order.o proc.o \ + put.o putscj.o reader.o regs.o table.o + +LOBJS= common.lo mkext.lo table.lo + +HDRS= $(srcdir)/defs.h $(srcdir)/defines.h $(srcdir)/ftypes.h \ + $(MIPDIR)/pass2.h $(MIPDIR)/manifest.h $(MIPDIR)/node.h \ + $(MDIR)/macdefs.h + +GSRC= $(srcdir)/gram.head $(srcdir)/gram.dcl $(srcdir)/gram.expr \ + $(srcdir)/gram.exec $(srcdir)/gram.io + +all: $(DEST) + +# +# round 1: generate external.[ch] & gram.[ch] +# + +$(LOBJS): $(HDRS) + +common.lo: $(MIPDIR)/common.c + $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/common.c + +mkext.lo: $(MIPDIR)/mkext.c + $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/mkext.c + +table.lo: $(MDIR)/table.c + $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MDIR)/table.c + +$(MKEXT): $(LOBJS) + $(CC_FOR_BUILD) $(LDFLAGS) $(LOBJS) -o $@ $(LIBS) + +external.c: $(MKEXT) + $(builddir)/$(MKEXT) + +gram.c: $(GSRC) $(srcdir)/tokens + ( grep -n . < $(srcdir)/tokens | sed "s/\([^:]*\):\(.*\)/%token \2 \1/"; \ + cat $(GSRC) ) > gram.y + $(YACC) $(YFLAGS) -d gram.y + mv -f y.tab.c gram.c + mv -f y.tab.h gram.h + +# +# round 2: compile $(OBJS) +# + +$(OBJS): $(HDRS) external.c gram.c + +common.o: $(MIPDIR)/common.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c + +compat.o: $(MIPDIR)/compat.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/compat.c + +data.o: $(srcdir)/data.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/data.c + +equiv.o: $(srcdir)/equiv.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/equiv.c + +error.o: $(srcdir)/error.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/error.c + +exec.o: $(srcdir)/exec.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/exec.c + +expr.o: $(srcdir)/expr.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/expr.c + +external.o: external.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ external.c + +flocal.o: $(MDIR)/flocal.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/flocal.c + +gram.o: gram.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ gram.c + +init.o: $(srcdir)/init.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/init.c + +intr.o: $(srcdir)/intr.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/intr.c + +io.o: $(srcdir)/io.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/io.c + +lex.o: $(srcdir)/lex.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/lex.c + +local2.o: $(MDIR)/local2.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local2.c + +main.o: $(srcdir)/main.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c + +match.o: $(MIPDIR)/match.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/match.c + +misc.o: $(srcdir)/misc.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/misc.c + +optim2.o: $(MIPDIR)/optim2.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/optim2.c + +order.o: $(MDIR)/order.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/order.c + +proc.o: $(srcdir)/proc.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/proc.c + +put.o: $(srcdir)/put.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/put.c + +putscj.o: $(srcdir)/putscj.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/putscj.c + +reader.o: $(MIPDIR)/reader.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/reader.c + +regs.o: $(MIPDIR)/regs.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/regs.c + +table.o: $(MDIR)/table.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/table.c + +# +# round 3: build $(DEST) +# + +$(DEST): $(OBJS) + $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) + +install: $(DEST) + test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)" + $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir) + +clean: + rm -f $(DEST) $(OBJS) $(MKEXT) $(LOBJS) \ + y.tab.[ch] gram.[ych] external.[ch] + +distclean: clean + rm -f Makefile diff --git a/lang/pcc/pcc/f77/fcom/data.c b/lang/pcc/pcc/f77/fcom/data.c new file mode 100644 index 000000000..6313b5ddf --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/data.c @@ -0,0 +1,358 @@ +/* $Id: data.c,v 1.15 2008/05/11 15:28:03 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "defines.h" +#include "defs.h" + +#if 1 /* RAGGE */ +extern FILE *initfile; +#endif + +/* ROUTINES CALLED DURING DATA STATEMENT PROCESSING */ +LOCAL void setdata(struct bigblock *, struct bigblock *, ftnint, ftnint); + +static char datafmt[] = "%s\t%05ld\t%05ld\t%d" ; + +/* another initializer, called from parser */ +void +dataval(repp, valp) +register struct bigblock *repp, *valp; +{ +int i, nrep; +ftnint elen, vlen; +register struct bigblock *p; + +if(repp == NULL) + nrep = 1; +else if (ISICON(repp) && repp->b_const.fconst.ci >= 0) + nrep = repp->b_const.fconst.ci; +else + { + err("invalid repetition count in DATA statement"); + frexpr(repp); + goto ret; + } +frexpr(repp); + +if( ! ISCONST(valp) ) + { + err("non-constant initializer"); + goto ret; + } + +if(toomanyinit) goto ret; +for(i = 0 ; i < nrep ; ++i) + { + p = nextdata(&elen, &vlen); + if(p == NULL) + { + err("too many initializers"); + toomanyinit = YES; + goto ret; + } + setdata(p, valp, elen, vlen); + frexpr(p); + } + +ret: + frexpr(valp); +} + + +struct bigblock *nextdata(elenp, vlenp) +ftnint *elenp, *vlenp; +{ +register struct bigblock *ip; +struct bigblock *pp; +register struct bigblock *np; +register chainp rp; +bigptr p; +bigptr neltp; +register bigptr q; +int skip; +ftnint off; + +while(curdtp) + { + p = curdtp->chain.datap; + if(p->tag == TIMPLDO) + { + ip = p; + if(ip->b_impldo.implb==NULL || ip->b_impldo.impub==NULL || ip->b_impldo.varnp==NULL) + fatal1("bad impldoblock 0%o", ip); + if(ip->isactive) + ip->b_impldo.varvp->b_const.fconst.ci += ip->b_impldo.impdiff; + else + { + q = fixtype(cpexpr(ip->b_impldo.implb)); + if( ! ISICON(q) ) + goto doerr; + ip->b_impldo.varvp = q; + + if(ip->b_impldo.impstep) + { + q = fixtype(cpexpr(ip->b_impldo.impstep)); + if( ! ISICON(q) ) + goto doerr; + ip->b_impldo.impdiff = q->b_const.fconst.ci; + frexpr(q); + } + else + ip->b_impldo.impdiff = 1; + + q = fixtype(cpexpr(ip->b_impldo.impub)); + if(! ISICON(q)) + goto doerr; + ip->b_impldo.implim = q->b_const.fconst.ci; + frexpr(q); + + ip->isactive = YES; + rp = ALLOC(rplblock); + rp->rplblock.nextp = rpllist; + rpllist = rp; + rp->rplblock.rplnp = ip->b_impldo.varnp; + rp->rplblock.rplvp = ip->b_impldo.varvp; + rp->rplblock.rpltag = TCONST; + } + + if( (ip->b_impldo.impdiff>0 && + (ip->b_impldo.varvp->b_const.fconst.ci <= ip->b_impldo.implim)) + || (ip->b_impldo.impdiff<0 && + (ip->b_impldo.varvp->b_const.fconst.ci >= ip->b_impldo.implim))) + { /* start new loop */ + curdtp = ip->b_impldo.datalist; + goto next; + } + + /* clean up loop */ + + popstack(&rpllist); + + frexpr(ip->b_impldo.varvp); + ip->isactive = NO; + curdtp = curdtp->chain.nextp; + goto next; + } + + pp = p; + np = pp->b_prim.namep; + skip = YES; + + if(p->b_prim.argsp==NULL && np->b_name.vdim!=NULL) + { /* array initialization */ + q = mkaddr(np); + off = typesize[np->vtype] * curdtelt; + if(np->vtype == TYCHAR) + off *= np->vleng->b_const.fconst.ci; + q->b_addr.memoffset = mkexpr(OPPLUS, q->b_addr.memoffset, mkintcon(off) ); + if( (neltp = np->b_name.vdim->nelt) && ISCONST(neltp)) + { + if(++curdtelt < neltp->b_const.fconst.ci) + skip = NO; + } + else + err("attempt to initialize adjustable array"); + } + else + q = mklhs( cpexpr(pp) ); + if(skip) + { + curdtp = curdtp->chain.nextp; + curdtelt = 0; + } + if(q->vtype == TYCHAR) + if(ISICON(q->vleng)) + *elenp = q->vleng->b_const.fconst.ci; + else { + err("initialization of string of nonconstant length"); + continue; + } + else *elenp = typesize[q->vtype]; + + if(np->vstg == STGCOMMON) + *vlenp = extsymtab[np->b_name.vardesc.varno].maxleng; + else if(np->vstg == STGEQUIV) + *vlenp = eqvclass[np->b_name.vardesc.varno].eqvleng; + else { + *vlenp = (np->vtype==TYCHAR ? + np->vleng->b_const.fconst.ci : typesize[np->vtype]); + if(np->b_name.vdim) + *vlenp *= np->b_name.vdim->nelt->b_const.fconst.ci; + } + return(q); + +doerr: + err("nonconstant implied DO parameter"); + frexpr(q); + curdtp = curdtp->chain.nextp; + +next: curdtelt = 0; + } + +return(NULL); +} + + + + + + +LOCAL void setdata(varp, valp, elen, vlen) +struct bigblock *varp; +ftnint elen, vlen; +struct bigblock *valp; +{ +union constant con; +int i, k; +int stg, type, valtype; +ftnint offset; +register char *s, *t; +static char varname[XL+2]; + +/* output form of name is padded with blanks and preceded + with a storage class digit +*/ + +stg = varp->vstg; +varname[0] = (stg==STGCOMMON ? '2' : (stg==STGEQUIV ? '1' : '0') ); +s = memname(stg, varp->b_addr.memno); +for(t = varname+1 ; *s ; ) + *t++ = *s++; +while(t < varname+XL+1) + *t++ = ' '; +varname[XL+1] = '\0'; + +offset = varp->b_addr.memoffset->b_const.fconst.ci; +type = varp->vtype; +valtype = valp->vtype; +if(type!=TYCHAR && valtype==TYCHAR) + { + if(! ftn66flag) + warn("non-character datum initialized with character string"); + varp->vleng = MKICON(typesize[type]); + varp->vtype = type = TYCHAR; + } +else if( (type==TYCHAR && valtype!=TYCHAR) || + (cktype(OPASSIGN,type,valtype) == TYERROR) ) + { + err("incompatible types in initialization"); + return; + } +if(type != TYCHAR) { + if(valtype == TYUNKNOWN) + con.ci = valp->b_const.fconst.ci; + else consconv(type, &con, valtype, &valp->b_const.fconst); +} + +k = 1; +switch(type) + { + case TYLOGICAL: + type = tylogical; + case TYSHORT: + case TYLONG: + fprintf(initfile, datafmt, varname, offset, vlen, type); + prconi(initfile, type, con.ci); + break; + + case TYCOMPLEX: + k = 2; + type = TYREAL; + case TYREAL: + goto flpt; + + case TYDCOMPLEX: + k = 2; + type = TYDREAL; + case TYDREAL: + flpt: + + for(i = 0 ; i < k ; ++i) + { + fprintf(initfile, datafmt, varname, offset, vlen, type); + prconr(initfile, type, con.cd[i]); + offset += typesize[type]; + } + break; + + case TYCHAR: + k = valp->vleng->b_const.fconst.ci; + if(elen < k) + k = elen; + + for(i = 0 ; i < k ; ++i) + { + fprintf(initfile, datafmt, varname, offset++, vlen, TYCHAR); + fprintf(initfile, "\t%d\n", valp->b_const.fconst.ccp[i]); + } + k = elen - valp->vleng->b_const.fconst.ci; + while( k-- > 0) + { + fprintf(initfile, datafmt, varname, offset++, vlen, TYCHAR); + fprintf(initfile, "\t%d\n", ' '); + } + break; + + default: + fatal1("setdata: impossible type %d", type); + } + +} + + +void +frdata(p0) +chainp p0; +{ +register chainp p; +register bigptr q; + +for(p = p0 ; p ; p = p->chain.nextp) + { + q = p->chain.datap; + if(q->tag == TIMPLDO) + { + if(q->isbusy) + return; /* circular chain completed */ + q->isbusy = YES; + frdata(q->b_impldo.datalist); + ckfree(q); + } + else + frexpr(q); + } + +frchain( &p0); +} diff --git a/lang/pcc/pcc/f77/fcom/defines.h b/lang/pcc/pcc/f77/fcom/defines.h new file mode 100644 index 000000000..4ea3a65d9 --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/defines.h @@ -0,0 +1,267 @@ +/* $Id: defines.h,v 1.15 2008/05/10 07:53:41 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 + +#ifdef FCOM +#include "pass2.h" +#endif +#include "ftypes.h" + +#define INTERDATA 2 +#define GCOS 3 +#define PDP11 4 +#define IBM 5 +#define CMACH 6 +#define VAX 7 + +#define DMR 2 +#define SCJ 3 + +#define BINARY 2 +#define ASCII 3 + +#define PREFIX 2 +#define POSTFIX 3 + +#define M(x) (1<tag==TCONST && ISINT(z->vtype)) +#define ISCHAR(z) (z->vtype==TYCHAR) +#define ISINT(z) ONEOF(z, MSKINT) +#define ISCONST(z) (z->tag==TCONST) +#define ISERROR(z) (z->tag==TERROR) +#define ISPLUSOP(z) (z->tag==TEXPR && z->b_expr.opcode==OPPLUS) +#define ISSTAROP(z) (z->tag==TEXPR && z->b_expr.opcode==OPSTAR) +#define ISONE(z) (ISICON(z) && z->b_const.fconst.ci==1) +/* #define INT(z) ONEOF(z, MSKINT|MSKCHAR) */ +#define MKICON(z) mkintcon( (ftnint)(z) ) +#define CHCON(z) mkstrcon(strlen(z), z) + +/* round a up to a multiple of b */ +#define roundup(a,b) ( b * ( (a+b-1)/b) ) + +/* prototypes for cpu-specific functions */ +void prchars(int *); + diff --git a/lang/pcc/pcc/f77/fcom/defs.h b/lang/pcc/pcc/f77/fcom/defs.h new file mode 100644 index 000000000..488d2b158 --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/defs.h @@ -0,0 +1,567 @@ +/* $Id: defs.h,v 1.23 2011/12/12 09:18:25 plunky Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 +#include +#include + +/* Copied from ../../cc/ccom/pass1.h. */ +#define DATA 1 +#define RDATA 2 +#define UDATA 4 + +#define VL 6 +#define XL 8 + +#define MAXINCLUDES 10 +#define MAXLITERALS 20 +#define MAXCTL 20 +#define MAXHASH 401 +#define MAXSTNO 1000 +#define MAXEXT 200 +#define MAXEQUIV 150 +#define MAXLABLIST 100 + +typedef struct bigblock *bigptr; +typedef union chainedblock *chainp; + +extern FILE *infile; +extern FILE *diagfile; +extern long int headoffset; + +extern char token [ ]; +extern int toklen; +extern int lineno; +extern char *infname; +extern int needkwd; +extern struct labelblock *thislabel; + +extern int mflag, tflag; + +extern flag profileflag; +extern flag optimflag; +extern flag quietflag; +extern flag nowarnflag; +extern flag ftn66flag; +extern flag shiftcase; +extern flag undeftype; +extern flag shortsubs; +extern flag onetripflag; +extern flag checksubs; +extern flag debugflag; +extern int nerr; +extern int nwarn; +extern int ndata; + +extern int parstate; +extern flag headerdone; +extern int blklevel; +extern flag saveall; +extern flag substars; +extern int impltype[ ]; +extern int implleng[ ]; +extern int implstg[ ]; + +extern int tyint; +extern int tylogical; +extern ftnint typesize[]; +extern int typealign[]; +extern int procno; +extern int proctype; +extern char * procname; +extern int rtvlabel[ ]; +extern int fudgelabel; /* to confuse the pdp11 optimizer */ +extern struct bigblock *typeaddr; +extern struct bigblock *retslot; +extern int cxslot; +extern int chslot; +extern int chlgslot; +extern int procclass; +extern ftnint procleng; +extern int nentry; +extern flag multitype; +extern int blklevel; +extern int lastlabno; +extern int lastvarno; +extern int lastargslot; +extern int argloc; +extern ftnint autoleng; +extern ftnint bssleng; +extern int retlabel; +extern int ret0label; +extern int dorange; +extern int regnum[ ]; +extern bigptr regnamep[ ]; +extern int maxregvar; +extern int highregvar; + +extern chainp templist; +extern chainp holdtemps; +extern chainp entries; +extern chainp rpllist; +extern chainp curdtp; +extern ftnint curdtelt; +extern flag toomanyinit; + +extern flag inioctl; +extern int iostmt; +extern struct bigblock *ioblkp; +extern int nioctl; +extern int nequiv; +extern int nintnames; +extern int nextnames; + +struct chain + { + chainp nextp; + bigptr datap; + }; + +extern chainp chains; + +struct ctlframe + { + unsigned ctltype:8; + unsigned dostepsign:8; + int ctlabels[4]; + int dolabel; + struct bigblock *donamep; + bigptr domax; + bigptr dostep; + }; +#define endlabel ctlabels[0] +#define elselabel ctlabels[1] +#define dobodylabel ctlabels[1] +#define doposlabel ctlabels[2] +#define doneglabel ctlabels[3] +extern struct ctlframe ctls[ ]; +extern struct ctlframe *ctlstack; +extern struct ctlframe *lastctl; + +struct extsym + { + char extname[XL]; + unsigned extstg:4; + unsigned extsave:1; + unsigned extinit:1; + chainp extp; + ftnint extleng; + ftnint maxleng; + }; + +extern struct extsym extsymtab[ ]; +extern struct extsym *nextext; +extern struct extsym *lastext; + +struct labelblock + { + int labelno; + unsigned blklevel:8; + unsigned labused:1; + unsigned labinacc:1; + unsigned labdefined:1; + unsigned labtype:2; + ftnint stateno; + }; + +extern struct labelblock labeltab[ ]; +extern struct labelblock *labtabend; +extern struct labelblock *highlabtab; + +struct entrypoint + { + chainp nextp; + struct extsym *entryname; + chainp arglist; + int entrylabel; + int typelabel; + ptr enamep; + }; + +struct primblock + { + struct bigblock *namep; + struct bigblock *argsp; + bigptr fcharp; + bigptr lcharp; + }; + + +struct hashentry + { + int hashval; + struct bigblock *varp; + }; +extern struct hashentry hashtab[ ]; +extern struct hashentry *lasthash; + +struct intrpacked /* bits for intrinsic function description */ + { + unsigned f1:3; + unsigned f2:4; + unsigned f3:7; + }; + +struct nameblock + { + char varname[VL]; + unsigned vdovar:1; + unsigned vdcldone:1; + unsigned vadjdim:1; + unsigned vsave:1; + unsigned vprocclass:3; + unsigned vregno:4; + union { + int varno; + chainp vstfdesc; /* points to (formals, expr) pair */ + struct intrpacked intrdesc; /* bits for intrinsic function */ + } vardesc; + struct dimblock *vdim; + int voffset; + }; + + +struct paramblock + { + char varname[VL]; + bigptr paramval; + } ; + + +struct exprblock + { + unsigned opcode:6; + bigptr leftp; + bigptr rightp; + }; + +struct dcomplex { + double dreal, dimag; +}; + +union constant + { + char *ccp; + ftnint ci; + double cd[2]; + struct dcomplex dc; + }; + +struct constblock + { + union constant fconst; + }; + + +struct listblock + { + chainp listp; + }; + + + +struct addrblock + { + int memno; + bigptr memoffset; + unsigned istemp:1; + unsigned ntempelt:10; + }; + + + +struct errorblock + { + int pad; + }; + + +struct dimblock + { + int ndim; + bigptr nelt; + bigptr baseoffset; + bigptr basexpr; + struct + { + bigptr dimsize; + bigptr dimexpr; + } dims[1]; + }; + + +struct impldoblock /* XXXX */ + { +#define isactive vtype +#define isbusy vclass + struct bigblock *varnp; + struct bigblock *varvp; + bigptr implb; + bigptr impub; + bigptr impstep; + ftnint impdiff; + ftnint implim; + chainp datalist; + }; + + +struct rplblock /* name replacement block */ + { + chainp nextp; + struct bigblock *rplnp; + ptr rplvp; + struct bigblock *rplxp; + int rpltag; + }; + + + +struct equivblock + { + ptr equivs; + unsigned eqvinit:1; + long int eqvtop; + long int eqvbottom; + } ; +#define eqvleng eqvtop + +extern struct equivblock eqvclass[ ]; + + +struct eqvchain + { + chainp nextp; + ptr eqvitem; + long int eqvoffset; + } ; + +union chainedblock + { + struct chain chain; + struct entrypoint entrypoint; + struct rplblock rplblock; + struct eqvchain eqvchain; + }; + + +struct bigblock { + unsigned tag:4; + unsigned vtype:4; + unsigned vclass:4; + unsigned vstg:4; + bigptr vleng; + union { + struct exprblock _expr; + struct addrblock _addr; + struct constblock _const; + struct errorblock _error; + struct listblock _list; + struct primblock _prim; + struct nameblock _name; + struct paramblock _param; + struct impldoblock _impldo; + } _u; +#define b_expr _u._expr +#define b_addr _u._addr +#define b_const _u._const +#define b_error _u._error +#define b_list _u._list +#define b_prim _u._prim +#define b_name _u._name +#define b_param _u._param +#define b_impldo _u._impldo +}; + +struct literal + { + short littype; + short litnum; + union { + ftnint litival; + double litdval; + struct { + char litclen; /* small integer */ + char litcstr[XL]; + } litcval; + } litval; + }; + +extern struct literal litpool[ ]; +extern int nliterals; + + + + + +/* popular functions with non integer return values */ +#define expptr bigptr +#define tagptr bigptr + +ptr cpblock(int ,void *); + +ptr ckalloc(int); +char *varstr(int, char *), *nounder(int, char *), *varunder(int, char *); +char *copyn(int, char *), *copys(char *); +chainp hookup(chainp, chainp), mkchain(bigptr, chainp); +ftnint convci(int, char *), iarrlen(struct bigblock *q); +ftnint lmin(ftnint, ftnint), lmax(ftnint, ftnint); +ftnint simoffset(expptr *); +char *memname(int, int), *convic(ftnint), *setdoto(char *); +double convcd(int, char *); +struct extsym *mkext(char *), + *newentry(struct bigblock *), + *comblock(int, char *s); +struct bigblock *mkname(int, char *); +struct labelblock *mklabel(ftnint); +struct bigblock *addrof(expptr), *call1(int, char *, expptr), + *call2(int, char *, expptr, expptr), + *call3(int, char *, expptr, expptr, expptr), + *call4(int, char *, expptr, expptr, expptr, expptr); +struct bigblock *call0(int, char *), *mkexpr(int, bigptr, bigptr); +struct bigblock *callk(int, char *, bigptr); + +struct bigblock *builtin(int, char *), *fmktemp(int, bigptr), + *mktmpn(int, int, bigptr), *nextdata(ftnint *, ftnint *), + *autovar(int, int, bigptr), *mklhs(struct bigblock *), + *mkaddr(struct bigblock *), *putconst(struct bigblock *), + *memversion(struct bigblock *); +struct bigblock *mkscalar(struct bigblock *np); +struct bigblock *realpart(struct bigblock *p); +struct bigblock *imagpart(struct bigblock *p); + +struct bigblock *mkintcon(ftnint), *mkbitcon(int, int, char *), + *mklogcon(int), *mkaddcon(int), *mkrealcon(int, double), + *mkstrcon(int, char *), *mkcxcon(bigptr,bigptr); +bigptr mkconst(int t); + +bigptr mklist(chainp p); +bigptr mkiodo(chainp, chainp); + + +bigptr mkconv(int, bigptr), + mkfunct(struct bigblock *), fixexpr(struct bigblock *), + fixtype(bigptr); + + +bigptr cpexpr(bigptr), mkprim(bigptr, struct bigblock *, bigptr, bigptr); +struct bigblock *mkarg(int, int); +struct bigblock *errnode(void); +void initkey(void), prtail(void), puteof(void), done(int); +void fileinit(void), procinit(void), endproc(void), doext(void), preven(int); +int inilex(char *), yyparse(void), newlabel(void), lengtype(int, int); +void err(char *, ...), warn(char *, ...), fatal(char *, ...), enddcl(void); +void p2pass(char *s), frexpr(bigptr), execerr(char *, ...); +void setimpl(int, ftnint, int, int), setlog(void), newproc(void); +void prdbginfo(void), impldcl(struct bigblock *p); +void putbracket(void), enddcl(void), doequiv(void); +void puthead(char *), startproc(struct extsym *, int); +void dclerr(char *s, struct bigblock *v), putforce(int, bigptr); +void entrypt(int, int, ftnint, struct extsym *, chainp); +void settype(struct bigblock *, int, int), putlabel(int); +void putbranch(struct bigblock *p), goret(int), putrbrack(int); +void prolog(struct entrypoint *, struct bigblock *), prendproc(void); +void prlocvar(char *, ftnint), prext(char *, ftnint, int); +void vardcl(struct bigblock *v), frchain(chainp *p); +void frtemp(struct bigblock *p), incomm(struct extsym *, struct bigblock *); +void setintr(struct bigblock * v), setext(struct bigblock * v); +struct uux { expptr lb, ub; }; +void setbound(struct bigblock *, int, struct uux []); +void setfmt(struct labelblock *lp), frdata(chainp), frrpl(void), + dataval(struct bigblock *, struct bigblock *), + consnegop(struct bigblock *p), exdo(int, chainp), exelse(void), + exendif(void), exif(bigptr), exelif(bigptr), + exequals(struct bigblock *, bigptr), + exassign(struct bigblock *, struct labelblock *), + exarif(bigptr, struct labelblock *, struct labelblock *, + struct labelblock *); + + + +int intrfunct(char s[VL]), eqn(int, char *, char *); +int fmtstmt(struct labelblock *lp); +int cktype(int, int, int); +int yylex(void), inregister(struct bigblock *); +int inilex(char *), iocname(void); +int maxtype(int, int), flog2(ftnint), hextoi(int); +int cmpstr(char *, char *, ftnint, ftnint); +int enregister(struct bigblock *np); +int conssgn(bigptr p); +int fixargs(int, struct bigblock *); +int addressable(bigptr p); + +void prlabel(int); +void prconi(FILE *, int, ftnint); +void prcona(ftnint); +void prconr(FILE *, int, double); +void prarif(bigptr, int, int, int); +void putstr(char *, ftnint); +NODE *putex1(bigptr p); +void puteq(bigptr, bigptr); +void popstack(chainp *p); +void consconv(int, union constant *, int, union constant *); +void yyerror(char *s); +void enddo(int); +void doinclude(char *); +void flline(void); +void startioctl(void); +void endioctl(void), endio(void), ioclause(int, bigptr), doio(chainp); +void excall(struct bigblock *, struct bigblock *, int, struct labelblock *[]); +void exreturn(expptr p); +void exstop(int, expptr); +void exgoto(struct labelblock *); +void exasgoto(bigptr); +void putcmgo(expptr, int, struct labelblock *[]); +void putexpr(expptr p); +void putif(expptr, int); +void putgoto(int); +void deregister(struct bigblock *np); +NODE *putx(expptr p); +void cpn(int, char *, char *); +void prcmgoto(expptr, int, int, int); +char *lexline(ftnint *n); +bigptr suboffset(struct bigblock *p); +struct bigblock *intraddr(struct bigblock *np); +struct bigblock *intrcall(bigptr, bigptr, int); +void setloc(int); +void prnloc(char *name); +void fprint(bigptr p, int indx); +void ckfree(void *p); + +#undef expptr +#undef tagptr + +#define err1 err +#define err2 err +#define warn1 warn +#define fatal1 fatal diff --git a/lang/pcc/pcc/f77/fcom/equiv.c b/lang/pcc/pcc/f77/fcom/equiv.c new file mode 100644 index 000000000..7e83d153a --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/equiv.c @@ -0,0 +1,309 @@ +/* $Id: equiv.c,v 1.11 2008/05/11 15:28:03 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 "defines.h" +#include "defs.h" + + +/* ROUTINES RELATED TO EQUIVALENCE CLASS PROCESSING */ +LOCAL void eqvcommon(struct equivblock *, int, ftnint); +LOCAL void eqveqv(int, int, ftnint); +LOCAL void freqchain(struct equivblock *p); +LOCAL int nsubs(struct bigblock *p); + +/* called at end of declarations section to process chains + created by EQUIVALENCE statements + */ +void +doequiv() +{ +register int i; +int inequiv, comno, ovarno; +ftnint comoffset, offset, leng; +register struct equivblock *p; +register chainp q; +struct bigblock *itemp; +register struct bigblock *np; +bigptr offp; +int ns; +chainp cp; + +ovarno = comoffset = offset = 0; /* XXX gcc */ +for(i = 0 ; i < nequiv ; ++i) + { + p = &eqvclass[i]; + p->eqvbottom = p->eqvtop = 0; + comno = -1; + + for(q = p->equivs ; q ; q = q->eqvchain.nextp) + { + itemp = q->eqvchain.eqvitem; + vardcl(np = itemp->b_prim.namep); + if(itemp->b_prim.argsp || itemp->b_prim.fcharp) + { + if(np->b_name.vdim!=NULL && np->b_name.vdim->ndim>1 && + nsubs(itemp->b_prim.argsp)==1 ) + { + if(! ftn66flag) + warn("1-dim subscript in EQUIVALENCE"); + cp = NULL; + ns = np->b_name.vdim->ndim; + while(--ns > 0) + cp = mkchain( MKICON(1), cp); + itemp->b_prim.argsp->b_list.listp->chain.nextp = cp; + } + offp = suboffset(itemp); + } + else offp = MKICON(0); + if(ISICON(offp)) + offset = q->eqvchain.eqvoffset = offp->b_const.fconst.ci; + else { + dclerr("nonconstant subscript in equivalence ", np); + np = NULL; + goto endit; + } + if( (leng = iarrlen(np)) < 0) + { + dclerr("adjustable in equivalence", np); + np = NULL; + goto endit; + } + p->eqvbottom = lmin(p->eqvbottom, -offset); + p->eqvtop = lmax(p->eqvtop, leng-offset); + + switch(np->vstg) + { + case STGUNKNOWN: + case STGBSS: + case STGEQUIV: + break; + + case STGCOMMON: + comno = np->b_name.vardesc.varno; + comoffset = np->b_name.voffset + offset; + break; + + default: + dclerr("bad storage class in equivalence", np); + np = NULL; + goto endit; + } + endit: + frexpr(offp); + q->eqvchain.eqvitem = np; + } + + if(comno >= 0) + eqvcommon(p, comno, comoffset); + else for(q = p->equivs ; q ; q = q->eqvchain.nextp) + { + if((np = q->eqvchain.eqvitem)) + { + inequiv = NO; + if(np->vstg==STGEQUIV) { + if( (ovarno = np->b_name.vardesc.varno) == i) + { + if(np->b_name.voffset + q->eqvchain.eqvoffset != 0) + dclerr("inconsistent equivalence", np); + } + else { + offset = np->b_name.voffset; + inequiv = YES; + } + } + np->vstg = STGEQUIV; + np->b_name.vardesc.varno = i; + np->b_name.voffset = - q->eqvchain.eqvoffset; + + if(inequiv) + eqveqv(i, ovarno, q->eqvchain.eqvoffset + offset); + } + } + } + +for(i = 0 ; i < nequiv ; ++i) + { + p = & eqvclass[i]; + if(p->eqvbottom!=0 || p->eqvtop!=0) + { + for(q = p->equivs ; q; q = q->eqvchain.nextp) + { + np = q->eqvchain.eqvitem; + np->b_name.voffset -= p->eqvbottom; + if(np->b_name.voffset % typealign[np->vtype] != 0) + dclerr("bad alignment forced by equivalence", np); + } + p->eqvtop -= p->eqvbottom; + p->eqvbottom = 0; + } + freqchain(p); + } +} + + + + + +/* put equivalence chain p at common block comno + comoffset */ + +LOCAL void eqvcommon(p, comno, comoffset) +struct equivblock *p; +int comno; +ftnint comoffset; +{ +int ovarno; +ftnint k, offq; +register struct bigblock *np; +register chainp q; + +if(comoffset + p->eqvbottom < 0) + { + err1("attempt to extend common %s backward", + nounder(XL, extsymtab[comno].extname) ); + freqchain(p); + return; + } + +if( (k = comoffset + p->eqvtop) > extsymtab[comno].extleng) + extsymtab[comno].extleng = k; + +for(q = p->equivs ; q ; q = q->eqvchain.nextp) + if((np = q->eqvchain.eqvitem)) + { + switch(np->vstg) + { + case STGUNKNOWN: + case STGBSS: + np->vstg = STGCOMMON; + np->b_name.vardesc.varno = comno; + np->b_name.voffset = comoffset - q->eqvchain.eqvoffset; + break; + + case STGEQUIV: + ovarno = np->b_name.vardesc.varno; + offq = comoffset - q->eqvchain.eqvoffset - np->b_name.voffset; + np->vstg = STGCOMMON; + np->b_name.vardesc.varno = comno; + np->b_name.voffset = comoffset - q->eqvchain.eqvoffset; + if(ovarno != (p - eqvclass)) + eqvcommon(&eqvclass[ovarno], comno, offq); + break; + + case STGCOMMON: + if(comno != np->b_name.vardesc.varno || + comoffset != np->b_name.voffset+q->eqvchain.eqvoffset) + dclerr("inconsistent common usage", np); + break; + + + default: + fatal1("eqvcommon: impossible vstg %d", np->vstg); + } + } + +freqchain(p); +p->eqvbottom = p->eqvtop = 0; +} + + +/* put all items on ovarno chain on front of nvarno chain + * adjust offsets of ovarno elements and top and bottom of nvarno chain + */ + +LOCAL void eqveqv(nvarno, ovarno, delta) +int ovarno, nvarno; +ftnint delta; +{ +register struct equivblock *p0, *p; +register struct nameblock *np; +chainp q, q1; + +p0 = eqvclass + nvarno; +p = eqvclass + ovarno; +p0->eqvbottom = lmin(p0->eqvbottom, p->eqvbottom - delta); +p0->eqvtop = lmax(p0->eqvtop, p->eqvtop - delta); +p->eqvbottom = p->eqvtop = 0; + +for(q = p->equivs ; q ; q = q1) + { + q1 = q->eqvchain.nextp; + if( (np = q->eqvchain.eqvitem) && np->vardesc.varno==ovarno) + { + q->eqvchain.nextp = p0->equivs; + p0->equivs = q; + q->eqvchain.eqvoffset -= delta; + np->vardesc.varno = nvarno; + np->voffset -= delta; + } + else ckfree(q); + } +p->equivs = NULL; +} + + + + +LOCAL void +freqchain(p) +register struct equivblock *p; +{ +register chainp q, oq; + +for(q = p->equivs ; q ; q = oq) + { + oq = q->eqvchain.nextp; + ckfree(q); + } +p->equivs = NULL; +} + + + + + +LOCAL int +nsubs(p) +register struct bigblock *p; +{ +register int n; +register chainp q; + +n = 0; +if(p) + for(q = p->b_list.listp ; q ; q = q->chain.nextp) + ++n; + +return(n); +} diff --git a/lang/pcc/pcc/f77/fcom/error.c b/lang/pcc/pcc/f77/fcom/error.c new file mode 100644 index 000000000..d2fbabdae --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/error.c @@ -0,0 +1,121 @@ +/* $Id: error.c,v 1.8 2008/05/10 07:53:41 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 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. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 + +#include "defines.h" +#include "defs.h" + +void +warn(char *s, ...) +{ + va_list ap; + + if(nowarnflag) + return; + + va_start(ap, s); + fprintf(diagfile, "Warning on line %d of %s: ", lineno, infname); + vfprintf(diagfile, s, ap); + fprintf(diagfile, "\n"); + va_end(ap); + ++nwarn; +} + +void +err(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + fprintf(diagfile, "Error on line %d of %s: ", lineno, infname); + vfprintf(diagfile, s, ap); + fprintf(diagfile, "\n"); + va_end(ap); + ++nerr; +} + +void +yyerror(s) +char *s; +{ err(s); } + + +void +dclerr(s, v) + char *s; + struct bigblock *v; +{ + char buff[100]; + + if(v) { + sprintf(buff, "Declaration error for %s: %s", + varstr(VL, v->b_name.varname), s); + err( buff); + } else + err1("Declaration error %s", s); +} + + +void +execerr(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + fprintf(diagfile, "Error on line %d of %s: Execution error ", + lineno, infname); + vfprintf(diagfile, s, ap); + fprintf(diagfile, "\n"); + va_end(ap); + ++nerr; +} + +void +fatal(char *s, ...) +{ + va_list ap; + + va_start(ap, s); + fprintf(diagfile, "Compiler error line %d of %s: ", lineno, infname); + vfprintf(diagfile, s, ap); + fprintf(diagfile, "\n"); + va_end(ap); + + if(debugflag) + abort(); + done(3); + exit(3); +} diff --git a/lang/pcc/pcc/f77/fcom/exec.c b/lang/pcc/pcc/f77/fcom/exec.c new file mode 100644 index 000000000..6584e8ac1 --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/exec.c @@ -0,0 +1,591 @@ +/* $Id: exec.c,v 1.14 2008/05/11 15:28:03 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 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. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 + +#include "defines.h" +#include "defs.h" + +/* Logical IF codes +*/ +LOCAL void exar2(int, bigptr, int, int); +LOCAL void pushctl(int code); +LOCAL void popctl(void); +LOCAL void poplab(void); +LOCAL void mkstfunct(struct bigblock *, bigptr); + +void +exif(p) +bigptr p; +{ +pushctl(CTLIF); +ctlstack->elselabel = newlabel(); +putif(p, ctlstack->elselabel); +} + + +void +exelif(p) +bigptr p; +{ +if(ctlstack->ctltype == CTLIF) + { + if(ctlstack->endlabel == 0) + ctlstack->endlabel = newlabel(); + putgoto(ctlstack->endlabel); + putlabel(ctlstack->elselabel); + ctlstack->elselabel = newlabel(); + putif(p, ctlstack->elselabel); + } + +else execerr("elseif out of place", 0); +} + + + + +void +exelse() +{ +if(ctlstack->ctltype==CTLIF) + { + if(ctlstack->endlabel == 0) + ctlstack->endlabel = newlabel(); + putgoto( ctlstack->endlabel ); + putlabel(ctlstack->elselabel); + ctlstack->ctltype = CTLELSE; + } + +else execerr("else out of place", 0); +} + +void +exendif() +{ +if(ctlstack->ctltype == CTLIF) + { + putlabel(ctlstack->elselabel); + if(ctlstack->endlabel) + putlabel(ctlstack->endlabel); + popctl(); + } +else if(ctlstack->ctltype == CTLELSE) + { + putlabel(ctlstack->endlabel); + popctl(); + } + +else execerr("endif out of place", 0); +} + + + +LOCAL void +pushctl(code) +int code; +{ +register int i; + +if(++ctlstack >= lastctl) + fatal("nesting too deep"); +ctlstack->ctltype = code; +for(i = 0 ; i < 4 ; ++i) + ctlstack->ctlabels[i] = 0; +++blklevel; +} + + +LOCAL void +popctl() +{ +if( ctlstack-- < ctls ) + fatal("control stack empty"); +--blklevel; +poplab(); +} + + + +LOCAL void +poplab() +{ +register struct labelblock *lp; + +for(lp = labeltab ; lp < highlabtab ; ++lp) + if(lp->labdefined) + { + /* mark all labels in inner blocks unreachable */ + if(lp->blklevel > blklevel) + lp->labinacc = YES; + } + else if(lp->blklevel > blklevel) + { + /* move all labels referred to in inner blocks out a level */ + lp->blklevel = blklevel; + } +} + + + +/* BRANCHING CODE +*/ +void +exgoto(lab) +struct labelblock *lab; +{ +putgoto(lab->labelno); +} + + + + +/* + * Found an assignment expression. + */ +void +exequals(struct bigblock *lp, bigptr rp) +{ + if(lp->tag != TPRIM) { + err("assignment to a non-variable"); + frexpr(lp); + frexpr(rp); + } else if(lp->b_prim.namep->vclass!=CLVAR && lp->b_prim.argsp) { + if(parstate >= INEXEC) + err("statement function amid executables"); + else + mkstfunct(lp, rp); + } else { + if(parstate < INDATA) + enddcl(); + puteq(mklhs(lp), rp); + } +} + +/* + * Create a statement function; e.g. like "f(i)=i*i" + */ +void +mkstfunct(struct bigblock *lp, bigptr rp) +{ + struct bigblock *p; + struct bigblock *np; + chainp args; + + np = lp->b_prim.namep; + if(np->vclass == CLUNKNOWN) + np->vclass = CLPROC; + else { + dclerr("redeclaration of statement function", np); + return; + } + + np->b_name.vprocclass = PSTFUNCT; + np->vstg = STGSTFUNCT; + impldcl(np); + args = (lp->b_prim.argsp ? lp->b_prim.argsp->b_list.listp : NULL); + np->b_name.vardesc.vstfdesc = mkchain((void *)args, (void *)rp); + + for( ; args ; args = args->chain.nextp) + if( (p = args->chain.datap)->tag!=TPRIM || + p->b_prim.argsp || p->b_prim.fcharp || p->b_prim.lcharp) + err("non-variable argument in statement function definition"); + else { + vardcl(args->chain.datap = p->b_prim.namep); + ckfree(p); + } +} + + +void +excall(name, args, nstars, labels) +struct bigblock *name; +struct bigblock *args; +int nstars; +struct labelblock *labels[ ]; +{ +register bigptr p; + +settype(name, TYSUBR, 0); +p = mkfunct( mkprim(name, args, NULL, NULL) ); +p->vtype = p->b_expr.leftp->vtype = TYINT; +if(nstars > 0) + putcmgo(p, nstars, labels); +else putexpr(p); +} + + +void +exstop(stop, p) +int stop; +register bigptr p; +{ +char *q; +int n; + +if(p) + { + if( ! ISCONST(p) ) + { + execerr("pause/stop argument must be constant", 0); + frexpr(p); + p = mkstrcon(0, 0); + } + else if( ISINT(p->vtype) ) + { + q = convic(p->b_const.fconst.ci); + n = strlen(q); + if(n > 0) + { + p->b_const.fconst.ccp = copyn(n, q); + p->vtype = TYCHAR; + p->vleng = MKICON(n); + } + else + p = mkstrcon(0, 0); + } + else if(p->vtype != TYCHAR) + { + execerr("pause/stop argument must be integer or string", 0); + p = mkstrcon(0, 0); + } + } +else p = mkstrcon(0, 0); + +putexpr( call1(TYSUBR, (stop ? "s_stop" : "s_paus"), p) ); +} + +/* DO LOOP CODE */ + +#define DOINIT par[0] +#define DOLIMIT par[1] +#define DOINCR par[2] + +#define VARSTEP 0 +#define POSSTEP 1 +#define NEGSTEP 2 + +void +exdo(range, spec) +int range; +chainp spec; +{ +register bigptr p, q; +bigptr q1; +register struct bigblock *np; +chainp cp; +register int i; +int dotype, incsign = 0; /* XXX gcc */ +struct bigblock *dovarp, *dostgp; +bigptr par[3]; + +pushctl(CTLDO); +dorange = ctlstack->dolabel = range; +np = spec->chain.datap; +ctlstack->donamep = NULL; +if(np->b_name.vdovar) + { + err1("nested loops with variable %s", varstr(VL,np->b_name.varname)); + ctlstack->donamep = NULL; + return; + } + +dovarp = mklhs( mkprim(np, 0,0,0) ); +if( ! ONEOF(dovarp->vtype, MSKINT|MSKREAL) ) + { + err("bad type on do variable"); + return; + } +ctlstack->donamep = np; + +np->b_name.vdovar = YES; +if( enregister(np) ) + { + /* stgp points to a storage version, varp to a register version */ + dostgp = dovarp; + dovarp = mklhs( mkprim(np, 0,0,0) ); + } +else + dostgp = NULL; +dotype = dovarp->vtype; + +for(i=0 , cp = spec->chain.nextp ; cp!=NULL && i<3 ; cp = cp->chain.nextp) + { + p = par[i++] = fixtype(cp->chain.datap); + if( ! ONEOF(p->vtype, MSKINT|MSKREAL) ) + { + err("bad type on DO parameter"); + return; + } + } + +frchain(&spec); +switch(i) + { + case 0: + case 1: + err("too few DO parameters"); + return; + + default: + err("too many DO parameters"); + return; + + case 2: + DOINCR = MKICON(1); + + case 3: + break; + } + +ctlstack->endlabel = newlabel(); +ctlstack->dobodylabel = newlabel(); + +if( ISCONST(DOLIMIT) ) + ctlstack->domax = mkconv(dotype, DOLIMIT); +else + ctlstack->domax = fmktemp(dotype, NULL); + +if( ISCONST(DOINCR) ) + { + ctlstack->dostep = mkconv(dotype, DOINCR); + if( (incsign = conssgn(ctlstack->dostep)) == 0) + err("zero DO increment"); + ctlstack->dostepsign = (incsign > 0 ? POSSTEP : NEGSTEP); + } +else + { + ctlstack->dostep = fmktemp(dotype, NULL); + ctlstack->dostepsign = VARSTEP; + ctlstack->doposlabel = newlabel(); + ctlstack->doneglabel = newlabel(); + } + +if( ISCONST(ctlstack->domax) && ISCONST(DOINIT) && ctlstack->dostepsign!=VARSTEP) + { + puteq(cpexpr(dovarp), cpexpr(DOINIT)); + if( onetripflag ) + frexpr(DOINIT); + else + { + q = mkexpr(OPPLUS, MKICON(1), + mkexpr(OPMINUS, cpexpr(ctlstack->domax), cpexpr(DOINIT)) ); + if(incsign != conssgn(q)) + { + warn("DO range never executed"); + putgoto(ctlstack->endlabel); + } + frexpr(q); + } + } +else if(ctlstack->dostepsign!=VARSTEP && !onetripflag) + { + if( ISCONST(ctlstack->domax) ) + q = cpexpr(ctlstack->domax); + else + q = mkexpr(OPASSIGN, cpexpr(ctlstack->domax), DOLIMIT); + + q1 = mkexpr(OPASSIGN, cpexpr(dovarp), DOINIT); + q = mkexpr( (ctlstack->dostepsign==POSSTEP ? OPLE : OPGE), q1, q); + putif(q, ctlstack->endlabel); + } +else + { + if(! ISCONST(ctlstack->domax) ) + puteq( cpexpr(ctlstack->domax), DOLIMIT); + q = DOINIT; + if( ! onetripflag ) + q = mkexpr(OPMINUS, q, + mkexpr(OPASSIGN, cpexpr(ctlstack->dostep), DOINCR) ); + puteq( cpexpr(dovarp), q); + if(onetripflag && ctlstack->dostepsign==VARSTEP) + puteq( cpexpr(ctlstack->dostep), DOINCR); + } + +if(ctlstack->dostepsign == VARSTEP) + { + if(onetripflag) + putgoto(ctlstack->dobodylabel); + else + putif( mkexpr(OPGE, cpexpr(ctlstack->dostep), MKICON(0)), + ctlstack->doneglabel ); + putlabel(ctlstack->doposlabel); + + p = cpexpr(dovarp); + putif( mkexpr(OPLE, mkexpr(OPASSIGN, p, + mkexpr(OPPLUS, cpexpr(dovarp), cpexpr(ctlstack->dostep))), + cpexpr(ctlstack->domax)), ctlstack->endlabel); + } +putlabel(ctlstack->dobodylabel); +if(dostgp) + puteq(dostgp, cpexpr(dovarp)); +frexpr(dovarp); +} + +/* + * Reached the end of a DO statement. + */ +void +enddo(int here) +{ + register struct ctlframe *q; + register bigptr t; + struct bigblock *np; + struct bigblock *ap; + register int i; + + while(here == dorange) { + if((np = ctlstack->donamep)) { + + t = mklhs(mkprim(ctlstack->donamep, 0,0 ,0)); + t = mkexpr(OPASSIGN, cpexpr(t), + mkexpr(OPPLUS, t, cpexpr(ctlstack->dostep))); + + if(ctlstack->dostepsign == VARSTEP) { + putif( mkexpr(OPLE, cpexpr(ctlstack->dostep), + MKICON(0)), ctlstack->doposlabel); + putlabel(ctlstack->doneglabel); + putif( mkexpr(OPLT, t, ctlstack->domax), + ctlstack->dobodylabel); + } else + putif( mkexpr( (ctlstack->dostepsign==POSSTEP ? + OPGT : OPLT), t, ctlstack->domax), + ctlstack->dobodylabel); + putlabel(ctlstack->endlabel); + if((ap = memversion(np))) + puteq(ap, mklhs( mkprim(np,0,0,0)) ); + for(i = 0 ; i < 4 ; ++i) + ctlstack->ctlabels[i] = 0; + deregister(ctlstack->donamep); + ctlstack->donamep->b_name.vdovar = NO; + frexpr(ctlstack->dostep); + } + + popctl(); + dorange = 0; + for(q = ctlstack ; q>=ctls ; --q) + if(q->ctltype == CTLDO) { + dorange = q->dolabel; + break; + } + } +} + +void +exassign(vname, labelval) +struct bigblock *vname; +struct labelblock *labelval; +{ +struct bigblock *p; + +p = mklhs(mkprim(vname,0,0,0)); +if( ! ONEOF(p->vtype, MSKINT|MSKADDR) ) + err("noninteger assign variable"); +else + puteq(p, mkaddcon(labelval->labelno) ); +} + + +void +exarif(expr, neglab, zerlab, poslab) +bigptr expr; +struct labelblock *neglab, *zerlab, *poslab; +{ +register int lm, lz, lp; + +lm = neglab->labelno; +lz = zerlab->labelno; +lp = poslab->labelno; +expr = fixtype(expr); + +if( ! ONEOF(expr->vtype, MSKINT|MSKREAL) ) + { + err("invalid type of arithmetic if expression"); + frexpr(expr); + } +else + { + if(lm == lz) + exar2(OPLE, expr, lm, lp); + else if(lm == lp) + exar2(OPNE, expr, lm, lz); + else if(lz == lp) + exar2(OPGE, expr, lz, lm); + else + prarif(expr, lm, lz, lp); + } +} + + + +LOCAL void exar2(op, e, l1, l2) +int op; +bigptr e; +int l1, l2; +{ +putif( mkexpr(op, e, MKICON(0)), l2); +putgoto(l1); +} + +void +exreturn(p) +register bigptr p; +{ +if(p && (proctype!=TYSUBR || procclass!=CLPROC) ) + { + err("alternate return in nonsubroutine"); + p = 0; + } + +if(p) + { + putforce(TYINT, p); + putgoto(retlabel); + } +else + putgoto(procclass==TYSUBR ? ret0label : retlabel); +} + + +void +exasgoto(labvar) +bigptr labvar; +{ +register struct bigblock *p; + +p = mklhs( mkprim(labvar,0,0,0) ); +if( ! ISINT(p->vtype) ) + err("assigned goto variable must be integer"); +else + putbranch(p); +} diff --git a/lang/pcc/pcc/f77/fcom/expr.c b/lang/pcc/pcc/f77/fcom/expr.c new file mode 100644 index 000000000..0f4d24b4f --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/expr.c @@ -0,0 +1,2179 @@ +/* $Id: expr.c,v 1.20 2008/05/11 15:28:03 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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 + +#include "defines.h" +#include "defs.h" + +/* little routines to create constant blocks */ +LOCAL int letter(int c); +LOCAL void conspower(union constant *, struct bigblock *, ftnint); +LOCAL void consbinop(int, int, union constant *, union constant *, + union constant *); +LOCAL void zdiv(struct dcomplex *, struct dcomplex *, struct dcomplex *); +LOCAL struct bigblock *stfcall(struct bigblock *, struct bigblock *); +LOCAL bigptr mkpower(struct bigblock *p); +LOCAL bigptr fold(struct bigblock *e); +LOCAL bigptr subcheck(struct bigblock *, bigptr); + +struct bigblock *mkconst(t) +register int t; +{ +register struct bigblock *p; + +p = BALLO(); +p->tag = TCONST; +p->vtype = t; +return(p); +} + + +struct bigblock *mklogcon(l) +register int l; +{ +register struct bigblock * p; + +p = mkconst(TYLOGICAL); +p->b_const.fconst.ci = l; +return(p); +} + + + +struct bigblock *mkintcon(l) +ftnint l; +{ +register struct bigblock *p; + +p = mkconst(TYLONG); +p->b_const.fconst.ci = l; +#ifdef MAXSHORT + if(l >= -MAXSHORT && l <= MAXSHORT) + p->vtype = TYSHORT; +#endif +return(p); +} + + + +struct bigblock *mkaddcon(l) +register int l; +{ +register struct bigblock *p; + +p = mkconst(TYADDR); +p->b_const.fconst.ci = l; +return(p); +} + + + +struct bigblock *mkrealcon(t, d) +register int t; +double d; +{ +register struct bigblock *p; + +p = mkconst(t); +p->b_const.fconst.cd[0] = d; +return(p); +} + + +struct bigblock *mkbitcon(shift, leng, s) +int shift; +int leng; +char *s; +{ +register struct bigblock *p; + +p = mkconst(TYUNKNOWN); +p->b_const.fconst.ci = 0; +while(--leng >= 0) + if(*s != ' ') + p->b_const.fconst.ci = (p->b_const.fconst.ci << shift) | hextoi(*s++); +return(p); +} + + + + + +struct bigblock *mkstrcon(l,v) +int l; +register char *v; +{ +register struct bigblock *p; +register char *s; + +p = mkconst(TYCHAR); +p->vleng = MKICON(l); +p->b_const.fconst.ccp = s = (char *) ckalloc(l); +while(--l >= 0) + *s++ = *v++; +return(p); +} + + +struct bigblock *mkcxcon(realp,imagp) +register bigptr realp, imagp; +{ +int rtype, itype; +register struct bigblock *p; + +rtype = realp->vtype; +itype = imagp->vtype; + +if( ISCONST(realp) && ISNUMERIC(rtype) && ISCONST(imagp) && ISNUMERIC(itype) ) + { + p = mkconst( (rtype==TYDREAL||itype==TYDREAL) ? TYDCOMPLEX : TYCOMPLEX ); + if( ISINT(rtype) ) + p->b_const.fconst.cd[0] = realp->b_const.fconst.ci; + else p->b_const.fconst.cd[0] = realp->b_const.fconst.cd[0]; + if( ISINT(itype) ) + p->b_const.fconst.cd[1] = imagp->b_const.fconst.ci; + else p->b_const.fconst.cd[1] = imagp->b_const.fconst.cd[0]; + } +else + { + err("invalid complex constant"); + p = errnode(); + } + +frexpr(realp); +frexpr(imagp); +return(p); +} + + +struct bigblock *errnode() +{ +struct bigblock *p; +p = BALLO(); +p->tag = TERROR; +p->vtype = TYERROR; +return(p); +} + + + + + +bigptr mkconv(t, p) +register int t; +register bigptr p; +{ +register bigptr q; + +if(t==TYUNKNOWN || t==TYERROR) + fatal1("mkconv of impossible type %d", t); +if(t == p->vtype) + return(p); + +else if( ISCONST(p) && p->vtype!=TYADDR) + { + q = mkconst(t); + consconv(t, &(q->b_const.fconst), p->vtype, &(p->b_const.fconst)); + frexpr(p); + } +else + { + q = mkexpr(OPCONV, p, 0); + q->vtype = t; + } +return(q); +} + + + +struct bigblock *addrof(p) +bigptr p; +{ +return( mkexpr(OPADDR, p, NULL) ); +} + + + +bigptr +cpexpr(p) +register bigptr p; +{ +register bigptr e; +int tag; +register chainp ep, pp; + +#if 0 +static int blksize[ ] = { 0, sizeof(struct nameblock), sizeof(struct constblock), + sizeof(struct exprblock), sizeof(struct addrblock), + sizeof(struct primblock), sizeof(struct listblock), + sizeof(struct errorblock) + }; +#endif + +if(p == NULL) + return(NULL); + +if( (tag = p->tag) == TNAME) + return(p); + +#if 0 +e = cpblock( blksize[p->tag] , p); +#else +e = cpblock( sizeof(struct bigblock) , p); +#endif + +switch(tag) + { + case TCONST: + if(e->vtype == TYCHAR) + { + e->b_const.fconst.ccp = copyn(1+strlen(e->b_const.fconst.ccp), e->b_const.fconst.ccp); + e->vleng = cpexpr(e->vleng); + } + case TERROR: + break; + + case TEXPR: + e->b_expr.leftp = cpexpr(p->b_expr.leftp); + e->b_expr.rightp = cpexpr(p->b_expr.rightp); + break; + + case TLIST: + if((pp = p->b_list.listp)) + { + ep = e->b_list.listp = mkchain( cpexpr(pp->chain.datap), NULL); + for(pp = pp->chain.nextp ; pp ; pp = pp->chain.nextp) + ep = ep->chain.nextp = mkchain( cpexpr(pp->chain.datap), NULL); + } + break; + + case TADDR: + e->vleng = cpexpr(e->vleng); + e->b_addr.memoffset = cpexpr(e->b_addr.memoffset); + e->b_addr.istemp = NO; + break; + + case TPRIM: + e->b_prim.argsp = cpexpr(e->b_prim.argsp); + e->b_prim.fcharp = cpexpr(e->b_prim.fcharp); + e->b_prim.lcharp = cpexpr(e->b_prim.lcharp); + break; + + default: + fatal1("cpexpr: impossible tag %d", tag); + } + +return(e); +} + +void +frexpr(p) +register bigptr p; +{ +register chainp q; + +if(p == NULL) + return; + +switch(p->tag) + { + case TCONST: + if( ISCHAR(p) ) + { + ckfree(p->b_const.fconst.ccp); + frexpr(p->vleng); + } + break; + + case TADDR: + if(p->b_addr.istemp) + { + frtemp(p); + return; + } + frexpr(p->vleng); + frexpr(p->b_addr.memoffset); + break; + + case TERROR: + break; + + case TNAME: + return; + + case TPRIM: + frexpr(p->b_prim.argsp); + frexpr(p->b_prim.fcharp); + frexpr(p->b_prim.lcharp); + break; + + case TEXPR: + frexpr(p->b_expr.leftp); + if(p->b_expr.rightp) + frexpr(p->b_expr.rightp); + break; + + case TLIST: + for(q = p->b_list.listp ; q ; q = q->chain.nextp) + frexpr(q->chain.datap); + frchain( &(p->b_list.listp) ); + break; + + default: + fatal1("frexpr: impossible tag %d", p->tag); + } + +ckfree(p); +} + +/* fix up types in expression; replace subtrees and convert + names to address blocks */ + +bigptr fixtype(p) +register bigptr p; +{ + +if(p == 0) + return(0); + +switch(p->tag) + { + case TCONST: + if( ! ONEOF(p->vtype, MSKINT|MSKLOGICAL|MSKADDR) ) + p = putconst(p); + return(p); + + case TADDR: + p->b_addr.memoffset = fixtype(p->b_addr.memoffset); + return(p); + + case TERROR: + return(p); + + default: + fatal1("fixtype: impossible tag %d", p->tag); + + case TEXPR: + return( fixexpr(p) ); + + case TLIST: + return( p ); + + case TPRIM: + if(p->b_prim.argsp && p->b_prim.namep->vclass!=CLVAR) + return( mkfunct(p) ); + else return( mklhs(p) ); + } +} + + + + + +/* special case tree transformations and cleanups of expression trees */ + +bigptr fixexpr(p) +register struct bigblock *p; +{ +bigptr lp; +register bigptr rp; +register bigptr q; +int opcode, ltype, rtype, ptype, mtype; + +if(p->tag == TERROR) + return(p); +else if(p->tag != TEXPR) + fatal1("fixexpr: invalid tag %d", p->tag); +opcode = p->b_expr.opcode; +lp = p->b_expr.leftp = fixtype(p->b_expr.leftp); +ltype = lp->vtype; +if(opcode==OPASSIGN && lp->tag!=TADDR) + { + err("left side of assignment must be variable"); + frexpr(p); + return( errnode() ); + } + +if(p->b_expr.rightp) + { + rp = p->b_expr.rightp = fixtype(p->b_expr.rightp); + rtype = rp->vtype; + } +else + { + rp = NULL; + rtype = 0; + } + +/* force folding if possible */ +if( ISCONST(lp) && (rp==NULL || ISCONST(rp)) ) + { + q = mkexpr(opcode, lp, rp); + if( ISCONST(q) ) + return(q); + ckfree(q); /* constants did not fold */ + } + +if( (ptype = cktype(opcode, ltype, rtype)) == TYERROR) + { + frexpr(p); + return( errnode() ); + } + +switch(opcode) + { + case OPCONCAT: + if(p->vleng == NULL) + p->vleng = mkexpr(OPPLUS, cpexpr(lp->vleng), + cpexpr(rp->vleng) ); + break; + + case OPASSIGN: + if(ltype == rtype) + break; + if( ! ISCONST(rp) && ISREAL(ltype) && ISREAL(rtype) ) + break; + if( ISCOMPLEX(ltype) || ISCOMPLEX(rtype) ) + break; + if( ONEOF(ltype, MSKADDR|MSKINT) && ONEOF(rtype, MSKADDR|MSKINT) + && typesize[ltype]>=typesize[rtype] ) + break; + p->b_expr.rightp = fixtype( mkconv(ptype, rp) ); + break; + + case OPSLASH: + if( ISCOMPLEX(rtype) ) + { + p = call2(ptype, ptype==TYCOMPLEX? "c_div" : "z_div", + mkconv(ptype, lp), mkconv(ptype, rp) ); + break; + } + case OPPLUS: + case OPMINUS: + case OPSTAR: + case OPMOD: + if(ptype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp) ) || + (rtype==TYREAL && ! ISCONST(rp) ) )) + break; + if( ISCOMPLEX(ptype) ) + break; + if(ltype != ptype) + p->b_expr.leftp = fixtype(mkconv(ptype,lp)); + if(rtype != ptype) + p->b_expr.rightp = fixtype(mkconv(ptype,rp)); + break; + + case OPPOWER: + return( mkpower(p) ); + + case OPLT: + case OPLE: + case OPGT: + case OPGE: + case OPEQ: + case OPNE: + if(ltype == rtype) + break; + mtype = cktype(OPMINUS, ltype, rtype); + if(mtype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp)) || + (rtype==TYREAL && ! ISCONST(rp)) )) + break; + if( ISCOMPLEX(mtype) ) + break; + if(ltype != mtype) + p->b_expr.leftp = fixtype(mkconv(mtype,lp)); + if(rtype != mtype) + p->b_expr.rightp = fixtype(mkconv(mtype,rp)); + break; + + + case OPCONV: + ptype = cktype(OPCONV, p->vtype, ltype); + if(lp->tag==TEXPR && lp->b_expr.opcode==OPCOMMA) + { + lp->b_expr.rightp = fixtype( mkconv(ptype, lp->b_expr.rightp) ); + ckfree(p); + p = lp; + } + break; + + case OPADDR: + if(lp->tag==TEXPR && lp->b_expr.opcode==OPADDR) + fatal("addr of addr"); + break; + + case OPCOMMA: + break; + + case OPMIN: + case OPMAX: + ptype = p->vtype; + break; + + default: + break; + } + +p->vtype = ptype; +return(p); +} + +#if SZINT < SZLONG +/* + for efficient subscripting, replace long ints by shorts + in easy places +*/ + +bigptr shorten(p) +register bigptr p; +{ +register bigptr q; + +if(p->vtype != TYLONG) + return(p); + +switch(p->tag) + { + case TERROR: + case TLIST: + return(p); + + case TCONST: + case TADDR: + return( mkconv(TYINT,p) ); + + case TEXPR: + break; + + default: + fatal1("shorten: invalid tag %d", p->tag); + } + +switch(p->opcode) + { + case OPPLUS: + case OPMINUS: + case OPSTAR: + q = shorten( cpexpr(p->rightp) ); + if(q->vtype == TYINT) + { + p->leftp = shorten(p->leftp); + if(p->leftp->vtype == TYLONG) + frexpr(q); + else + { + frexpr(p->rightp); + p->rightp = q; + p->vtype = TYINT; + } + } + break; + + case OPNEG: + p->leftp = shorten(p->leftp); + if(p->leftp->vtype == TYINT) + p->vtype = TYINT; + break; + + case OPCALL: + case OPCCALL: + p = mkconv(TYINT,p); + break; + default: + break; + } + +return(p); +} +#endif + +int +fixargs(doput, p0) +int doput; +struct bigblock *p0; +{ +register chainp p; +register bigptr q, t; +register int qtag; +int nargs; + +nargs = 0; +if(p0) + for(p = p0->b_list.listp ; p ; p = p->chain.nextp) + { + ++nargs; + q = p->chain.datap; + qtag = q->tag; + if(qtag == TCONST) + { + if(q->vtype == TYSHORT) + q = mkconv(tyint, q); + if(doput) + p->chain.datap = putconst(q); + else + p->chain.datap = q; + } + else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->vclass==CLPROC) + p->chain.datap = mkaddr(q->b_prim.namep); + else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->b_name.vdim!=NULL) + p->chain.datap = mkscalar(q->b_prim.namep); + else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->b_name.vdovar && + (t = memversion(q->b_prim.namep)) ) + p->chain.datap = fixtype(t); + else p->chain.datap = fixtype(q); + } +return(nargs); +} + +struct bigblock * +mkscalar(np) +register struct bigblock *np; +{ +register struct bigblock *ap; + +vardcl(np); +ap = mkaddr(np); + +#ifdef __vax__ + /* on the VAX, prolog causes array arguments + to point at the (0,...,0) element, except when + subscript checking is on + */ + if( !checksubs && np->vstg==STGARG) + { + register struct dimblock *dp; + dp = np->vdim; + frexpr(ap->memoffset); + ap->memoffset = mkexpr(OPSTAR, MKICON(typesize[np->vtype]), + cpexpr(dp->baseoffset) ); + } +#endif +return(ap); +} + + + + + +bigptr mkfunct(p) +register struct bigblock * p; +{ +chainp ep; +struct bigblock *ap; +struct extsym *extp; +register struct bigblock *np; +register struct bigblock *q; +int k, nargs; +int class; + +np = p->b_prim.namep; +class = np->vclass; + +if(class == CLUNKNOWN) + { + np->vclass = class = CLPROC; + if(np->vstg == STGUNKNOWN) + { + if((k = intrfunct(np->b_name.varname))) + { + np->vstg = STGINTR; + np->b_name.vardesc.varno = k; + np->b_name.vprocclass = PINTRINSIC; + } + else + { + extp = mkext( varunder(VL,np->b_name.varname) ); + extp->extstg = STGEXT; + np->vstg = STGEXT; + np->b_name.vardesc.varno = extp - extsymtab; + np->b_name.vprocclass = PEXTERNAL; + } + } + else if(np->vstg==STGARG) + { + if(np->vtype!=TYCHAR && !ftn66flag) + warn("Dummy procedure not declared EXTERNAL. Code may be wrong."); + np->b_name.vprocclass = PEXTERNAL; + } + } + +if(class != CLPROC) + fatal1("invalid class code for function", class); +if(p->b_prim.fcharp || p->b_prim.lcharp) + { + err("no substring of function call"); + goto error; + } +impldcl(np); +nargs = fixargs( np->b_name.vprocclass!=PINTRINSIC, p->b_prim.argsp); + +switch(np->b_name.vprocclass) + { + case PEXTERNAL: + ap = mkaddr(np); + call: + q = mkexpr(OPCALL, ap, p->b_prim.argsp); + q->vtype = np->vtype; + if(np->vleng) + q->vleng = cpexpr(np->vleng); + break; + + case PINTRINSIC: + q = intrcall(np, p->b_prim.argsp, nargs); + break; + + case PSTFUNCT: + q = stfcall(np, p->b_prim.argsp); + break; + + case PTHISPROC: + warn("recursive call"); + for(ep = entries ; ep ; ep = ep->entrypoint.nextp) + if(ep->entrypoint.enamep == np) + break; + if(ep == NULL) + fatal("mkfunct: impossible recursion"); + ap = builtin(np->vtype, varstr(XL, ep->entrypoint.entryname->extname) ); + goto call; + + default: + fatal1("mkfunct: impossible vprocclass %d", np->b_name.vprocclass); + q = 0; /* XXX gcc */ + } +ckfree(p); +return(q); + +error: + frexpr(p); + return( errnode() ); +} + + + +LOCAL struct bigblock * +stfcall(struct bigblock *np, struct bigblock *actlist) +{ + register chainp actuals; + int nargs; + chainp oactp, formals; + int type; + struct bigblock *q, *rhs; + bigptr ap; + register chainp rp; + chainp tlist; + + if(actlist) { + actuals = actlist->b_list.listp; + ckfree(actlist); + } else + actuals = NULL; + oactp = actuals; + + nargs = 0; + tlist = NULL; + type = np->vtype; + + formals = (chainp)np->b_name.vardesc.vstfdesc->chain.datap; + rhs = (bigptr)np->b_name.vardesc.vstfdesc->chain.nextp; + + /* copy actual arguments into temporaries */ + while(actuals!=NULL && formals!=NULL) { + rp = ALLOC(rplblock); + rp->rplblock.rplnp = q = formals->chain.datap; + ap = fixtype(actuals->chain.datap); + if(q->vtype==ap->vtype && q->vtype!=TYCHAR + && (ap->tag==TCONST || ap->tag==TADDR) ) { + rp->rplblock.rplvp = ap; + rp->rplblock.rplxp = NULL; + rp->rplblock.rpltag = ap->tag; + } else { + rp->rplblock.rplvp = fmktemp(q->vtype, q->vleng); + rp->rplblock.rplxp = fixtype( mkexpr(OPASSIGN, + cpexpr(rp->rplblock.rplvp), ap) ); + if( (rp->rplblock.rpltag = + rp->rplblock.rplxp->tag) == TERROR) + err("disagreement of argument types in statement function call"); + } + rp->rplblock.nextp = tlist; + tlist = rp; + actuals = actuals->chain.nextp; + formals = formals->chain.nextp; + ++nargs; + } + + if(actuals!=NULL || formals!=NULL) + err("statement function definition and argument list differ"); + + /* + now push down names involved in formal argument list, then + evaluate rhs of statement function definition in this environment + */ + rpllist = hookup(tlist, rpllist); + q = mkconv(type, fixtype(cpexpr(rhs)) ); + + /* now generate the tree ( t1=a1, (t2=a2,... , f))))) */ + while(--nargs >= 0) { + if(rpllist->rplblock.rplxp) + q = mkexpr(OPCOMMA, rpllist->rplblock.rplxp, q); + rp = rpllist->rplblock.nextp; + frexpr(rpllist->rplblock.rplvp); + ckfree(rpllist); + rpllist = rp; + } + + frchain( &oactp ); + return(q); +} + + + + +struct bigblock * +mklhs(struct bigblock *p) +{ + struct bigblock *s; + struct bigblock *np; + chainp rp; + int regn; + + /* first fixup name */ + + if(p->tag != TPRIM) + return(p); + + np = p->b_prim.namep; + + /* is name on the replace list? */ + + for(rp = rpllist ; rp ; rp = rp->rplblock.nextp) { + if(np == rp->rplblock.rplnp) { + if(rp->rplblock.rpltag == TNAME) { + np = p->b_prim.namep = rp->rplblock.rplvp; + break; + } else + return( cpexpr(rp->rplblock.rplvp) ); + } + } + + /* is variable a DO index in a register ? */ + + if(np->b_name.vdovar && ( (regn = inregister(np)) >= 0) ) { + if(np->vtype == TYERROR) + return( errnode() ); + else { + s = BALLO(); + s->tag = TADDR; + s->vstg = STGREG; + s->vtype = TYIREG; + s->b_addr.memno = regn; + s->b_addr.memoffset = MKICON(0); + return(s); + } + } + + vardcl(np); + s = mkaddr(np); + s->b_addr.memoffset = mkexpr(OPPLUS, s->b_addr.memoffset, suboffset(p) ); + frexpr(p->b_prim.argsp); + p->b_prim.argsp = NULL; + + /* now do substring part */ + + if(p->b_prim.fcharp || p->b_prim.lcharp) { + if(np->vtype != TYCHAR) + err1("substring of noncharacter %s", + varstr(VL,np->b_name.varname)); + else { + if(p->b_prim.lcharp == NULL) + p->b_prim.lcharp = cpexpr(s->vleng); + if(p->b_prim.fcharp) + s->vleng = mkexpr(OPMINUS, p->b_prim.lcharp, + mkexpr(OPMINUS, p->b_prim.fcharp, MKICON(1) )); + else { + frexpr(s->vleng); + s->vleng = p->b_prim.lcharp; + } + } + } + + s->vleng = fixtype( s->vleng ); + s->b_addr.memoffset = fixtype( s->b_addr.memoffset ); + ckfree(p); + return(s); +} + + + + +void +deregister(np) +struct bigblock *np; +{ +} + + + + +struct bigblock *memversion(np) +register struct bigblock *np; +{ +register struct bigblock *s; + +if(np->b_name.vdovar==NO || (inregister(np)<0) ) + return(NULL); +np->b_name.vdovar = NO; +s = mklhs( mkprim(np, 0,0,0) ); +np->b_name.vdovar = YES; +return(s); +} + + +int +inregister(np) +register struct bigblock *np; +{ +return(-1); +} + + + +int +enregister(np) +struct bigblock *np; +{ + return(NO); +} + + + + +bigptr suboffset(p) +register struct bigblock *p; +{ +int n; +bigptr size; +chainp cp; +bigptr offp, prod; +struct dimblock *dimp; +bigptr sub[8]; +register struct bigblock *np; + +np = p->b_prim.namep; +offp = MKICON(0); +n = 0; +if(p->b_prim.argsp) + for(cp = p->b_prim.argsp->b_list.listp ; cp ; cp = cp->chain.nextp) + { + sub[n++] = fixtype(cpexpr(cp->chain.datap)); + if(n > 7) + { + err("more than 7 subscripts"); + break; + } + } + +dimp = np->b_name.vdim; +if(n>0 && dimp==NULL) + err("subscripts on scalar variable"); +else if(dimp && dimp->ndim!=n) + err1("wrong number of subscripts on %s", + varstr(VL, np->b_name.varname) ); +else if(n > 0) + { + prod = sub[--n]; + while( --n >= 0) + prod = mkexpr(OPPLUS, sub[n], + mkexpr(OPSTAR, prod, cpexpr(dimp->dims[n].dimsize)) ); +#ifdef __vax__ + if(checksubs || np->vstg!=STGARG) + prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset)); +#else + prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset)); +#endif + if(checksubs) + prod = subcheck(np, prod); + if(np->vtype == TYCHAR) + size = cpexpr(np->vleng); + else size = MKICON( typesize[np->vtype] ); + prod = mkexpr(OPSTAR, prod, size); + offp = mkexpr(OPPLUS, offp, prod); + } + +if(p->b_prim.fcharp && np->vtype==TYCHAR) + offp = mkexpr(OPPLUS, offp, mkexpr(OPMINUS, cpexpr(p->b_prim.fcharp), MKICON(1) )); + +return(offp); +} + + +/* + * Check if an array is addressed out of bounds. + */ +bigptr +subcheck(struct bigblock *np, bigptr p) +{ + struct dimblock *dimp; + bigptr t, badcall; + int l1, l2; + + dimp = np->b_name.vdim; + if(dimp->nelt == NULL) + return(p); /* don't check arrays with * bounds */ + if( ISICON(p) ) { + if(p->b_const.fconst.ci < 0) + goto badsub; + if( ISICON(dimp->nelt) ) { + if(p->b_const.fconst.ci < dimp->nelt->b_const.fconst.ci) + return(p); + else + goto badsub; + } + } + + if (p->tag==TADDR && p->vstg==STGREG) { + t = p; + } else { + t = fmktemp(p->vtype, NULL); + putexpr(mkexpr(OPASSIGN, cpexpr(t), p)); + } + /* t now cotains evaluated expression */ + + l1 = newlabel(); + l2 = newlabel(); + putif(mkexpr(OPLT, cpexpr(t), cpexpr(dimp->nelt)), l1); + putif(mkexpr(OPGE, cpexpr(t), MKICON(0)), l1); + putgoto(l2); + putlabel(l1); + + badcall = call4(t->vtype, "s_rnge", mkstrcon(VL, np->b_name.varname), + mkconv(TYLONG, cpexpr(t)), + mkstrcon(XL, procname), MKICON(lineno)); + badcall->b_expr.opcode = OPCCALL; + + putexpr(badcall); + putlabel(l2); + return t; + +badsub: + frexpr(p); + err1("subscript on variable %s out of range", + varstr(VL,np->b_name.varname)); + return ( MKICON(0) ); +} + + + + +struct bigblock *mkaddr(p) +register struct bigblock *p; +{ +struct extsym *extp; +register struct bigblock *t; + +switch( p->vstg) + { + case STGUNKNOWN: + if(p->vclass != CLPROC) + break; + extp = mkext( varunder(VL, p->b_name.varname) ); + extp->extstg = STGEXT; + p->vstg = STGEXT; + p->b_name.vardesc.varno = extp - extsymtab; + p->b_name.vprocclass = PEXTERNAL; + + case STGCOMMON: + case STGEXT: + case STGBSS: + case STGINIT: + case STGEQUIV: + case STGARG: + case STGLENG: + case STGAUTO: + t = BALLO(); + t->tag = TADDR; + t->vclass = p->vclass; + t->vtype = p->vtype; + t->vstg = p->vstg; + t->b_addr.memno = p->b_name.vardesc.varno; + t->b_addr.memoffset = MKICON(p->b_name.voffset); + if(p->vleng) + t->vleng = cpexpr(p->vleng); + return(t); + + case STGINTR: + return( intraddr(p) ); + + } +/*debug*/ fprintf(diagfile, "mkaddr. vtype=%d, vclass=%d\n", p->vtype, p->vclass); +fatal1("mkaddr: impossible storage tag %d", p->vstg); +/* NOTREACHED */ +return 0; /* XXX gcc */ +} + + + +struct bigblock * +mkarg(type, argno) +int type, argno; +{ +register struct bigblock *p; + +p = BALLO(); +p->tag = TADDR; +p->vtype = type; +p->vclass = CLVAR; +p->vstg = (type==TYLENG ? STGLENG : STGARG); +p->b_addr.memno = argno; +return(p); +} + + + + +bigptr mkprim(v, args, lstr, rstr) +register bigptr v; +struct bigblock *args; +bigptr lstr, rstr; +{ +register struct bigblock *p; + +if(v->vclass == CLPARAM) + { + if(args || lstr || rstr) + { + err1("no qualifiers on parameter name", varstr(VL,v->b_name.varname)); + frexpr(args); + frexpr(lstr); + frexpr(rstr); + frexpr(v); + return( errnode() ); + } + return( cpexpr(v->b_param.paramval) ); + } + +p = BALLO(); +p->tag = TPRIM; +p->vtype = v->vtype; +p->b_prim.namep = v; +p->b_prim.argsp = args; +p->b_prim.fcharp = lstr; +p->b_prim.lcharp = rstr; +return(p); +} + + +void +vardcl(v) +register struct bigblock *v; +{ +int nelt; +struct dimblock *t; +struct bigblock *p; +bigptr neltp; + +if(v->b_name.vdcldone) return; + +if(v->vtype == TYUNKNOWN) + impldcl(v); +if(v->vclass == CLUNKNOWN) + v->vclass = CLVAR; +else if(v->vclass!=CLVAR && v->b_name.vprocclass!=PTHISPROC) + { + dclerr("used as variable", v); + return; + } +if(v->vstg==STGUNKNOWN) + v->vstg = implstg[ letter(v->b_name.varname[0]) ]; + +switch(v->vstg) + { + case STGBSS: + v->b_name.vardesc.varno = ++lastvarno; + break; + case STGAUTO: + if(v->vclass==CLPROC && v->b_name.vprocclass==PTHISPROC) + break; + nelt = 1; + if((t = v->b_name.vdim)) { + if( (neltp = t->nelt) && ISCONST(neltp) ) + nelt = neltp->b_const.fconst.ci; + else + dclerr("adjustable automatic array", v); + } + p = autovar(nelt, v->vtype, v->vleng); + v->b_name.voffset = p->b_addr.memoffset->b_const.fconst.ci; + frexpr(p); + break; + + default: + break; + } +v->b_name.vdcldone = YES; +} + + + +void +impldcl(p) +register struct bigblock *p; +{ +register int k; +int type, leng; + +if(p->b_name.vdcldone || (p->vclass==CLPROC && p->b_name.vprocclass==PINTRINSIC) ) + return; +if(p->vtype == TYUNKNOWN) + { + k = letter(p->b_name.varname[0]); + type = impltype[ k ]; + leng = implleng[ k ]; + if(type == TYUNKNOWN) + { + if(p->vclass == CLPROC) + return; + dclerr("attempt to use undefined variable", p); + type = TYERROR; + leng = 1; + } + settype(p, type, leng); + } +} + + + + +LOCAL int +letter(c) +register int c; +{ +if( isupper(c) ) + c = tolower(c); +return(c - 'a'); +} + +#define ICONEQ(z, c) (ISICON(z) && z->b_const.fconst.ci==c) +#define COMMUTE { e = lp; lp = rp; rp = e; } + + +struct bigblock * +mkexpr(opcode, lp, rp) +int opcode; +register bigptr lp, rp; +{ +register struct bigblock *e, *e1; +int etype; +int ltype, rtype; +int ltag, rtag; + +ltype = lp->vtype; +ltag = lp->tag; +if(rp && opcode!=OPCALL && opcode!=OPCCALL) + { + rtype = rp->vtype; + rtag = rp->tag; + } +else rtype = rtag = 0; + +etype = cktype(opcode, ltype, rtype); +if(etype == TYERROR) + goto error; + +switch(opcode) + { + /* check for multiplication by 0 and 1 and addition to 0 */ + + case OPSTAR: + if( ISCONST(lp) ) + COMMUTE + + if( ISICON(rp) ) + { + if(rp->b_const.fconst.ci == 0) + goto retright; + goto mulop; + } + break; + + case OPSLASH: + case OPMOD: + if( ICONEQ(rp, 0) ) + { + err("attempted division by zero"); + rp = MKICON(1); + break; + } + if(opcode == OPMOD) + break; + + + mulop: + if( ISICON(rp) ) + { + if(rp->b_const.fconst.ci == 1) + goto retleft; + + if(rp->b_const.fconst.ci == -1) + { + frexpr(rp); + return( mkexpr(OPNEG, lp, 0) ); + } + } + + if( ISSTAROP(lp) && ISICON(lp->b_expr.rightp) ) + { + if(opcode == OPSTAR) + e = mkexpr(OPSTAR, lp->b_expr.rightp, rp); + else if(ISICON(rp) && lp->b_expr.rightp->b_const.fconst.ci % rp->b_const.fconst.ci == 0) + e = mkexpr(OPSLASH, lp->b_expr.rightp, rp); + else break; + + e1 = lp->b_expr.leftp; + ckfree(lp); + return( mkexpr(OPSTAR, e1, e) ); + } + break; + + + case OPPLUS: + if( ISCONST(lp) ) + COMMUTE + goto addop; + + case OPMINUS: + if( ICONEQ(lp, 0) ) + { + frexpr(lp); + return( mkexpr(OPNEG, rp, 0) ); + } + + if( ISCONST(rp) ) + { + opcode = OPPLUS; + consnegop(rp); + } + + addop: + if( ISICON(rp) ) + { + if(rp->b_const.fconst.ci == 0) + goto retleft; + if( ISPLUSOP(lp) && ISICON(lp->b_expr.rightp) ) + { + e = mkexpr(OPPLUS, lp->b_expr.rightp, rp); + e1 = lp->b_expr.leftp; + ckfree(lp); + return( mkexpr(OPPLUS, e1, e) ); + } + } + break; + + + case OPPOWER: + break; + + case OPNEG: + if(ltag==TEXPR && lp->b_expr.opcode==OPNEG) + { + e = lp->b_expr.leftp; + ckfree(lp); + return(e); + } + break; + + case OPNOT: + if(ltag==TEXPR && lp->b_expr.opcode==OPNOT) + { + e = lp->b_expr.leftp; + ckfree(lp); + return(e); + } + break; + + case OPCALL: + case OPCCALL: + etype = ltype; + if(rp!=NULL && rp->b_list.listp==NULL) + { + ckfree(rp); + rp = NULL; + } + break; + + case OPAND: + case OPOR: + if( ISCONST(lp) ) + COMMUTE + + if( ISCONST(rp) ) + { + if(rp->b_const.fconst.ci == 0) + if(opcode == OPOR) + goto retleft; + else + goto retright; + else if(opcode == OPOR) + goto retright; + else + goto retleft; + } + case OPEQV: + case OPNEQV: + + case OPBITAND: + case OPBITOR: + case OPBITXOR: + case OPBITNOT: + case OPLSHIFT: + case OPRSHIFT: + + case OPLT: + case OPGT: + case OPLE: + case OPGE: + case OPEQ: + case OPNE: + + case OPCONCAT: + break; + case OPMIN: + case OPMAX: + + case OPASSIGN: + + case OPCONV: + case OPADDR: + + case OPCOMMA: + break; + + default: + fatal1("mkexpr: impossible opcode %d", opcode); + } + +e = BALLO(); +e->tag = TEXPR; +e->b_expr.opcode = opcode; +e->vtype = etype; +e->b_expr.leftp = lp; +e->b_expr.rightp = rp; +if(ltag==TCONST && (rp==0 || rtag==TCONST) ) + e = fold(e); +return(e); + +retleft: + frexpr(rp); + return(lp); + +retright: + frexpr(lp); + return(rp); + +error: + frexpr(lp); + if(rp && opcode!=OPCALL && opcode!=OPCCALL) + frexpr(rp); + return( errnode() ); +} + +#define ERR(s) { errs = s; goto error; } + +int +cktype(op, lt, rt) +register int op, lt, rt; +{ +char *errs = NULL; /* XXX gcc */ + +if(lt==TYERROR || rt==TYERROR) + goto error1; + +if(lt==TYUNKNOWN) + return(TYUNKNOWN); +if(rt==TYUNKNOWN) + if(op!=OPNOT && op!=OPBITNOT && op!=OPNEG && op!=OPCALL && op!=OPCCALL && op!=OPADDR) + return(TYUNKNOWN); + +switch(op) + { + case OPPLUS: + case OPMINUS: + case OPSTAR: + case OPSLASH: + case OPPOWER: + case OPMOD: + if( ISNUMERIC(lt) && ISNUMERIC(rt) ) + return( maxtype(lt, rt) ); + ERR("nonarithmetic operand of arithmetic operator") + + case OPNEG: + if( ISNUMERIC(lt) ) + return(lt); + ERR("nonarithmetic operand of negation") + + case OPNOT: + if(lt == TYLOGICAL) + return(TYLOGICAL); + ERR("NOT of nonlogical") + + case OPAND: + case OPOR: + case OPEQV: + case OPNEQV: + if(lt==TYLOGICAL && rt==TYLOGICAL) + return(TYLOGICAL); + ERR("nonlogical operand of logical operator") + + case OPLT: + case OPGT: + case OPLE: + case OPGE: + case OPEQ: + case OPNE: + if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL) + { + if(lt != rt) + ERR("illegal comparison") + } + + else if( ISCOMPLEX(lt) || ISCOMPLEX(rt) ) + { + if(op!=OPEQ && op!=OPNE) + ERR("order comparison of complex data") + } + + else if( ! ISNUMERIC(lt) || ! ISNUMERIC(rt) ) + ERR("comparison of nonarithmetic data") + return(TYLOGICAL); + + case OPCONCAT: + if(lt==TYCHAR && rt==TYCHAR) + return(TYCHAR); + ERR("concatenation of nonchar data") + + case OPCALL: + case OPCCALL: + return(lt); + + case OPADDR: + return(TYADDR); + + case OPCONV: + if(rt == 0) + return(0); + case OPASSIGN: + if( ISINT(lt) && rt==TYCHAR) + return(lt); + if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL) + if(op!=OPASSIGN || lt!=rt) + { +/* debug fprintf(diagfile, " lt=%d, rt=%d, op=%d\n", lt, rt, op); */ +/* debug fatal("impossible conversion. possible compiler bug"); */ + ERR("impossible conversion") + } + return(lt); + + case OPMIN: + case OPMAX: + case OPBITOR: + case OPBITAND: + case OPBITXOR: + case OPBITNOT: + case OPLSHIFT: + case OPRSHIFT: + return(lt); + + case OPCOMMA: + return(rt); + + default: + fatal1("cktype: impossible opcode %d", op); + } +error: err(errs); +error1: return(TYERROR); +} + +LOCAL bigptr fold(e) +register struct bigblock *e; +{ +struct bigblock *p; +register bigptr lp, rp; +int etype, mtype, ltype, rtype, opcode; +int i, ll, lr; +char *q, *s; +union constant lcon, rcon; + +opcode = e->b_expr.opcode; +etype = e->vtype; + +lp = e->b_expr.leftp; +ltype = lp->vtype; +rp = e->b_expr.rightp; + +if(rp == 0) + switch(opcode) + { + case OPNOT: + lp->b_const.fconst.ci = ! lp->b_const.fconst.ci; + return(lp); + + case OPBITNOT: + lp->b_const.fconst.ci = ~ lp->b_const.fconst.ci; + return(lp); + + case OPNEG: + consnegop(lp); + return(lp); + + case OPCONV: + case OPADDR: + return(e); + + default: + fatal1("fold: invalid unary operator %d", opcode); + } + +rtype = rp->vtype; + +p = BALLO(); +p->tag = TCONST; +p->vtype = etype; +p->vleng = e->vleng; + +switch(opcode) + { + case OPCOMMA: + return(e); + + case OPAND: + p->b_const.fconst.ci = lp->b_const.fconst.ci && rp->b_const.fconst.ci; + break; + + case OPOR: + p->b_const.fconst.ci = lp->b_const.fconst.ci || rp->b_const.fconst.ci; + break; + + case OPEQV: + p->b_const.fconst.ci = lp->b_const.fconst.ci == rp->b_const.fconst.ci; + break; + + case OPNEQV: + p->b_const.fconst.ci = lp->b_const.fconst.ci != rp->b_const.fconst.ci; + break; + + case OPBITAND: + p->b_const.fconst.ci = lp->b_const.fconst.ci & rp->b_const.fconst.ci; + break; + + case OPBITOR: + p->b_const.fconst.ci = lp->b_const.fconst.ci | rp->b_const.fconst.ci; + break; + + case OPBITXOR: + p->b_const.fconst.ci = lp->b_const.fconst.ci ^ rp->b_const.fconst.ci; + break; + + case OPLSHIFT: + p->b_const.fconst.ci = lp->b_const.fconst.ci << rp->b_const.fconst.ci; + break; + + case OPRSHIFT: + p->b_const.fconst.ci = lp->b_const.fconst.ci >> rp->b_const.fconst.ci; + break; + + case OPCONCAT: + ll = lp->vleng->b_const.fconst.ci; + lr = rp->vleng->b_const.fconst.ci; + p->b_const.fconst.ccp = q = (char *) ckalloc(ll+lr); + p->vleng = MKICON(ll+lr); + s = lp->b_const.fconst.ccp; + for(i = 0 ; i < ll ; ++i) + *q++ = *s++; + s = rp->b_const.fconst.ccp; + for(i = 0; i < lr; ++i) + *q++ = *s++; + break; + + + case OPPOWER: + if( ! ISINT(rtype) ) + return(e); + conspower(&(p->b_const.fconst), lp, rp->b_const.fconst.ci); + break; + + + default: + if(ltype == TYCHAR) + { + lcon.ci = cmpstr(lp->b_const.fconst.ccp, rp->b_const.fconst.ccp, + lp->vleng->b_const.fconst.ci, rp->vleng->b_const.fconst.ci); + rcon.ci = 0; + mtype = tyint; + } + else { + mtype = maxtype(ltype, rtype); + consconv(mtype, &lcon, ltype, &(lp->b_const.fconst) ); + consconv(mtype, &rcon, rtype, &(rp->b_const.fconst) ); + } + consbinop(opcode, mtype, &(p->b_const.fconst), &lcon, &rcon); + break; + } + +frexpr(e); +return(p); +} + + + +/* assign constant l = r , doing coercion */ +void +consconv(lt, lv, rt, rv) +int lt, rt; +register union constant *lv, *rv; +{ +switch(lt) + { + case TYSHORT: + case TYLONG: + if( ISINT(rt) ) + lv->ci = rv->ci; + else lv->ci = rv->cd[0]; + break; + + case TYCOMPLEX: + case TYDCOMPLEX: + switch(rt) + { + case TYSHORT: + case TYLONG: + /* fall through and do real assignment of + first element + */ + case TYREAL: + case TYDREAL: + lv->cd[1] = 0; break; + case TYCOMPLEX: + case TYDCOMPLEX: + lv->cd[1] = rv->cd[1]; break; + } + + case TYREAL: + case TYDREAL: + if( ISINT(rt) ) + lv->cd[0] = rv->ci; + else lv->cd[0] = rv->cd[0]; + break; + + case TYLOGICAL: + lv->ci = rv->ci; + break; + } +} + + +void +consnegop(p) +register struct bigblock *p; +{ +switch(p->vtype) + { + case TYSHORT: + case TYLONG: + p->b_const.fconst.ci = - p->b_const.fconst.ci; + break; + + case TYCOMPLEX: + case TYDCOMPLEX: + p->b_const.fconst.cd[1] = - p->b_const.fconst.cd[1]; + /* fall through and do the real parts */ + case TYREAL: + case TYDREAL: + p->b_const.fconst.cd[0] = - p->b_const.fconst.cd[0]; + break; + default: + fatal1("consnegop: impossible type %d", p->vtype); + } +} + + + +LOCAL void +conspower(powp, ap, n) +register union constant *powp; +struct bigblock *ap; +ftnint n; +{ +register int type; +union constant x; + +switch(type = ap->vtype) /* pow = 1 */ + { + case TYSHORT: + case TYLONG: + powp->ci = 1; + break; + case TYCOMPLEX: + case TYDCOMPLEX: + powp->cd[1] = 0; + case TYREAL: + case TYDREAL: + powp->cd[0] = 1; + break; + default: + fatal1("conspower: invalid type %d", type); + } + +if(n == 0) + return; +if(n < 0) + { + if( ISINT(type) ) + { + err("integer ** negative power "); + return; + } + n = - n; + consbinop(OPSLASH, type, &x, powp, &(ap->b_const.fconst)); + } +else + consbinop(OPSTAR, type, &x, powp, &(ap->b_const.fconst)); + +for( ; ; ) + { + if(n & 01) + consbinop(OPSTAR, type, powp, powp, &x); + if(n >>= 1) + consbinop(OPSTAR, type, &x, &x, &x); + else + break; + } +} + + + +/* do constant operation cp = a op b */ + + +LOCAL void +consbinop(opcode, type, cp, ap, bp) +int opcode, type; +register union constant *ap, *bp, *cp; +{ +int k; +double temp; + +switch(opcode) + { + case OPPLUS: + switch(type) + { + case TYSHORT: + case TYLONG: + cp->ci = ap->ci + bp->ci; + break; + case TYCOMPLEX: + case TYDCOMPLEX: + cp->cd[1] = ap->cd[1] + bp->cd[1]; + case TYREAL: + case TYDREAL: + cp->cd[0] = ap->cd[0] + bp->cd[0]; + break; + } + break; + + case OPMINUS: + switch(type) + { + case TYSHORT: + case TYLONG: + cp->ci = ap->ci - bp->ci; + break; + case TYCOMPLEX: + case TYDCOMPLEX: + cp->cd[1] = ap->cd[1] - bp->cd[1]; + case TYREAL: + case TYDREAL: + cp->cd[0] = ap->cd[0] - bp->cd[0]; + break; + } + break; + + case OPSTAR: + switch(type) + { + case TYSHORT: + case TYLONG: + cp->ci = ap->ci * bp->ci; + break; + case TYREAL: + case TYDREAL: + cp->cd[0] = ap->cd[0] * bp->cd[0]; + break; + case TYCOMPLEX: + case TYDCOMPLEX: + temp = ap->cd[0] * bp->cd[0] - + ap->cd[1] * bp->cd[1] ; + cp->cd[1] = ap->cd[0] * bp->cd[1] + + ap->cd[1] * bp->cd[0] ; + cp->cd[0] = temp; + break; + } + break; + case OPSLASH: + switch(type) + { + case TYSHORT: + case TYLONG: + cp->ci = ap->ci / bp->ci; + break; + case TYREAL: + case TYDREAL: + cp->cd[0] = ap->cd[0] / bp->cd[0]; + break; + case TYCOMPLEX: + case TYDCOMPLEX: + zdiv(&cp->dc, &ap->dc, &bp->dc); + break; + } + break; + + case OPMOD: + if( ISINT(type) ) + { + cp->ci = ap->ci % bp->ci; + break; + } + else + fatal("inline mod of noninteger"); + + default: /* relational ops */ + switch(type) + { + case TYSHORT: + case TYLONG: + if(ap->ci < bp->ci) + k = -1; + else if(ap->ci == bp->ci) + k = 0; + else k = 1; + break; + case TYREAL: + case TYDREAL: + if(ap->cd[0] < bp->cd[0]) + k = -1; + else if(ap->cd[0] == bp->cd[0]) + k = 0; + else k = 1; + break; + case TYCOMPLEX: + case TYDCOMPLEX: + if(ap->cd[0] == bp->cd[0] && + ap->cd[1] == bp->cd[1] ) + k = 0; + else k = 1; + break; + default: /* XXX gcc */ + k = 0; + break; + } + + switch(opcode) + { + case OPEQ: + cp->ci = (k == 0); + break; + case OPNE: + cp->ci = (k != 0); + break; + case OPGT: + cp->ci = (k == 1); + break; + case OPLT: + cp->ci = (k == -1); + break; + case OPGE: + cp->ci = (k >= 0); + break; + case OPLE: + cp->ci = (k <= 0); + break; + } + break; + } +} + + + +int +conssgn(p) +register bigptr p; +{ +if( ! ISCONST(p) ) + fatal( "sgn(nonconstant)" ); + +switch(p->vtype) + { + case TYSHORT: + case TYLONG: + if(p->b_const.fconst.ci > 0) return(1); + if(p->b_const.fconst.ci < 0) return(-1); + return(0); + + case TYREAL: + case TYDREAL: + if(p->b_const.fconst.cd[0] > 0) return(1); + if(p->b_const.fconst.cd[0] < 0) return(-1); + return(0); + + case TYCOMPLEX: + case TYDCOMPLEX: + return(p->b_const.fconst.cd[0]!=0 || p->b_const.fconst.cd[1]!=0); + + default: + fatal1( "conssgn(type %d)", p->vtype); + } +/* NOTREACHED */ +return 0; /* XXX gcc */ +} + +char *powint[ ] = { "pow_ii", "pow_ri", "pow_di", "pow_ci", "pow_zi" }; + + +LOCAL bigptr mkpower(p) +register struct bigblock *p; +{ +register bigptr q, lp, rp; +int ltype, rtype, mtype; + +lp = p->b_expr.leftp; +rp = p->b_expr.rightp; +ltype = lp->vtype; +rtype = rp->vtype; + +if(ISICON(rp)) + { + if(rp->b_const.fconst.ci == 0) + { + frexpr(p); + if( ISINT(ltype) ) + return( MKICON(1) ); + else + return( putconst( mkconv(ltype, MKICON(1))) ); + } + if(rp->b_const.fconst.ci < 0) + { + if( ISINT(ltype) ) + { + frexpr(p); + err("integer**negative"); + return( errnode() ); + } + rp->b_const.fconst.ci = - rp->b_const.fconst.ci; + p->b_expr.leftp = lp = fixexpr(mkexpr(OPSLASH, MKICON(1), lp)); + } + if(rp->b_const.fconst.ci == 1) + { + frexpr(rp); + ckfree(p); + return(lp); + } + + if( ONEOF(ltype, MSKINT|MSKREAL) ) + { + p->vtype = ltype; + return(p); + } + } +if( ISINT(rtype) ) + { + if(ltype==TYSHORT && rtype==TYSHORT) + q = call2(TYSHORT, "pow_hh", lp, rp); + else { + if(ltype == TYSHORT) + { + ltype = TYLONG; + lp = mkconv(TYLONG,lp); + } + q = call2(ltype, powint[ltype-TYLONG], lp, mkconv(TYLONG, rp)); + } + } +else if( ISREAL( (mtype = maxtype(ltype,rtype)) )) + q = call2(mtype, "pow_dd", + mkconv(TYDREAL,lp), mkconv(TYDREAL,rp)); +else { + q = call2(TYDCOMPLEX, "pow_zz", + mkconv(TYDCOMPLEX,lp), mkconv(TYDCOMPLEX,rp)); + if(mtype == TYCOMPLEX) + q = mkconv(TYCOMPLEX, q); + } +ckfree(p); +return(q); +} + + + +/* Complex Division. Same code as in Runtime Library +*/ + + + +LOCAL void +zdiv(c, a, b) +register struct dcomplex *a, *b, *c; +{ +double ratio, den; +double abr, abi; + +if( (abr = b->dreal) < 0.) + abr = - abr; +if( (abi = b->dimag) < 0.) + abi = - abi; +if( abr <= abi ) + { + if(abi == 0) + fatal("complex division by zero"); + ratio = b->dreal / b->dimag ; + den = b->dimag * (1 + ratio*ratio); + c->dreal = (a->dreal*ratio + a->dimag) / den; + c->dimag = (a->dimag*ratio - a->dreal) / den; + } + +else + { + ratio = b->dimag / b->dreal ; + den = b->dreal * (1 + ratio*ratio); + c->dreal = (a->dreal + a->dimag*ratio) / den; + c->dimag = (a->dimag - a->dreal*ratio) / den; + } + +} diff --git a/lang/pcc/pcc/f77/fcom/ftypes.h b/lang/pcc/pcc/f77/fcom/ftypes.h new file mode 100644 index 000000000..81468abc8 --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/ftypes.h @@ -0,0 +1,82 @@ +/* $Id: ftypes.h,v 1.5 2008/12/19 08:08:48 ragge Exp $ */ +/* + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code and documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditionsand the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND 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 CALDERA INTERNATIONAL, INC. 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 OFLIABILITY, 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. + */ +/* variable types + * numeric assumptions: + * int < reals < complexes + * TYDREAL-TYREAL = TYDCOMPLEX-TYCOMPLEX + */ + +#ifndef _FTYPES_H_ +#define _FTYPES_H_ + + +#define TYUNKNOWN 0 +#define TYADDR 1 +#define TYSHORT 2 +#define TYLONG 3 +#define TYREAL 4 +#define TYDREAL 5 +#define TYCOMPLEX 6 +#define TYDCOMPLEX 7 +#define TYLOGICAL 8 +#define TYCHAR 9 +#define TYSUBR 10 +#define TYERROR 11 + +#define NTYPES (TYERROR+1) + +/* + * Type conversion from pcc to f77 internal format. + */ +#define FSZADDR (SZPOINT(0)/SZCHAR) /* XXX - typecheck? */ +#define FSZSHORT (SZSHORT/SZCHAR) +#define FSZINT (SZINT/SZCHAR) +#define FSZLONG (SZLONG/SZCHAR) +#define ALIADDR (ALPOINT/ALCHAR) +#define ALISHORT (ALSHORT/ALCHAR) +#define ALILONG (ALLONG/ALCHAR) +#define ALIDOUBLE (ALDOUBLE/ALCHAR) + +#ifndef SZINT +#include "macdefs.h" +#endif +#if SZINT == SZSHORT +#define TYINT TYSHORT +#else /* SZLONG >= SZINT */ +#define TYINT TYLONG +#endif + +#define TYLENG TYLONG +#endif /* !_FTYPES_H_ */ diff --git a/lang/pcc/pcc/f77/fcom/gram.dcl b/lang/pcc/pcc/f77/fcom/gram.dcl new file mode 100644 index 000000000..493f7a968 --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/gram.dcl @@ -0,0 +1,318 @@ +spec: dcl + | common + | external + | intrinsic + | equivalence + | data + | implicit + | SSAVE + { saveall = YES; } + | SSAVE savelist + | SFORMAT + { fmtstmt(thislabel); setfmt(thislabel); } + | SPARAM in_dcl SLPAR paramlist SRPAR + ; + +dcl: type name in_dcl dims lengspec + { settype($2, $1, $5); + if(ndim>0) setbound($2,ndim,dims); + } + | dcl SCOMMA name dims lengspec + { settype($3, $1, $5); + if(ndim>0) setbound($3,ndim,dims); + } + ; + +type: typespec lengspec + { varleng = $2; } + ; + +typespec: typename + { varleng = ($1<0 || $1==TYLONG ? 0 : typesize[$1]); } + ; + +typename: SINTEGER { $$ = TYLONG; } + | SREAL { $$ = TYREAL; } + | SCOMPLEX { $$ = TYCOMPLEX; } + | SDOUBLE { $$ = TYDREAL; } + | SDCOMPLEX { $$ = TYDCOMPLEX; } + | SLOGICAL { $$ = TYLOGICAL; } + | SCHARACTER { $$ = TYCHAR; } + | SUNDEFINED { $$ = TYUNKNOWN; } + | SDIMENSION { $$ = TYUNKNOWN; } + | SAUTOMATIC { $$ = - STGAUTO; } + | SSTATIC { $$ = - STGBSS; } + ; + +lengspec: + { $$ = varleng; } + | SSTAR expr + { + if( ! ISICON($2) ) + { + $$ = 0; + dclerr("length must be an integer constant", 0); + } + else $$ = $2->b_const.fconst.ci; + } + | SSTAR SLPAR SSTAR SRPAR + { $$ = 0; } + ; + +common: SCOMMON in_dcl var + { incomm( $$ = comblock(0, 0) , $3 ); } + | SCOMMON in_dcl comblock var + { $$ = $3; incomm($3, $4); } + | common opt_comma comblock opt_comma var + { $$ = $3; incomm($3, $5); } + | common SCOMMA var + { incomm($1, $3); } + ; + +comblock: SCONCAT + { $$ = comblock(0, 0); } + | SSLASH SFNAME SSLASH + { $$ = comblock(toklen, token); } + ; + +external: SEXTERNAL in_dcl name + { setext($3); } + | external SCOMMA name + { setext($3); } + ; + +intrinsic: SINTRINSIC in_dcl name + { setintr($3); } + | intrinsic SCOMMA name + { setintr($3); } + ; + +equivalence: SEQUIV in_dcl equivset + | equivalence SCOMMA equivset + ; + +equivset: SLPAR equivlist SRPAR + { + struct equivblock *p; + if(nequiv >= MAXEQUIV) + fatal("too many equivalences"); + p = & eqvclass[nequiv++]; + p->eqvinit = 0; + p->eqvbottom = 0; + p->eqvtop = 0; + p->equivs = $2; + } + ; + +equivlist: lhs + { $$ = ALLOC(eqvchain); $$->eqvchain.eqvitem = $1; } + | equivlist SCOMMA lhs + { $$ = ALLOC(eqvchain); $$->eqvchain.eqvitem = $3; $$->eqvchain.nextp = $1; } + ; + +data: SDATA in_data datalist + | data opt_comma datalist + ; + +in_data: + { if(parstate == OUTSIDE) + { + newproc(); + startproc(0, CLMAIN); + } + if(parstate < INDATA) + { + enddcl(); + parstate = INDATA; + } + } + ; + +datalist: datavarlist SSLASH vallist SSLASH + { ftnint junk; + if(nextdata(&junk,&junk) != NULL) + { + err("too few initializers"); + curdtp = NULL; + } + frdata($1); + frrpl(); + } + ; + +vallist: { toomanyinit = NO; } val + | vallist SCOMMA val + ; + +val: value + { dataval(NULL, $1); } + | simple SSTAR value + { dataval($1, $3); } + ; + +value: simple + | addop simple + { if( $1==OPMINUS && ISCONST($2) ) + consnegop($2); + $$ = $2; + } + | complex_const + | bit_const + ; + +savelist: saveitem + | savelist SCOMMA saveitem + ; + +saveitem: name + { int k; + $1->b_name.vsave = 1; + k = $1->vstg; + if( ! ONEOF(k, M(STGUNKNOWN)|M(STGBSS)|M(STGINIT)) ) + dclerr("can only save static variables", $1); + } + | comblock + { $1->extsave = 1; } + ; + +paramlist: paramitem + | paramlist SCOMMA paramitem + ; + +paramitem: name SEQUALS expr + { if($1->vclass == CLUNKNOWN) + { $1->vclass = CLPARAM; + $1->b_param.paramval = $3; + } + else dclerr("cannot make %s parameter", $1); + } + ; + +var: name dims + { if(ndim>0) setbound($1, ndim, dims); } + ; + +datavar: lhs + { struct bigblock *np; + vardcl(np = $1->b_prim.namep); + if(np->vstg == STGBSS) + np->vstg = STGINIT; + else if(np->vstg == STGCOMMON) + extsymtab[np->b_name.vardesc.varno].extinit = YES; + else if(np->vstg==STGEQUIV) + eqvclass[np->b_name.vardesc.varno].eqvinit = YES; + else if(np->vstg != STGINIT) + dclerr("inconsistent storage classes", np); + $$ = mkchain($1, 0); + } + | SLPAR datavarlist SCOMMA dospec SRPAR + { chainp p; struct bigblock *q; + q = BALLO(); + q->tag = TIMPLDO; + q->b_impldo.varnp = $4->chain.datap; + p = $4->chain.nextp; + if(p) { q->b_impldo.implb = p->chain.datap; p = p->chain.nextp; } + if(p) { q->b_impldo.impub = p->chain.datap; p = p->chain.nextp; } + if(p) { q->b_impldo.impstep = p->chain.datap; p = p->chain.nextp; } + frchain( & ($4) ); + $$ = mkchain(q, 0); + q->b_impldo.datalist = hookup($2, $$); + } + ; + +datavarlist: datavar + { curdtp = $1; curdtelt = 0; } + | datavarlist SCOMMA datavar + { $$ = hookup($1, $3); } + ; + +dims: + { ndim = 0; } + | SLPAR dimlist SRPAR + ; + +dimlist: { ndim = 0; } dim + | dimlist SCOMMA dim + ; + +dim: ubound + { dims[ndim].lb = 0; + dims[ndim].ub = $1; + ++ndim; + } + | expr SCOLON ubound + { dims[ndim].lb = $1; + dims[ndim].ub = $3; + ++ndim; + } + ; + +ubound: SSTAR + { $$ = 0; } + | expr + ; + +labellist: label + { nstars = 1; labarray[0] = $1; } + | labellist SCOMMA label + { labarray[nstars++] = $3; } + ; + +label: labelval + { if($1->labinacc) + warn1("illegal branch to inner block, statement %s", + convic( (ftnint) ($1->stateno) )); + else if($1->labdefined == NO) + $1->blklevel = blklevel; + $1->labused = YES; + } + ; + +labelval: SICON + { $$ = mklabel( convci(toklen, token) ); } + ; + +implicit: SIMPLICIT in_dcl implist + | implicit SCOMMA implist + ; + +implist: imptype SLPAR letgroups SRPAR + ; + +imptype: { needkwd = 1; } type + { vartype = $2; } + ; + +letgroups: letgroup + | letgroups SCOMMA letgroup + ; + +letgroup: letter + { setimpl(vartype, varleng, $1, $1); } + | letter SMINUS letter + { setimpl(vartype, varleng, $1, $3); } + ; + +letter: SFNAME + { if(toklen!=1 || token[0]<'a' || token[0]>'z') + { + dclerr("implicit item must be single letter", 0); + $$ = 0; + } + else $$ = token[0]; + } + ; + +in_dcl: + { switch(parstate) + { + case OUTSIDE: newproc(); + startproc(0, CLMAIN); + case INSIDE: parstate = INDCL; + case INDCL: break; + + default: + dclerr("declaration among executables", 0); + } + } + ; diff --git a/lang/pcc/pcc/f77/fcom/gram.exec b/lang/pcc/pcc/f77/fcom/gram.exec new file mode 100644 index 000000000..546f4b969 --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/gram.exec @@ -0,0 +1,112 @@ +exec: iffable + | SDO end_spec label opt_comma dospec + { + if($3->labdefined) + execerr("no backward DO loops"); + $3->blklevel = blklevel+1; + exdo($3->labelno, $5); + } + | logif iffable + { exendif(); thiswasbranch = NO; } + | logif STHEN + | SELSEIF end_spec SLPAR expr SRPAR STHEN + { exelif($4); lastwasbranch = NO; } + | SELSE end_spec + { exelse(); lastwasbranch = NO; } + | SENDIF end_spec + { exendif(); lastwasbranch = NO; } + ; + +logif: SLOGIF end_spec SLPAR expr SRPAR + { exif($4); } + ; + +dospec: name SEQUALS exprlist + { $$ = mkchain($1, $3); } + ; + +iffable: let lhs SEQUALS expr + { exequals($2, $4); } + | SASSIGN end_spec labelval STO name + { exassign($5, $3); } + | SCONTINUE end_spec + | goto + | io + { inioctl = NO; } + | SARITHIF end_spec SLPAR expr SRPAR label SCOMMA label SCOMMA label + { exarif($4, $6, $8, $10); thiswasbranch = YES; } + | call + { excall($1, 0, 0, labarray); } + | call SLPAR SRPAR + { excall($1, 0, 0, labarray); } + | call SLPAR callarglist SRPAR + { excall($1, mklist($3), nstars, labarray); } + | SRETURN end_spec opt_expr + { exreturn($3); thiswasbranch = YES; } + | stop end_spec opt_expr + { exstop($1, $3); thiswasbranch = $1; } + ; + +let: SLET + { if(parstate == OUTSIDE) + { + newproc(); + startproc(0, CLMAIN); + } + } + ; + +goto: SGOTO end_spec label + { exgoto($3); thiswasbranch = YES; } + | SASGOTO end_spec name + { exasgoto($3); thiswasbranch = YES; } + | SASGOTO end_spec name opt_comma SLPAR labellist SRPAR + { exasgoto($3); thiswasbranch = YES; } + | SCOMPGOTO end_spec SLPAR labellist SRPAR opt_comma expr + { putcmgo(fixtype($7), nstars, labarray); } + ; + +opt_comma: + | SCOMMA + ; + +call: SCALL end_spec name + { nstars = 0; $$ = $3; } + ; + +callarglist: callarg + { $$ = ($1 ? mkchain($1,0) : 0); } + | callarglist SCOMMA callarg + { if($3) { + if($1) $$ = hookup($1, mkchain($3,0)); + else $$ = mkchain($3,0); + } + } + ; + +callarg: expr + | SSTAR label + { labarray[nstars++] = $2; $$ = 0; } + ; + +stop: SPAUSE + { $$ = 0; } + | SSTOP + { $$ = 1; } + ; + +exprlist: expr + { $$ = mkchain($1, 0); } + | exprlist SCOMMA expr + { $$ = hookup($1, mkchain($3,0) ); } + ; + +end_spec: + { if(parstate == OUTSIDE) + { + newproc(); + startproc(0, CLMAIN); + } + if(parstate < INDATA) enddcl(); + } + ; diff --git a/lang/pcc/pcc/f77/fcom/gram.expr b/lang/pcc/pcc/f77/fcom/gram.expr new file mode 100644 index 000000000..e8977a727 --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/gram.expr @@ -0,0 +1,125 @@ +funarglist: + { $$ = 0; } + | funargs + ; + +funargs: expr + { $$ = mkchain($1, 0); } + | funargs SCOMMA expr + { $$ = hookup($1, mkchain($3,0) ); } + ; + + +expr: uexpr + | SLPAR expr SRPAR { $$ = $2; } + | complex_const + ; + +uexpr: lhs + | simple_const + | expr addop expr %prec SPLUS + { $$ = mkexpr($2, $1, $3); } + | expr SSTAR expr + { $$ = mkexpr(OPSTAR, $1, $3); } + | expr SSLASH expr + { $$ = mkexpr(OPSLASH, $1, $3); } + | expr SPOWER expr + { $$ = mkexpr(OPPOWER, $1, $3); } + | addop expr %prec SSTAR + { if($1 == OPMINUS) + $$ = mkexpr(OPNEG, $2, 0); + else $$ = $2; + } + | expr relop expr %prec SEQ + { $$ = mkexpr($2, $1, $3); } + | expr SEQV expr + { $$ = mkexpr(OPEQV, $1,$3); } + | expr SNEQV expr + { $$ = mkexpr(OPNEQV, $1, $3); } + | expr SOR expr + { $$ = mkexpr(OPOR, $1, $3); } + | expr SAND expr + { $$ = mkexpr(OPAND, $1, $3); } + | SNOT expr + { $$ = mkexpr(OPNOT, $2, 0); } + | expr SCONCAT expr + { $$ = mkexpr(OPCONCAT, $1, $3); } + ; + +addop: SPLUS { $$ = OPPLUS; } + | SMINUS { $$ = OPMINUS; } + ; + +relop: SEQ { $$ = OPEQ; } + | SGT { $$ = OPGT; } + | SLT { $$ = OPLT; } + | SGE { $$ = OPGE; } + | SLE { $$ = OPLE; } + | SNE { $$ = OPNE; } + ; + +lhs: name + { $$ = mkprim($1, 0, 0, 0); } + | name SLPAR opt_expr SCOLON opt_expr SRPAR + { $$ = mkprim($1, 0, $3, $5); } + | name SLPAR funarglist SRPAR + { $$ = mkprim($1, mklist($3), 0, 0); } + | name SLPAR funarglist SRPAR SLPAR opt_expr SCOLON opt_expr SRPAR + { $$ = mkprim($1, mklist($3), $6, $8); } + ; + +opt_expr: + { $$ = 0; } + | expr + ; + +simple: name + { if($1->vclass == CLPARAM) + $$ = cpexpr($1->b_param.paramval); + } + | simple_const + ; + +simple_const: STRUE { $$ = mklogcon(1); } + | SFALSE { $$ = mklogcon(0); } + | SHOLLERITH { $$ = mkstrcon(toklen, token); } + | SICON { $$ = mkintcon( convci(toklen, token) ); } + | SRCON { $$ = mkrealcon(TYREAL, convcd(toklen, token)); } + | SDCON { $$ = mkrealcon(TYDREAL, convcd(toklen, token)); } + ; + +complex_const: SLPAR uexpr SCOMMA uexpr SRPAR + { $$ = mkcxcon($2,$4); } + ; + +bit_const: SHEXCON + { $$ = mkbitcon(4, toklen, token); } + | SOCTCON + { $$ = mkbitcon(3, toklen, token); } + | SBITCON + { $$ = mkbitcon(1, toklen, token); } + ; + +fexpr: unpar_fexpr + | SLPAR fexpr SRPAR + { $$ = $2; } + ; + +unpar_fexpr: lhs + | simple_const + | fexpr addop fexpr %prec SPLUS + { $$ = mkexpr($2, $1, $3); } + | fexpr SSTAR fexpr + { $$ = mkexpr(OPSTAR, $1, $3); } + | fexpr SSLASH fexpr + { $$ = mkexpr(OPSLASH, $1, $3); } + | fexpr SPOWER fexpr + { $$ = mkexpr(OPPOWER, $1, $3); } + | addop fexpr %prec SSTAR + { if($1 == OPMINUS) + $$ = mkexpr(OPNEG, $2, 0); + else $$ = $2; + } + | fexpr SCONCAT fexpr + { $$ = mkexpr(OPCONCAT, $1, $3); } + ; diff --git a/lang/pcc/pcc/f77/fcom/gram.head b/lang/pcc/pcc/f77/fcom/gram.head new file mode 100644 index 000000000..07d5d30ce --- /dev/null +++ b/lang/pcc/pcc/f77/fcom/gram.head @@ -0,0 +1,174 @@ +%{ + +#include "defines.h" +#include "defs.h" + +static int nstars; +static int ndim; +static int vartype; +static ftnint varleng; +struct uux dims[8]; +static struct labelblock *labarray[100]; +static int lastwasbranch = NO; +static int thiswasbranch = NO; + +%} + +/* Specify precedences and associativies. */ + +%left SCOMMA +%nonassoc SCOLON +%right SEQUALS +%left SEQV SNEQV +%left SOR +%left SAND +%left SNOT +%nonassoc SLT SGT SLE SGE SEQ SNE +%left SCONCAT +%left SPLUS SMINUS +%left SSTAR SSLASH +%right SPOWER + +%union { + struct labelblock *label; + struct extsym *extsym; + + bigptr bigptr; + chainp chainp; + + ftnint fint; + char *str; + char token; + int num; +} + +%type