commit 660a8d9dfa44050897b2f5ead823554893d79f24
parent 0384d73e8daa5c948fb08c7301144c0d7e740ef9
Author: Quentin Carbonneaux <quentin@c9x.me>
Date: Mon, 29 Apr 2019 11:29:22 +0200
fix folding of unsigned operations
This fixes similar bugs than the ones fixed
in the previous commit.
In the folding code the invariant is that
when a result is 32 bits wide, the low 32
bits of 'x' are correct. The high bits
can be anything.
Diffstat:
2 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/fold.c b/fold.c
@@ -373,14 +373,14 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr)
case Osub: x = l.u - r.u; break;
case Odiv: x = w ? l.s / r.s : (int32_t)l.s / (int32_t)r.s; break;
case Orem: x = w ? l.s % r.s : (int32_t)l.s % (int32_t)r.s; break;
- case Oudiv: x = l.u / r.u; break;
- case Ourem: x = l.u % r.u; break;
+ case Oudiv: x = w ? l.u / r.u : (uint32_t)l.u / (uint32_t)r.u; break;
+ case Ourem: x = w ? l.u % r.u : (uint32_t)l.u % (uint32_t)r.u; break;
case Omul: x = l.u * r.u; break;
case Oand: x = l.u & r.u; break;
case Oor: x = l.u | r.u; break;
case Oxor: x = l.u ^ r.u; break;
case Osar: x = (w ? l.s : (int32_t)l.s) >> (r.u & 63); break;
- case Oshr: x = l.u >> (r.u & 63); break;
+ case Oshr: x = (w ? l.u : (uint32_t)l.u) >> (r.u & 63); break;
case Oshl: x = l.u << (r.u & 63); break;
case Oextsb: x = (int8_t)l.u; break;
case Oextub: x = (uint8_t)l.u; break;
diff --git a/test/fold1.ssa b/test/fold1.ssa
@@ -19,7 +19,29 @@ function w $f3() {
ret %x
}
+export
+function w $f4() {
+@start
+ %x =w shr 4294967296, 1 # 2^32 >> 1
+ ret %x
+}
+
+export
+function w $f5() {
+@start
+ %x =w udiv 1, 4294967297 # 1 / (2^32 + 1)
+ ret %x
+}
+
+export
+function w $f6() {
+@start
+ %x =w urem 4294967296, 7 # 2^32 % 7
+ ret %x
+}
+
# >>> driver
-# extern int f1(), f2(), f3();
-# int main() { return !(f1() == -1 && f2() == -32 && f3() == -5); }
+# extern int f1(), f2(), f3(), f4(), f5(), f6();
+# int main() { return !(f1() == -1 && f2() == -32 && f3() == -5 &&
+# f4() == 0 && f5() == 1 && f6() == 0); }
# <<<