diff options
author | Michael Forney <mforney@mforney.org> | 2019-02-16 20:47:45 -0800 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2019-02-16 20:51:11 -0800 |
commit | 7d746860bda62c2f382bc0ac82d4d6c8cdf6c7b2 (patch) | |
tree | 3b57414a9a175c04d529e43a4be672ee22c1f88d | |
parent | 18ad54b003608f3060d4baf2fef00a8a2b6f0a7b (diff) |
Extend char/short types before comparing
Thanks to Andrew Chambers for reporting the issue.
-rw-r--r-- | qbe.c | 26 | ||||
-rw-r--r-- | tests/cast-bool-char.c | 3 | ||||
-rw-r--r-- | tests/cast-bool-char.qbe | 10 | ||||
-rw-r--r-- | tests/compare-char.c | 3 | ||||
-rw-r--r-- | tests/compare-char.qbe | 11 |
5 files changed, 53 insertions, 0 deletions
@@ -527,6 +527,19 @@ ftou(struct function *f, struct representation *r, struct value *v) return funcinst(f, IPHI, r, phi); } +static struct value * +extend(struct function *f, struct type *t, struct value *v) +{ + enum instructionkind op; + + switch (t->size) { + case 1: op = t->basic.issigned ? IEXTSB : IEXTUB; break; + case 2: op = t->basic.issigned ? IEXTSH : IEXTUH; break; + default: return v; + } + return funcinst(f, op, &i32, (struct value *[]){v}); +} + struct value * funcexpr(struct function *f, struct expression *e) { @@ -612,6 +625,7 @@ funcexpr(struct function *f, struct expression *e) srcprop = typeprop(src); dstprop = typeprop(dst); if (dst->basic.kind == BASICBOOL) { + l = extend(f, src, l); r = mkintconst(src->repr, 0); if (srcprop & PROPINT) op = src->size == 8 ? ICNEL : ICNEW; @@ -704,36 +718,48 @@ funcexpr(struct function *f, struct expression *e) op = IXOR; break; case TLESS: + l = extend(f, t, l); + r = extend(f, t, r); if (t->size <= 4) op = typeprop(t) & PROPFLOAT ? ICLTS : t->basic.issigned ? ICSLTW : ICULTW; else op = typeprop(t) & PROPFLOAT ? ICLTD : t->basic.issigned ? ICSLTL : ICULTL; break; case TGREATER: + l = extend(f, t, l); + r = extend(f, t, r); if (t->size <= 4) op = typeprop(t) & PROPFLOAT ? ICGTS : t->basic.issigned ? ICSGTW : ICUGTW; else op = typeprop(t) & PROPFLOAT ? ICGTD : t->basic.issigned ? ICSGTL : ICUGTL; break; case TLEQ: + l = extend(f, t, l); + r = extend(f, t, r); if (t->size <= 4) op = typeprop(t) & PROPFLOAT ? ICLES : t->basic.issigned ? ICSLEW : ICULEW; else op = typeprop(t) & PROPFLOAT ? ICLED : t->basic.issigned ? ICSLEL : ICULEL; break; case TGEQ: + l = extend(f, t, l); + r = extend(f, t, r); if (t->size <= 4) op = typeprop(t) & PROPFLOAT ? ICGES : t->basic.issigned ? ICSGEW : ICUGEW; else op = typeprop(t) & PROPFLOAT ? ICGED : t->basic.issigned ? ICSGEL : ICUGEL; break; case TEQL: + l = extend(f, t, l); + r = extend(f, t, r); if (t->size <= 4) op = typeprop(t) & PROPFLOAT ? ICEQS : ICEQW; else op = typeprop(t) & PROPFLOAT ? ICEQD : ICEQL; break; case TNEQ: + l = extend(f, t, l); + r = extend(f, t, r); if (t->size <= 4) op = typeprop(t) & PROPFLOAT ? ICNES : ICNEW; else diff --git a/tests/cast-bool-char.c b/tests/cast-bool-char.c new file mode 100644 index 0000000..d05f575 --- /dev/null +++ b/tests/cast-bool-char.c @@ -0,0 +1,3 @@ +int main(void) { + return (_Bool)(unsigned char)256; +} diff --git a/tests/cast-bool-char.qbe b/tests/cast-bool-char.qbe new file mode 100644 index 0000000..81d4eba --- /dev/null +++ b/tests/cast-bool-char.qbe @@ -0,0 +1,10 @@ +export +function w $main() { +@start.1 +@body.2 + %.1 =w copy 256 + %.2 =w extub %.1 + %.3 =w cnew %.2, 0 + %.4 =w extub %.3 + ret %.4 +} diff --git a/tests/compare-char.c b/tests/compare-char.c new file mode 100644 index 0000000..5219647 --- /dev/null +++ b/tests/compare-char.c @@ -0,0 +1,3 @@ +int main(void) { + return (unsigned char)0 < (unsigned char)256; +} diff --git a/tests/compare-char.qbe b/tests/compare-char.qbe new file mode 100644 index 0000000..a0a1c03 --- /dev/null +++ b/tests/compare-char.qbe @@ -0,0 +1,11 @@ +export +function w $main() { +@start.1 +@body.2 + %.1 =w copy 0 + %.2 =w copy 256 + %.3 =w extub %.1 + %.4 =w extub %.2 + %.5 =w cultw %.3, %.4 + ret %.5 +} |