summaryrefslogtreecommitdiff
path: root/usr.bin/pcc/ccom
diff options
context:
space:
mode:
authorStefan Kempf <stefan@cvs.openbsd.org>2007-11-22 15:06:44 +0000
committerStefan Kempf <stefan@cvs.openbsd.org>2007-11-22 15:06:44 +0000
commit7abafbe7948887da7ef709612930fdb77ee8eed9 (patch)
treefbfa7c7793f3e2004f9d3ce25351e32415818d6f /usr.bin/pcc/ccom
parent9f7362ac1c12b1c54bcafe0722250b9effa94b3e (diff)
Pull from master repo:
Put the genswitch() code that is found in most backends into the MI part. The backend version is renamed to mygenswitch() and can provide improved translations for switch statements. Improved implementation of the switch constraints/semantics described in the standard. ok ragge@, otto@ With help and comments from ragge and gmcgarry
Diffstat (limited to 'usr.bin/pcc/ccom')
-rw-r--r--usr.bin/pcc/ccom/cgram.y101
-rw-r--r--usr.bin/pcc/ccom/pass1.h5
-rw-r--r--usr.bin/pcc/ccom/trees.c17
3 files changed, 97 insertions, 26 deletions
diff --git a/usr.bin/pcc/ccom/cgram.y b/usr.bin/pcc/ccom/cgram.y
index 10961e47eae..7cec014fb61 100644
--- a/usr.bin/pcc/ccom/cgram.y
+++ b/usr.bin/pcc/ccom/cgram.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: cgram.y,v 1.5 2007/11/18 17:39:55 ragge Exp $ */
+/* $OpenBSD: cgram.y,v 1.6 2007/11/22 15:06:43 stefan Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
@@ -169,7 +169,8 @@ static void swend(void);
static void addcase(NODE *p);
static void adddef(void);
static void savebc(void);
-static void swstart(int);
+static void swstart(int, TWORD);
+static void genswitch(int, TWORD, struct swents **, int);
static NODE * structref(NODE *p, int f, char *name);
static char *mkpstr(char *str);
static struct symtab *clbrace(NODE *);
@@ -863,23 +864,24 @@ forprefix: C_FOR '(' .e ';' .e ';' {
switchpart: C_SWITCH '(' e ')' {
NODE *p;
int num;
+ TWORD t;
savebc();
brklab = getlab();
- if ($3->n_type != INT) {
- /* must cast to integer */
- p = block(NAME, NIL, NIL, INT, 0, MKSUE(INT));
- p = buildtree(CAST, p, $3);
- $3 = p->n_right;
- nfree(p->n_left);
- nfree(p);
+ if (($3->n_type != BOOL && $3->n_type > ULONGLONG) ||
+ $3->n_type < CHAR) {
+ uerror("switch expression must have integer "
+ "type");
+ t = INT;
+ } else {
+ $3 = intprom($3);
+ t = $3->n_type;
}
-// ecomp( buildtree( FORCE, $3, NIL ) );
- p = tempnode(0, INT, 0, MKSUE(INT));
+ p = tempnode(0, t, 0, MKSUE(t));
num = p->n_lval;
ecomp(buildtree(ASSIGN, p, $3));
branch( $$ = getlab());
- swstart(num);
+ swstart(num, t);
reached = 0;
}
;
@@ -1145,6 +1147,7 @@ struct swdef {
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;
/*
@@ -1154,6 +1157,7 @@ static void
addcase(NODE *p)
{
struct swents **put, *w, *sw = tmpalloc(sizeof(struct swents));
+ CONSZ val;
p = optim(p); /* change enum to ints */
if (p->n_op != ICON || p->n_sp != NULL) {
@@ -1165,19 +1169,35 @@ addcase(NODE *p)
return;
}
+ val = p->n_lval;
+ p = makety(p, swpole->type, 0, 0, MKSUE(swpole->type));
+ if (p->n_op != ICON)
+ cerror("could not cast case value to type of switch "
+ "expression");
+ if (p->n_lval != val)
+ werror("case expression truncated");
+
sw->sval = p->n_lval;
+ tfree(p);
put = &swpole->ents;
- for (w = swpole->ents; w != NULL && w->sval < sw->sval; w = w->next)
- put = &w->next;
- if (w != NULL && w->sval == sw->sval)
+ 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");
- else {
- plabel(sw->slab = getlab());
- *put = sw;
- sw->next = w;
- swpole->nents++;
+ return;
}
- tfree(p);
+ plabel(sw->slab = getlab());
+ *put = sw;
+ sw->next = w;
+ swpole->nents++;
}
/*
@@ -1195,7 +1215,7 @@ adddef(void)
}
static void
-swstart(int num)
+swstart(int num, TWORD type)
{
struct swdef *sw = tmpalloc(sizeof(struct swdef));
@@ -1203,6 +1223,7 @@ swstart(int num)
sw->ents = NULL;
sw->next = swpole;
sw->num = num;
+ sw->type = type;
swpole = sw;
}
@@ -1225,12 +1246,46 @@ swend(void)
swp[i] = swpole->ents;
swpole->ents = swpole->ents->next;
}
- genswitch(swpole->num, swp, swpole->nents);
+ 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, MKSUE(type));
+ q = block(ICON, NIL, NIL, type, 0, MKSUE(type));
+ q->n_sp = NULL;
+ q->n_lval = p[i]->sval;
+ 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 *
diff --git a/usr.bin/pcc/ccom/pass1.h b/usr.bin/pcc/ccom/pass1.h
index c736b681043..052673848d2 100644
--- a/usr.bin/pcc/ccom/pass1.h
+++ b/usr.bin/pcc/ccom/pass1.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pass1.h,v 1.4 2007/11/18 17:39:55 ragge Exp $ */
+/* $OpenBSD: pass1.h,v 1.5 2007/11/22 15:06:43 stefan Exp $ */
/*
* Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
*
@@ -177,7 +177,7 @@ struct swents { /* switch table */
CONSZ sval; /* case value */
int slab; /* associated label */
};
-void genswitch(int, struct swents **, int);
+int mygenswitch(int, TWORD, struct swents **, int);
extern int blevel;
extern int instruct, got_type;
@@ -254,6 +254,7 @@ extern NODE
*btsize(TWORD, union dimfun *, struct suedef *),
*tempnode(int, TWORD type, union dimfun *df, struct suedef *sue),
*doacall(NODE *f, NODE *a);
+NODE *intprom(NODE *);
OFFSZ tsize(TWORD, union dimfun *, struct suedef *),
psize(NODE *);
NODE * typenode(NODE *new);
diff --git a/usr.bin/pcc/ccom/trees.c b/usr.bin/pcc/ccom/trees.c
index 1fa2ecc9c74..7d93e4a97d2 100644
--- a/usr.bin/pcc/ccom/trees.c
+++ b/usr.bin/pcc/ccom/trees.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trees.c,v 1.9 2007/11/18 17:39:55 ragge Exp $ */
+/* $OpenBSD: trees.c,v 1.10 2007/11/22 15:06:43 stefan Exp $ */
/*
* Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
* All rights reserved.
@@ -2398,3 +2398,18 @@ plabel(int label)
reached = 1; /* Will this always be correct? */
send_passt(IP_DEFLAB, 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, MKSUE(UNSIGNED));
+ return makety(n, INT, 0, 0, MKSUE(INT));
+ }
+ return n;
+}