aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-04-23 21:22:25 -0700
committerMichael Forney <mforney@mforney.org>2019-04-23 21:23:19 -0700
commita98385a607aafe373c14d2a6fb2778d21a600c30 (patch)
tree2b4c71cfb8f7ceab26e65f4489905a85488f6791
parente0b772b836265b77686e9a7aa8ad01bb1fca53e7 (diff)
Fix integer promotion on bit-fields
Fixes #47.
-rw-r--r--cc.h6
-rw-r--r--expr.c33
-rw-r--r--qbe.c2
-rw-r--r--stmt.c2
-rw-r--r--test/bitfield-integer-promotion-long.c6
-rw-r--r--test/bitfield-integer-promotion-long.qbe6
-rw-r--r--test/bitfield-integer-promotion.c7
-rw-r--r--test/bitfield-integer-promotion.qbe17
-rw-r--r--type.c27
9 files changed, 79 insertions, 27 deletions
diff --git a/cc.h b/cc.h
index ec6339f..0a6641f 100644
--- a/cc.h
+++ b/cc.h
@@ -400,9 +400,8 @@ _Bool typecompatible(struct type *, struct type *);
_Bool typesame(struct type *, struct type *);
struct type *typecomposite(struct type *, struct type *);
struct type *typeunqual(struct type *, enum typequal *);
-struct type *typecommonreal(struct type *, struct type *);
-struct type *typeargpromote(struct type *);
-struct type *typeintpromote(struct type *);
+struct type *typecommonreal(struct type *, unsigned, struct type *, unsigned);
+struct type *typepromote(struct type *, unsigned);
enum typeprop typeprop(struct type *);
struct member *typemember(struct type *, const char *, uint64_t *);
@@ -451,6 +450,7 @@ uint64_t intconstexpr(struct scope *, _Bool);
void delexpr(struct expr *);
struct expr *exprconvert(struct expr *, struct type *);
+struct expr *exprpromote(struct expr *);
/* eval */
diff --git a/expr.c b/expr.c
index 52ff22b..0526b93 100644
--- a/expr.c
+++ b/expr.c
@@ -107,12 +107,29 @@ mkunaryexpr(enum tokenkind op, struct expr *base)
fatal("internal error: unknown unary operator %d", op);
}
+static unsigned
+bitfieldwidth(struct expr *e)
+{
+ if (e->kind != EXPRBITFIELD)
+ return -1;
+ return e->type->size * 8 - e->bitfield.bits.before - e->bitfield.bits.after;
+}
+
+struct expr *
+exprpromote(struct expr *e)
+{
+ struct type *t;
+
+ t = typepromote(e->type, bitfieldwidth(e));
+ return exprconvert(e, t);
+}
+
static struct type *
commonreal(struct expr **e1, struct expr **e2)
{
struct type *t;
- t = typecommonreal((*e1)->type, (*e2)->type);
+ t = typecommonreal((*e1)->type, bitfieldwidth(*e1), (*e2)->type, bitfieldwidth(*e2));
*e1 = exprconvert(*e1, t);
*e2 = exprconvert(*e2, t);
@@ -208,8 +225,8 @@ mkbinaryexpr(struct location *loc, enum tokenkind op, struct expr *l, struct exp
case TSHR:
if (!(lp & PROPINT) || !(rp & PROPINT))
error(loc, "operands to '%s' operator must be integer", tokstr[op]);
- l = exprconvert(l, typeintpromote(l->type));
- r = exprconvert(r, typeintpromote(r->type));
+ l = exprpromote(l);
+ r = exprpromote(r);
t = l->type;
break;
default:
@@ -597,7 +614,7 @@ postfixexpr(struct scope *s, struct expr *r)
error(&tok.loc, "too many arguments for function call");
*end = assignexpr(s);
if (!t->func.isprototype || (t->func.isvararg && !p))
- *end = exprconvert(*end, typeargpromote((*end)->type));
+ *end = exprpromote(*end);
else
*end = exprconvert(*end, p->type);
end = &(*end)->next;
@@ -682,14 +699,16 @@ unaryexpr(struct scope *s)
e = castexpr(s);
if (!(e->type->prop & PROPARITH))
error(&tok.loc, "operand of unary '+' operator must have arithmetic type");
- e = exprconvert(e, typeintpromote(e->type));
+ if (e->type->prop & PROPINT)
+ e = exprpromote(e);
break;
case TSUB:
next();
e = castexpr(s);
if (!(e->type->prop & PROPARITH))
error(&tok.loc, "operand of unary '-' operator must have arithmetic type");
- e = exprconvert(e, typeintpromote(e->type));
+ if (e->type->prop & PROPINT)
+ e = exprpromote(e);
e = mkbinaryexpr(&tok.loc, TSUB, mkconstexpr(&typeint, 0), e);
break;
case TBNOT:
@@ -697,7 +716,7 @@ unaryexpr(struct scope *s)
e = castexpr(s);
if (!(e->type->prop & PROPINT))
error(&tok.loc, "operand of '~' operator must have integer type");
- e = exprconvert(e, typeintpromote(e->type));
+ e = exprpromote(e);
e = mkbinaryexpr(&tok.loc, TXOR, e, mkconstexpr(e->type, -1));
break;
case TLNOT:
diff --git a/qbe.c b/qbe.c
index 06d6615..68bc1b3 100644
--- a/qbe.c
+++ b/qbe.c
@@ -382,7 +382,7 @@ mkfunc(char *name, struct type *t, struct scope *s)
for (p = t->func.params; p; p = p->next) {
if (!p->name)
error(&tok.loc, "parameter name omitted in function definition");
- if (!t->func.isprototype && !typecompatible(p->type, typeargpromote(p->type)))
+ if (!t->func.isprototype && !typecompatible(p->type, typepromote(p->type, -1)))
error(&tok.loc, "old-style function definition with parameter type incompatible with promoted type is not yet supported");
emittype(p->type);
d = mkdecl(DECLOBJECT, p->type, p->qual, LINKNONE);
diff --git a/stmt.c b/stmt.c
index 4033a69..c53c969 100644
--- a/stmt.c
+++ b/stmt.c
@@ -127,7 +127,7 @@ stmt(struct func *f, struct scope *s)
if (!(e->type->prop & PROPINT))
error(&tok.loc, "controlling expression of switch statement must have integer type");
- e = exprconvert(e, typeintpromote(e->type));
+ e = exprpromote(e);
label[0] = mkblock("switch_cond");
label[1] = mkblock("switch_join");
diff --git a/test/bitfield-integer-promotion-long.c b/test/bitfield-integer-promotion-long.c
new file mode 100644
index 0000000..fc51fbc
--- /dev/null
+++ b/test/bitfield-integer-promotion-long.c
@@ -0,0 +1,6 @@
+struct {unsigned long x:31;} s1;
+struct {unsigned long x:32;} s2;
+struct {unsigned long x:33;} s3;
+int c1 = __builtin_types_compatible_p(__typeof__(+s1.x), int);
+int c2 = __builtin_types_compatible_p(__typeof__(+s2.x), unsigned);
+int c3 = __builtin_types_compatible_p(__typeof__(+s3.x), unsigned long);
diff --git a/test/bitfield-integer-promotion-long.qbe b/test/bitfield-integer-promotion-long.qbe
new file mode 100644
index 0000000..761cbee
--- /dev/null
+++ b/test/bitfield-integer-promotion-long.qbe
@@ -0,0 +1,6 @@
+export data $c1 = align 4 { w 1, }
+export data $c2 = align 4 { w 1, }
+export data $c3 = align 4 { w 1, }
+export data $s1 = align 8 { z 8 }
+export data $s2 = align 8 { z 8 }
+export data $s3 = align 8 { z 8 }
diff --git a/test/bitfield-integer-promotion.c b/test/bitfield-integer-promotion.c
new file mode 100644
index 0000000..e0a95f5
--- /dev/null
+++ b/test/bitfield-integer-promotion.c
@@ -0,0 +1,7 @@
+struct {
+ unsigned a : 2;
+} s;
+
+int main(void) {
+ return -1 > s.a;
+}
diff --git a/test/bitfield-integer-promotion.qbe b/test/bitfield-integer-promotion.qbe
new file mode 100644
index 0000000..dd3bf63
--- /dev/null
+++ b/test/bitfield-integer-promotion.qbe
@@ -0,0 +1,17 @@
+export
+function w $main() {
+@start.1
+@body.2
+ %.1 =w sub 0, 1
+ %.2 =l copy $s
+ %.3 =l mul 0, 1
+ %.4 =l add %.2, %.3
+ %.5 =l copy %.4
+ %.6 =w loaduw %.5
+ %.7 =w shl %.6, 30
+ %.8 =w shr %.7, 30
+ %.9 =w copy %.8
+ %.10 =w csgtw %.1, %.9
+ ret %.10
+}
+export data $s = align 4 { z 4 }
diff --git a/type.c b/type.c
index 30ca520..b05898e 100644
--- a/type.c
+++ b/type.c
@@ -149,7 +149,7 @@ typecompatible(struct type *t1, struct type *t2)
return false;
if (!t2->func.paraminfo) {
for (p1 = t1->func.params; p1; p1 = p1->next) {
- if (!typecompatible(p1->type, typeargpromote(p1->type)))
+ if (!typecompatible(p1->type, typepromote(p1->type, -1)))
return false;
}
return true;
@@ -157,7 +157,7 @@ typecompatible(struct type *t1, struct type *t2)
for (p1 = t1->func.params, p2 = t2->func.params; p1 && p2; p1 = p1->next, p2 = p2->next) {
if (p1->qual != p2->qual)
return false;
- tmp = t2->func.isprototype ? p2->type : typeargpromote(p2->type);
+ tmp = t2->func.isprototype ? p2->type : typepromote(p2->type, -1);
if (!typecompatible(p1->type, tmp))
return false;
}
@@ -186,23 +186,20 @@ typecomposite(struct type *t1, struct type *t2)
}
struct type *
-typeintpromote(struct type *t)
-{
- if (t->prop & PROPINT && typerank(t) <= typerank(&typeint))
- return t->size < typeint.size || t->basic.issigned ? &typeint : &typeuint;
- return t;
-}
-
-struct type *
-typeargpromote(struct type *t)
+typepromote(struct type *t, unsigned width)
{
if (t == &typefloat)
return &typedouble;
- return typeintpromote(t);
+ if (t->prop & PROPINT && (typerank(t) <= typerank(&typeint) || width <= typeint.size * 8)) {
+ if (width == -1)
+ width = t->size * 8;
+ return width - t->basic.issigned < typeint.size * 8 ? &typeint : &typeuint;
+ }
+ return t;
}
struct type *
-typecommonreal(struct type *t1, struct type *t2)
+typecommonreal(struct type *t1, unsigned w1, struct type *t2, unsigned w2)
{
struct type *tmp;
@@ -215,8 +212,8 @@ typecommonreal(struct type *t1, struct type *t2)
return &typedouble;
if (t1 == &typefloat || t2 == &typefloat)
return &typefloat;
- t1 = typeintpromote(t1);
- t2 = typeintpromote(t2);
+ t1 = typepromote(t1, w1);
+ t2 = typepromote(t2, w2);
if (t1 == t2)
return t1;
if (t1->basic.issigned == t2->basic.issigned)