summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-04-27 12:22:57 -0700
committerQuentin Carbonneaux <quentin@c9x.me>2019-04-29 11:04:34 +0200
commit0384d73e8daa5c948fb08c7301144c0d7e740ef9 (patch)
treed79f696c8c91e9bcc60883b86a270bfb25b20263
parente2bc0ad3960769ba7a0f1223ac160b0d985fff35 (diff)
downloadroux-0384d73e8daa5c948fb08c7301144c0d7e740ef9.tar.gz
fold: Make sure 32-bit constants get sign extended when necessary
-rw-r--r--fold.c6
-rw-r--r--test/fold1.ssa25
2 files changed, 28 insertions, 3 deletions
diff --git a/fold.c b/fold.c
index 019b739..521c911 100644
--- a/fold.c
+++ b/fold.c
@@ -371,15 +371,15 @@ foldint(Con *res, int op, int w, Con *cl, Con *cr)
 	switch (op) {
 	case Oadd:  x = l.u + r.u; break;
 	case Osub:  x = l.u - r.u; break;
-	case Odiv:  x = l.s / r.s; break;
-	case Orem:  x = l.s % r.s; 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 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 = l.s >> (r.u & 63); 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 Oshl:  x = l.u << (r.u & 63); break;
 	case Oextsb: x = (int8_t)l.u;   break;
diff --git a/test/fold1.ssa b/test/fold1.ssa
new file mode 100644
index 0000000..0ee2f91
--- /dev/null
+++ b/test/fold1.ssa
@@ -0,0 +1,25 @@
+export
+function w $f1() {
+@start
+	%x =w sar 2147483648, 31
+	ret %x
+}
+
+export
+function w $f2() {
+@start
+	%x =w div 4294967040, 8  # -256 / 8
+	ret %x
+}
+
+export
+function w $f3() {
+@start
+	%x =w rem 4294967284, 7  # -12 % 7
+	ret %x
+}
+
+# >>> driver
+# extern int f1(), f2(), f3();
+# int main() { return !(f1() == -1 && f2() == -32 && f3() == -5); }
+# <<<