summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDerek Schuff <dschuff@chromium.org>2016-02-03 15:01:43 -0800
committerJF Bastien <jfb@chromium.org>2016-02-04 01:07:38 -0800
commitddaca4202886f036bf525eb174a1b2fd339fa42c (patch)
treee8e1ae4e143e046849457e5068a4964c40a085d3 /src
parent26d5aa903a1f5908e26e63095fd92749e1bc9544 (diff)
downloadbinaryen-ddaca4202886f036bf525eb174a1b2fd339fa42c.tar.gz
binaryen-ddaca4202886f036bf525eb174a1b2fd339fa42c.tar.bz2
binaryen-ddaca4202886f036bf525eb174a1b2fd339fa42c.zip
Use unsigned types to evaluate i32 and i64 binary operators
Instead of defaulting to signed types and casting as necessary, use unsigned types. Explicitly make signed copies of them and us them where appropriate, avoiding lots of casting and improving readability. Avoids undefined behavior of signed overflow.
Diffstat (limited to 'src')
-rw-r--r--src/wasm-interpreter.h82
1 files changed, 42 insertions, 40 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 1f3e93d60..022dd04bc 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -454,28 +454,29 @@ private:
assert(left.type == curr->left->type);
assert(right.type == curr->right->type);
if (left.type == i32) {
- int32_t l = left.geti32(), r = right.geti32();
+ uint32_t l = left.geti32(), r = right.geti32();
+ int32_t l_signed = l, r_signed = r;
switch (curr->op) {
case Add: return Literal(l + r);
case Sub: return Literal(l - r);
case Mul: return Literal(l * r);
case DivS: {
- if (r == 0) trap("i32.div_s by 0");
- if (l == INT32_MIN && r == -1) trap("i32.div_s overflow"); // signed division overflow
- return Literal(l / r);
+ if (r_signed == 0) trap("i32.div_s by 0");
+ if (l_signed == INT32_MIN && r_signed == -1) trap("i32.div_s overflow"); // signed division overflow
+ return Literal(l_signed / r_signed);
}
case DivU: {
if (r == 0) trap("i32.div_u by 0");
- return Literal(int32_t(uint32_t(l) / uint32_t(r)));
+ return Literal(l / r);
}
case RemS: {
- if (r == 0) trap("i32.rem_s by 0");
- if (l == INT32_MIN && r == -1) return Literal(int32_t(0));
- return Literal(l % r);
+ if (r_signed == 0) trap("i32.rem_s by 0");
+ if (l_signed == INT32_MIN && r_signed == -1) return Literal(int32_t(0));
+ return Literal(l_signed % r_signed);
}
case RemU: {
if (r == 0) trap("i32.rem_u by 0");
- return Literal(int32_t(uint32_t(l) % uint32_t(r)));
+ return Literal(l % r);
}
case And: return Literal(l & r);
case Or: return Literal(l | r);
@@ -486,47 +487,48 @@ private:
}
case ShrU: {
r = r & 31;
- return Literal(int32_t(uint32_t(l) >> uint32_t(r)));
+ return Literal(l >> r);
}
case ShrS: {
- r = r & 31;
- return Literal(l >> r);
+ r_signed = r_signed & 31;
+ return Literal(l_signed >> r_signed);
}
case Eq: return Literal(l == r);
case Ne: return Literal(l != r);
- case LtS: return Literal(l < r);
- case LtU: return Literal(uint32_t(l) < uint32_t(r));
- case LeS: return Literal(l <= r);
- case LeU: return Literal(uint32_t(l) <= uint32_t(r));
- case GtS: return Literal(l > r);
- case GtU: return Literal(uint32_t(l) > uint32_t(r));
- case GeS: return Literal(l >= r);
- case GeU: return Literal(uint32_t(l) >= uint32_t(r));
+ case LtS: return Literal(l_signed < r_signed);
+ case LtU: return Literal(l < r);
+ case LeS: return Literal(l_signed <= r_signed);
+ case LeU: return Literal(l <= r);
+ case GtS: return Literal(l_signed > r_signed);
+ case GtU: return Literal(l > r);
+ case GeS: return Literal(l_signed >= r_signed);
+ case GeU: return Literal(l >= r);
default: abort();
}
} else if (left.type == i64) {
- int64_t l = left.geti64(), r = right.geti64();
+ uint64_t l = left.geti64(), r = right.geti64();
+ int64_t l_signed = l, r_signed = r;
switch (curr->op) {
case Add: return Literal(l + r);
case Sub: return Literal(l - r);
case Mul: return Literal(l * r);
case DivS: {
- if (r == 0) trap("i64.div_s by 0");
- if (l == LLONG_MIN && r == -1) trap("i64.div_s overflow"); // signed division overflow
- return Literal(l / r);
+ if (r_signed == 0) trap("i64.div_s by 0");
+ if (l_signed == LLONG_MIN && r_signed == -1LL) trap("i64.div_s overflow"); // signed division overflow
+ return Literal(l_signed / r_signed);
}
case DivU: {
if (r == 0) trap("i64.div_u by 0");
- return Literal(int64_t(uint64_t(l) / uint64_t(r)));
+ return Literal(l / r);
}
case RemS: {
- if (r == 0) trap("i64.rem_s by 0");
- if (l == LLONG_MIN && r == -1) return Literal(int64_t(0));
- return Literal(l % r);
+ if (r_signed == 0) trap("i64.rem_s by 0");
+ if (l_signed == LLONG_MIN && r_signed == -1LL) return Literal(int64_t(0));
+ return Literal(l_signed % r_signed);
}
case RemU: {
if (r == 0) trap("i64.rem_u by 0");
- return Literal(int64_t(uint64_t(l) % uint64_t(r)));
+ return Literal(l % r);
}
case And: return Literal(l & r);
case Or: return Literal(l | r);
@@ -537,22 +539,22 @@ private:
}
case ShrU: {
r = r & 63;
- return Literal(int64_t(uint64_t(l) >> uint64_t(r)));
+ return Literal(l >> r);
}
case ShrS: {
- r = r & 63;
- return Literal(l >> r);
+ r_signed = r_signed & 63;
+ return Literal(l_signed >> r_signed);
}
case Eq: return Literal(l == r);
case Ne: return Literal(l != r);
- case LtS: return Literal(l < r);
- case LtU: return Literal(uint64_t(l) < uint64_t(r));
- case LeS: return Literal(l <= r);
- case LeU: return Literal(uint64_t(l) <= uint64_t(r));
- case GtS: return Literal(l > r);
- case GtU: return Literal(uint64_t(l) > uint64_t(r));
- case GeS: return Literal(l >= r);
- case GeU: return Literal(uint64_t(l) >= uint64_t(r));
+ case LtS: return Literal(l_signed < r_signed);
+ case LtU: return Literal(l < r);
+ case LeS: return Literal(l_signed <= r_signed);
+ case LeU: return Literal(l <= r);
+ case GtS: return Literal(l_signed > r_signed);
+ case GtU: return Literal(l > r);
+ case GeS: return Literal(l_signed >= r_signed);
+ case GeU: return Literal(l >= r);
default: abort();
}
} else if (left.type == f32) {