summaryrefslogtreecommitdiff
path: root/utils/cc
diff options
context:
space:
mode:
Diffstat (limited to 'utils/cc')
-rw-r--r--utils/cc/cc.h13
-rw-r--r--utils/cc/com.c2
-rw-r--r--utils/cc/com64.c8
-rw-r--r--utils/cc/dcl.c20
-rw-r--r--utils/cc/dpchk.c49
-rw-r--r--utils/cc/lex.c72
-rw-r--r--utils/cc/lexbody6
-rw-r--r--utils/cc/mkfile2
-rw-r--r--utils/cc/pgen.c548
-rw-r--r--utils/cc/pickle.c2
-rw-r--r--utils/cc/pswt.c144
11 files changed, 822 insertions, 44 deletions
diff --git a/utils/cc/cc.h b/utils/cc/cc.h
index d05b4397..2813d25f 100644
--- a/utils/cc/cc.h
+++ b/utils/cc/cc.h
@@ -121,7 +121,7 @@ struct Type
long width;
long offset;
long lineno;
- char shift;
+ schar shift;
char nbits;
char etype;
char garb;
@@ -317,6 +317,7 @@ enum
TSTRUCT,
TUNION,
TENUM,
+ TDOT,
NTYPE,
TAUTO = NTYPE,
@@ -329,7 +330,6 @@ enum
TVOLATILE,
TUNSIGNED,
TSIGNED,
- TDOT,
TFILE,
TOLD,
NALLTYPES,
@@ -430,6 +430,7 @@ EXTERN Type* firstargtype;
EXTERN Decl* firstdcl;
EXTERN int fperror;
EXTERN Sym* hash[NHASH];
+EXTERN int hasdoubled;
EXTERN char* hunk;
EXTERN char* include[20];
EXTERN Io* iofree;
@@ -473,6 +474,9 @@ EXTERN int nterm;
EXTERN int packflg;
EXTERN int fproundflg;
EXTERN int profileflg;
+EXTERN int ncontin;
+EXTERN int canreach;
+EXTERN int warnreach;
EXTERN Bits zbits;
extern char *onames[], *tnames[], *gnames[];
@@ -501,6 +505,9 @@ extern char typechlvp[];
extern char typechlp[];
extern char typechlpfd[];
+EXTERN char* typeword;
+EXTERN char* typecmplx;
+
extern ulong thash1;
extern ulong thash2;
extern ulong thash3;
@@ -596,7 +603,7 @@ void edecl(int, Type*, Sym*);
Type* fnproto(Node*);
Type* fnproto1(Node*);
void markdcl(void);
-Type* paramconv(Type*, int);
+Type* paramconv(Type*, int, int);
void pdecl(int, Type*, Sym*);
Decl* push(void);
Decl* push1(Sym*);
diff --git a/utils/cc/com.c b/utils/cc/com.c
index 558077b7..59a7bd06 100644
--- a/utils/cc/com.c
+++ b/utils/cc/com.c
@@ -221,6 +221,8 @@ tcomo(Node *n, int f)
if(tcompat(n, l->type, r->type, tand))
goto bad;
n->type = l->type;
+ n->right = new1(OCAST, r, Z);
+ n->right->type = types[TINT];
if(typeu[n->type->etype]) {
if(n->op == OASASHR)
n->op = OASLSHR;
diff --git a/utils/cc/com64.c b/utils/cc/com64.c
index 88bf11bf..e1f7c8a3 100644
--- a/utils/cc/com64.c
+++ b/utils/cc/com64.c
@@ -1,7 +1,7 @@
#include "cc.h"
/*
- * this is machine depend, but it is totally
+ * this is machine dependent, but it is totally
* common on all of the 64-bit symulating machines.
*/
@@ -258,6 +258,8 @@ com64(Node *n)
r->op = OFUNC;
r->type = types[TLONG];
return 1;
+ case OCOND:
+ return 1;
}
}
@@ -503,6 +505,7 @@ setvinc:
n->left = a;
l = new(OADDR, l, Z);
l->type = typ(TIND, l->left->type);
+ l->complex = l->left->complex;
n->right = new(OLIST, l, r);
n->complex = FNX;
n->op = OFUNC;
@@ -536,6 +539,7 @@ setasop:
t = new(OADDR, l, 0);
t->type = typ(TIND, l->type);
+ t->complex = l->complex;
r = new(OLIST, t, r);
n->left = nodvasop;
@@ -551,6 +555,8 @@ bool64(Node *n)
{
Node *n1;
+ if(machcap(Z))
+ return;
if(typev[n->type->etype]) {
n1 = new(OXXX, 0, 0);
*n1 = *n;
diff --git a/utils/cc/dcl.c b/utils/cc/dcl.c
index 71925701..6a8e7245 100644
--- a/utils/cc/dcl.c
+++ b/utils/cc/dcl.c
@@ -347,6 +347,10 @@ init1(Sym *s, Type *t, long o, int exflag)
return Z;
if(a->op == OCONST) {
+ if(vconst(a) && t->etype == TIND && a->type && a->type->etype != TIND){
+ diag(a, "initialize pointer to an integer: %s", s->name);
+ return Z;
+ }
if(!sametype(a->type, t)) {
/* hoop jumping to save malloc */
if(nodcast == Z)
@@ -537,6 +541,7 @@ suallign(Type *t)
l->offset = o;
} else {
if(l->width <= 0)
+ if(l->down != T)
if(l->sym)
diag(Z, "incomplete structure element: %s",
l->sym->name);
@@ -864,7 +869,7 @@ fnproto1(Node *n)
dodecl(NODECL, CXXX, n->type, n->left);
t = typ(TXXX, T);
if(lastdcl != T)
- *t = *paramconv(lastdcl, 1);
+ *t = *paramconv(lastdcl, 1, 0);
return t;
case ONAME:
@@ -970,6 +975,12 @@ rsametype(Type *t1, Type *t2, int n, int f)
snap(t1);
if(t2->link == T)
snap(t2);
+ if(t1 != t2 && t1->link == T && t2->link == T){
+ /* structs with missing or different tag names aren't considered equal */
+ if(t1->tag == nil || t2->tag == nil ||
+ strcmp(t1->tag->name, t2->tag->name) != 0)
+ return 0;
+ }
t1 = t1->link;
t2 = t2->link;
for(;;) {
@@ -990,7 +1001,6 @@ rsametype(Type *t1, Type *t2, int n, int f)
return 1;
}
}
- return 0;
}
typedef struct Typetab Typetab;
@@ -1166,13 +1176,13 @@ dcllabel(Sym *s, int f)
}
Type*
-paramconv(Type *t, int f)
+paramconv(Type *t, int f, int defining)
{
switch(t->etype) {
case TUNION:
case TSTRUCT:
- if(t->width <= 0)
+ if(t->width <= 0 && defining)
diag(Z, "incomplete structure: %s", t->tag->name);
break;
@@ -1266,7 +1276,7 @@ pdecl(int c, Type *t, Sym *s)
diag(Z, "not a parameter: %s", s->name);
return;
}
- t = paramconv(t, c==CPARAM);
+ t = paramconv(t, c==CPARAM, 1);
if(c == CXXX)
c = CPARAM;
if(c != CPARAM) {
diff --git a/utils/cc/dpchk.c b/utils/cc/dpchk.c
index a061b12c..011f9c8a 100644
--- a/utils/cc/dpchk.c
+++ b/utils/cc/dpchk.c
@@ -158,6 +158,7 @@ arginit(void)
argflag('.', Fignor);
argflag('#', Fignor);
argflag('u', Fignor);
+ argflag('h', Fignor);
argflag('+', Fignor);
argflag('-', Fignor);
@@ -444,18 +445,48 @@ void
pragincomplete(void)
{
Sym *s;
+ Type *t;
+ int istag, w, et;
+ istag = 0;
s = getsym();
- if(s){
- if(strcmp(s->name, "_off_") == 0)
- debug['T'] = 0;
- else if(strcmp(s->name, "_on_") == 0)
- debug['T'] = 1;
- else if(s->type == T)
- diag(Z, "unknown type %s in pragma incomplete", s->name);
- else
- s->type->garb |= GINCOMPLETE;
+ if(s == nil)
+ goto out;
+ et = 0;
+ w = s->lexical;
+ if(w == LSTRUCT)
+ et = TSTRUCT;
+ else if(w == LUNION)
+ et = TUNION;
+ if(et != 0){
+ s = getsym();
+ if(s == nil){
+ yyerror("missing struct/union tag in pragma incomplete");
+ goto out;
+ }
+ if(s->lexical != LNAME && s->lexical != LTYPE){
+ yyerror("invalid struct/union tag: %s", s->name);
+ goto out;
+ }
+ dotag(s, et, 0);
+ istag = 1;
+ }else if(strcmp(s->name, "_off_") == 0){
+ debug['T'] = 0;
+ goto out;
+ }else if(strcmp(s->name, "_on_") == 0){
+ debug['T'] = 1;
+ goto out;
}
+ t = s->type;
+ if(istag)
+ t = s->suetag;
+ if(t == T)
+ yyerror("unknown type %s in pragma incomplete", s->name);
+ else if(!typesu[t->etype])
+ yyerror("not struct/union type in pragma incomplete: %s", s->name);
+ else
+ t->garb |= GINCOMPLETE;
+out:
while(getnsc() != '\n')
;
if(debug['f'])
diff --git a/utils/cc/lex.c b/utils/cc/lex.c
index 7a99164b..8e96b7bb 100644
--- a/utils/cc/lex.c
+++ b/utils/cc/lex.c
@@ -7,27 +7,30 @@
/*
* known debug flags
- * -o file output file
- * -D name define
- * -I path include
* -a acid declaration output
- * -M constant multiplication
- * -B non ANSI
* -A !B
+ * -B non ANSI
* -d print declarations
- * -t print type trees
- * -L print every NAME symbol
- * -i print initialization
+ * -D name define
* -F format specification check
- * -r print registerization
- * -v verbose printing
- * -X abort on error
- * -w print warnings
+ * -i print initialization
+ * -I path include
+ * -l generate little-endian code
+ * -L print every NAME symbol
+ * -M constant multiplication
* -m print add/sub/mul trees
- * -s print structure offsets (with -a or -aa)
* -n print acid to file (%.c=%.acid) (with -a or -aa)
+ * -o file output file
* -p use standard cpp ANSI preprocessor (not on windows)
+ * -r print registerization
+ * -s print structure offsets (with -a or -aa)
+ * -S print assembly
+ * -t print type trees
* -V enable void* conversion warnings
+ * -v verbose printing
+ * -w print warnings
+ * -X abort on error
+ * -. Inhibit search for includes in source directory
*/
void
@@ -54,6 +57,15 @@ main(int argc, char *argv[])
debug[c]++;
break;
+ case 'l': /* for little-endian mips */
+ if(thechar != 'v'){
+ print("can only use -l with vc");
+ errorexit();
+ }
+ thechar = '0';
+ thestring = "spim";
+ break;
+
case 'o':
outfile = ARGF();
break;
@@ -81,7 +93,12 @@ main(int argc, char *argv[])
}
if(argc > 1 && !systemtype(Windows)) {
nproc = 1;
- if(p = getenv("NPROC"))
+ /*
+ * if we're writing acid to standard output, don't compile
+ * concurrently, to avoid interleaving output.
+ */
+ if(((!debug['a'] && !debug['Z']) || debug['n']) &&
+ (p = getenv("NPROC")) != nil)
nproc = atol(p); /* */
c = 0;
nout = 0;
@@ -137,6 +154,7 @@ compile(char *file, char **defs, int ndef)
char ofile[400], incfile[20];
char *p, *av[100], opt[256];
int i, c, fd[2];
+ static int first = 1;
strcpy(ofile, file);
p = utfrrune(ofile, pathchar());
@@ -146,6 +164,7 @@ compile(char *file, char **defs, int ndef)
include[0] = strdup(ofile);
} else
p = ofile;
+
if(outfile == 0) {
outfile = p;
if(outfile) {
@@ -175,21 +194,29 @@ compile(char *file, char **defs, int ndef)
setinclude("/sys/include");
}
}
+ if (first)
+ Binit(&diagbuf, 1, OWRITE);
+ /*
+ * if we're writing acid to standard output, don't keep scratching
+ * outbuf.
+ */
if((debug['a'] || debug['Z']) && !debug['n']) {
- outfile = 0;
- Binit(&outbuf, 1, OWRITE);
- Binit(&diagbuf, 2, OWRITE);
+ if (first) {
+ outfile = 0;
+ Binit(&outbuf, dup(1, -1), OWRITE);
+ dup(2, 1);
+ }
} else {
c = mycreat(outfile, 0664);
if(c < 0) {
- diag(Z, "cannot open %s", outfile);
+ diag(Z, "cannot open %s - %r", outfile);
outfile = 0;
errorexit();
}
Binit(&outbuf, c, OWRITE);
- Binit(&diagbuf, 1, OWRITE);
}
newio();
+ first = 0;
/* Use an ANSI preprocessor */
if(debug['p']) {
@@ -215,6 +242,10 @@ compile(char *file, char **defs, int ndef)
close(fd[1]);
av[0] = CPP;
i = 1;
+ if(debug['.']){
+ sprint(opt, "-.");
+ av[i++] = strdup(opt);
+ }
if(debug['+']) {
sprint(opt, "-+");
av[i++] = strdup(opt);
@@ -1005,7 +1036,6 @@ getnsc(void)
}
c = GETC();
}
- return 0;
}
void
@@ -1123,9 +1153,11 @@ struct
"for", LFOR, 0,
"goto", LGOTO, 0,
"if", LIF, 0,
+ "inline", LINLINE, 0,
"int", LINT, TINT,
"long", LLONG, TLONG,
"register", LREGISTER, 0,
+ "restrict", LRESTRICT, 0,
"return", LRETURN, 0,
"SET", LSET, 0,
"short", LSHORT, TSHORT,
diff --git a/utils/cc/lexbody b/utils/cc/lexbody
index d8e3f6eb..6b226ada 100644
--- a/utils/cc/lexbody
+++ b/utils/cc/lexbody
@@ -417,10 +417,8 @@ l1:
if(c1 == '/') {
for(;;) {
c = GETC();
- if(c == '\n') {
- lineno++;
- goto l0;
- }
+ if(c == '\n')
+ goto l1;
if(c == EOF) {
yyerror("eof in comment");
errorexit();
diff --git a/utils/cc/mkfile b/utils/cc/mkfile
index c2df13a5..9a5036be 100644
--- a/utils/cc/mkfile
+++ b/utils/cc/mkfile
@@ -18,7 +18,7 @@ OFILES=\
scon.$O\
sub.$O\
y.tab.$O\
- machcap.$O\
+ omachcap.$O\
HFILES=cc.h\
y.tab.h\
diff --git a/utils/cc/pgen.c b/utils/cc/pgen.c
new file mode 100644
index 00000000..131ff012
--- /dev/null
+++ b/utils/cc/pgen.c
@@ -0,0 +1,548 @@
+#include "gc.h"
+
+void
+codgen(Node *n, Node *nn)
+{
+ Prog *sp;
+ Node *n1, nod, nod1;
+
+ cursafe = 0;
+ curarg = 0;
+ maxargsafe = 0;
+ hasdoubled = 0;
+
+ /*
+ * isolate name
+ */
+ for(n1 = nn;; n1 = n1->left) {
+ if(n1 == Z) {
+ diag(nn, "cant find function name");
+ return;
+ }
+ if(n1->op == ONAME)
+ break;
+ }
+ nearln = nn->lineno;
+ gpseudo(ATEXT, n1->sym, nodconst(stkoff));
+ sp = p;
+
+ if(typecmplx[thisfn->link->etype]) {
+ if(nodret == nil) {
+ nodret = new(ONAME, Z, Z);
+ nodret->sym = slookup(".ret");
+ nodret->class = CPARAM;
+ nodret->type = types[TIND];
+ nodret->etype = TIND;
+ nodret = new(OIND, nodret, Z);
+ }
+ n1 = nodret->left;
+ if(n1->type == T || n1->type->link != thisfn->link) {
+ n1->type = typ(TIND, thisfn->link);
+ n1->etype = n1->type->etype;
+ nodret = new(OIND, n1, Z);
+ complex(nodret);
+ }
+ }
+
+ /*
+ * isolate first argument
+ */
+ if(REGARG >= 0) {
+ if(typecmplx[thisfn->link->etype]) {
+ nod1 = *nodret->left;
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ } else
+ if(firstarg && typeword[firstargtype->etype]) {
+ nod1 = znode;
+ nod1.op = ONAME;
+ nod1.sym = firstarg;
+ nod1.type = firstargtype;
+ nod1.class = CPARAM;
+ nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.etype = firstargtype->etype;
+ xcom(&nod1);
+ nodreg(&nod, &nod1, REGARG);
+ gmove(&nod, &nod1);
+ }
+ }
+
+ canreach = 1;
+ warnreach = 1;
+ gen(n);
+ if(canreach && thisfn->link->etype != TVOID)
+ warn(Z, "no return at end of function: %s", n1->sym->name);
+ noretval(3);
+ gbranch(ORETURN);
+
+ if(!debug['N'] || debug['R'] || debug['P'])
+ regopt(sp);
+
+ if(thechar=='6' || thechar=='7' || thechar=='9' || hasdoubled) /* [sic] */
+ maxargsafe = round(maxargsafe, 8);
+ sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+ int owarn;
+ long spc;
+ Prog *sp;
+
+ if(n == Z)
+ return;
+ suppress++;
+ owarn = warnreach;
+ warnreach = 0;
+ spc = pc;
+ sp = lastp;
+ gen(n);
+ lastp = sp;
+ pc = spc;
+ sp->link = nil;
+ suppress--;
+ warnreach = owarn;
+}
+
+void
+gen(Node *n)
+{
+ Node *l, nod;
+ Prog *sp, *spc, *spb;
+ Case *cn;
+ long sbc, scc;
+ int snbreak, sncontin;
+ int f, o, oldreach;
+
+loop:
+ if(n == Z)
+ return;
+ nearln = n->lineno;
+ o = n->op;
+ if(debug['G'])
+ if(o != OLIST)
+ print("%L %O\n", nearln, o);
+
+ if(!canreach) {
+ switch(o) {
+ case OLABEL:
+ case OCASE:
+ case OLIST:
+ case OBREAK:
+ case OFOR:
+ case OWHILE:
+ case ODWHILE:
+ /* all handled specially - see switch body below */
+ break;
+ default:
+ if(warnreach) {
+ warn(n, "unreachable code %O", o);
+ warnreach = 0;
+ }
+ }
+ }
+
+ switch(o) {
+
+ default:
+ complex(n);
+ cgen(n, Z);
+ break;
+
+ case OLIST:
+ gen(n->left);
+
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ canreach = 0;
+ warnreach = !suppress;
+ complex(n);
+ if(n->type == T)
+ break;
+ l = n->left;
+ if(l == Z) {
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ if(typecmplx[n->type->etype]) {
+ nod = znode;
+ nod.op = OAS;
+ nod.left = nodret;
+ nod.right = l;
+ nod.type = n->type;
+ nod.complex = l->complex;
+ cgen(&nod, Z);
+ noretval(3);
+ gbranch(ORETURN);
+ break;
+ }
+ regret(&nod, n);
+ cgen(l, &nod);
+ regfree(&nod);
+ if(typefd[n->type->etype])
+ noretval(1);
+ else
+ noretval(2);
+ gbranch(ORETURN);
+ break;
+
+ case OLABEL:
+ canreach = 1;
+ l = n->left;
+ if(l) {
+ l->pc = pc;
+ if(l->label)
+ patch(l->label, pc);
+ }
+ gbranch(OGOTO); /* prevent self reference in reg */
+ patch(p, pc);
+ goto rloop;
+
+ case OGOTO:
+ canreach = 0;
+ warnreach = !suppress;
+ n = n->left;
+ if(n == Z)
+ return;
+ if(n->complex == 0) {
+ diag(Z, "label undefined: %s", n->sym->name);
+ return;
+ }
+ if(suppress)
+ return;
+ gbranch(OGOTO);
+ if(n->pc) {
+ patch(p, n->pc);
+ return;
+ }
+ if(n->label)
+ patch(n->label, pc-1);
+ n->label = p;
+ return;
+
+ case OCASE:
+ canreach = 1;
+ l = n->left;
+ if(cases == C)
+ diag(n, "case/default outside a switch");
+ if(l == Z) {
+ casf();
+ cases->val = 0;
+ cases->def = 1;
+ cases->label = pc;
+ cases->isv = 0;
+ goto rloop;
+ }
+ complex(l);
+ if(l->type == T)
+ goto rloop;
+ if(l->op == OCONST)
+ if(typeword[l->type->etype] && l->type->etype != TIND) {
+ casf();
+ cases->val = l->vconst;
+ cases->def = 0;
+ cases->label = pc;
+ cases->isv = typev[l->type->etype];
+ goto rloop;
+ }
+ diag(n, "case expression must be integer constant");
+ goto rloop;
+
+ case OSWITCH:
+ l = n->left;
+ complex(l);
+ if(l->type == T)
+ break;
+ if(!typeword[l->type->etype] || l->type->etype == TIND) {
+ diag(n, "switch expression must be integer");
+ break;
+ }
+
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ cn = cases;
+ cases = C;
+ casf();
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ gen(n->right); /* body */
+ if(canreach){
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ nbreak++;
+ }
+
+ patch(sp, pc);
+ regalloc(&nod, l, Z);
+ /* always signed */
+ if(typev[l->type->etype])
+ nod.type = types[TVLONG];
+ else
+ nod.type = types[TLONG];
+ cgen(l, &nod);
+ doswit(&nod);
+ regfree(&nod);
+ patch(spb, pc);
+
+ cases = cn;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ break;
+
+ case OWHILE:
+ case ODWHILE:
+ l = n->left;
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ if(n->op == OWHILE)
+ patch(sp, pc);
+ bcomplex(l, Z); /* test */
+ patch(p, breakpc);
+ if(l->op != OCONST || vconst(l) == 0)
+ nbreak++;
+
+ if(n->op == ODWHILE)
+ patch(sp, pc);
+ gen(n->right); /* body */
+ gbranch(OGOTO);
+ patch(p, continpc);
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ break;
+
+ case OFOR:
+ l = n->left;
+ if(!canreach && l->right->left && warnreach) {
+ warn(n, "unreachable code FOR");
+ warnreach = 0;
+ }
+ gen(l->right->left); /* init */
+ gbranch(OGOTO); /* entry */
+ sp = p;
+
+ /*
+ * if there are no incoming labels in the
+ * body and the top's not reachable, warn
+ */
+ if(!canreach && warnreach && deadheads(n)) {
+ warn(n, "unreachable code %O", o);
+ warnreach = 0;
+ }
+
+ scc = continpc;
+ continpc = pc;
+ gbranch(OGOTO);
+ spc = p;
+
+ sbc = breakpc;
+ breakpc = pc;
+ snbreak = nbreak;
+ nbreak = 0;
+ sncontin = ncontin;
+ ncontin = 0;
+ gbranch(OGOTO);
+ spb = p;
+
+ patch(spc, pc);
+ gen(l->right->right); /* inc */
+ patch(sp, pc);
+ if(l->left != Z) { /* test */
+ bcomplex(l->left, Z);
+ patch(p, breakpc);
+ if(l->left->op != OCONST || vconst(l->left) == 0)
+ nbreak++;
+ }
+ canreach = 1;
+ gen(n->right); /* body */
+ if(canreach){
+ gbranch(OGOTO);
+ patch(p, continpc);
+ ncontin++;
+ }
+ if(!ncontin && l->right->right && warnreach) {
+ warn(l->right->right, "unreachable FOR inc");
+ warnreach = 0;
+ }
+
+ patch(spb, pc);
+ continpc = scc;
+ breakpc = sbc;
+ canreach = nbreak!=0;
+ if(canreach == 0)
+ warnreach = !suppress;
+ nbreak = snbreak;
+ ncontin = sncontin;
+ break;
+
+ case OCONTINUE:
+ if(continpc < 0) {
+ diag(n, "continue not in a loop");
+ break;
+ }
+ gbranch(OGOTO);
+ patch(p, continpc);
+ ncontin++;
+ canreach = 0;
+ warnreach = !suppress;
+ break;
+
+ case OBREAK:
+ if(breakpc < 0) {
+ diag(n, "break not in a loop");
+ break;
+ }
+ /*
+ * Don't complain about unreachable break statements.
+ * There are breaks hidden in yacc's output and some people
+ * write return; break; in their switch statements out of habit.
+ * However, don't confuse the analysis by inserting an
+ * unreachable reference to breakpc either.
+ */
+ if(!canreach)
+ break;
+ gbranch(OGOTO);
+ patch(p, breakpc);
+ nbreak++;
+ canreach = 0;
+ warnreach = !suppress;
+ break;
+
+ case OIF:
+ l = n->left;
+ if(bcomplex(l, n->right)) {
+ if(typefd[l->type->etype])
+ f = !l->fconst;
+ else
+ f = !l->vconst;
+ if(debug['c'])
+ print("%L const if %s\n", nearln, f ? "false" : "true");
+ if(f) {
+ canreach = 1;
+ supgen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ gen(n->right->right);
+ /*
+ * treat constant ifs as regular ifs for
+ * reachability warnings.
+ */
+ if(!canreach && oldreach && debug['w'] < 2)
+ warnreach = 0;
+ }
+ else {
+ canreach = 1;
+ gen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ supgen(n->right->right);
+ /*
+ * treat constant ifs as regular ifs for
+ * reachability warnings.
+ */
+ if(!oldreach && canreach && debug['w'] < 2)
+ warnreach = 0;
+ canreach = oldreach;
+ }
+ }
+ else {
+ sp = p;
+ canreach = 1;
+ if(n->right->left != Z)
+ gen(n->right->left);
+ oldreach = canreach;
+ canreach = 1;
+ if(n->right->right != Z) {
+ gbranch(OGOTO);
+ patch(sp, pc);
+ sp = p;
+ gen(n->right->right);
+ }
+ patch(sp, pc);
+ canreach = canreach || oldreach;
+ if(canreach == 0)
+ warnreach = !suppress;
+ }
+ break;
+
+ case OSET:
+ case OUSED:
+ usedset(n->left, o);
+ break;
+ }
+}
+
+void
+usedset(Node *n, int o)
+{
+ if(n->op == OLIST) {
+ usedset(n->left, o);
+ usedset(n->right, o);
+ return;
+ }
+ complex(n);
+ switch(n->op) {
+ case OADDR: /* volatile */
+ gins(ANOP, n, Z);
+ break;
+ case ONAME:
+ if(o == OSET)
+ gins(ANOP, Z, n);
+ else
+ gins(ANOP, n, Z);
+ break;
+ }
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+
+ complex(n);
+ if(n->type != T)
+ if(tcompat(n, T, n->type, tnot))
+ n->type = T;
+ if(n->type == T) {
+ gbranch(OGOTO);
+ return 0;
+ }
+ if(c != Z && n->op == OCONST && deadheads(c))
+ return 1;
+ bool64(n);
+ boolgen(n, 1, Z);
+ return 0;
+}
diff --git a/utils/cc/pickle.c b/utils/cc/pickle.c
index 370b9983..ef8df4c0 100644
--- a/utils/cc/pickle.c
+++ b/utils/cc/pickle.c
@@ -195,7 +195,7 @@ pickletype(Type *t)
goto asmstr;
an = pmap(s->name);
- Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an);
+ Bprint(&outbuf, "uchar*\npickle_%s(uchar *bp, uchar *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an);
for(l = t->link; l != T; l = l->down)
picklemember(l, 0);
Bprint(&outbuf, "\treturn bp;\n}\n\n");
diff --git a/utils/cc/pswt.c b/utils/cc/pswt.c
new file mode 100644
index 00000000..6ef4f2fb
--- /dev/null
+++ b/utils/cc/pswt.c
@@ -0,0 +1,144 @@
+#include "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+ C1 *p1, *p2;
+
+ p1 = (C1*)a1;
+ p2 = (C1*)a2;
+ if(p1->val < p2->val)
+ return -1;
+ return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+ Case *c;
+ C1 *q, *iq;
+ long def, nc, i, isv;
+ int dup;
+
+ def = 0;
+ nc = 0;
+ isv = 0;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def) {
+ if(def)
+ diag(n, "more than one default in switch");
+ def = c->label;
+ continue;
+ }
+ isv |= c->isv;
+ nc++;
+ }
+ if(isv && !typev[n->type->etype])
+ warn(n, "32-bit switch expression with 64-bit case constant");
+
+ iq = alloc(nc*sizeof(C1));
+ q = iq;
+ for(c = cases; c->link != C; c = c->link) {
+ if(c->def)
+ continue;
+ q->label = c->label;
+ if(isv)
+ q->val = c->val;
+ else
+ q->val = (long)c->val; /* cast ensures correct value for 32-bit switch on 64-bit architecture */
+ q++;
+ }
+ qsort(iq, nc, sizeof(C1), swcmp);
+ if(debug['W'])
+ for(i=0; i<nc; i++)
+ print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val);
+ dup = 0;
+ for(i=0; i<nc-1; i++)
+ if(iq[i].val == iq[i+1].val) {
+ diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
+ dup = 1;
+ }
+ if(dup)
+ return;
+ if(def == 0) {
+ def = breakpc;
+ nbreak++;
+ }
+ swit1(iq, nc, def, n);
+}
+
+void
+casf(void)
+{
+ Case *c;
+
+ c = alloc(sizeof(*c));
+ c->link = cases;
+ cases = c;
+}
+
+long
+outlstring(ushort *s, long n)
+{
+ char buf[2];
+ int c;
+ long r;
+
+ if(suppress)
+ return nstring;
+ while(nstring & 1)
+ outstring("", 1);
+ r = nstring;
+ while(n > 0) {
+ c = *s++;
+ if(align(0, types[TCHAR], Aarg1)) {
+ buf[0] = c>>8;
+ buf[1] = c;
+ } else {
+ buf[0] = c;
+ buf[1] = c>>8;
+ }
+ outstring(buf, 2);
+ n -= sizeof(ushort);
+ }
+ return r;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+ warn(Z, "result of operation not used");
+ if(l != Z)
+ cgen(l, Z);
+ if(r != Z)
+ cgen(r, Z);
+}
+
+void
+ieeedtod(Ieee *ieee, double native)
+{
+ double fr, ho, f;
+ int exp;
+
+ if(native < 0) {
+ ieeedtod(ieee, -native);
+ ieee->h |= 0x80000000L;
+ return;
+ }
+ if(native == 0) {
+ ieee->l = 0;
+ ieee->h = 0;
+ return;
+ }
+ fr = frexp(native, &exp);
+ f = 2097152L; /* shouldnt use fp constants here */
+ fr = modf(fr*f, &ho);
+ ieee->h = ho;
+ ieee->h &= 0xfffffL;
+ ieee->h |= (exp+1022L) << 20;
+ f = 65536L;
+ fr = modf(fr*f, &ho);
+ ieee->l = ho;
+ ieee->l <<= 16;
+ ieee->l |= (long)(fr*f);
+}