diff options
Diffstat (limited to 'src/wasm-interpreter.h')
-rw-r--r-- | src/wasm-interpreter.h | 323 |
1 files changed, 107 insertions, 216 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 88b87d88f..59e42783d 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -378,71 +378,61 @@ private: Literal value = flow.value; NOTE_EVAL1(value); if (value.type == i32) { - int32_t v = value.geti32(); switch (curr->op) { - case Clz: return Literal((int32_t)CountLeadingZeroes(v)); - case Ctz: return Literal((int32_t)CountTrailingZeroes(v)); - case Popcnt: return Literal((int32_t)PopCount(v)); + case Clz: return value.countLeadingZeroes(); + case Ctz: return value.countTrailingZeroes(); + case Popcnt: return value.popCount(); case ReinterpretInt: return value.castToF32(); - case ExtendSInt32: return Literal(int64_t(value.geti32())); - case ExtendUInt32: return Literal(uint64_t((uint32_t)value.geti32())); - case ConvertUInt32: return curr->type == f32 ? Literal(float(uint32_t(value.geti32()))) : Literal(double(uint32_t(value.geti32()))); - case ConvertSInt32: return curr->type == f32 ? Literal(float(int32_t(value.geti32()))) : Literal(double(int32_t(value.geti32()))); + case ExtendSInt32: return value.extendToSI64(); + case ExtendUInt32: return value.extendToUI64(); + case ConvertUInt32: return curr->type == f32 ? value.convertUToF32() : value.convertUToF64(); + case ConvertSInt32: return curr->type == f32 ? value.convertSToF32() : value.convertSToF64(); default: abort(); } } if (value.type == i64) { - int64_t v = value.geti64(); switch (curr->op) { - case Clz: return Literal((int64_t)CountLeadingZeroes(v)); - case Ctz: return Literal((int64_t)CountTrailingZeroes(v)); - case Popcnt: return Literal((int64_t)PopCount(v)); - case WrapInt64: return Literal(int32_t(value.geti64())); + case Clz: return value.countLeadingZeroes(); + case Ctz: return value.countTrailingZeroes(); + case Popcnt: return value.popCount(); + case WrapInt64: return value.truncateToI32(); case ReinterpretInt: return value.castToF64(); - case ConvertUInt64: return curr->type == f32 ? Literal(float((uint64_t)value.geti64())) : Literal(double((uint64_t)value.geti64())); - case ConvertSInt64: return curr->type == f32 ? Literal(float(value.geti64())) : Literal(double(value.geti64())); + case ConvertUInt64: return curr->type == f32 ? value.convertUToF32() : value.convertUToF64(); + case ConvertSInt64: return curr->type == f32 ? value.convertSToF32() : value.convertSToF64(); default: abort(); } } if (value.type == f32) { - float v = value.getf32(); - float ret; switch (curr->op) { - // operate on bits directly, to avoid signalling bit being set on a float - case Neg: return Literal(value.reinterpreti32() ^ 0x80000000).castToF32(); break; - case Abs: return Literal(value.reinterpreti32() & 0x7fffffff).castToF32(); break; - case Ceil: ret = std::ceil(v); break; - case Floor: ret = std::floor(v); break; - case Trunc: ret = std::trunc(v); break; - case Nearest: ret = std::nearbyint(v); break; - case Sqrt: ret = std::sqrt(v); break; + case Neg: return value.neg(); + case Abs: return value.abs(); + case Ceil: return value.ceil(); + case Floor: return value.floor(); + case Trunc: return value.trunc(); + case Nearest: return value.nearbyint(); + case Sqrt: return value.sqrt(); case TruncSFloat32: return truncSFloat(curr, value); case TruncUFloat32: return truncUFloat(curr, value); - case ReinterpretFloat: return Literal(value.reinterpreti32()); - case PromoteFloat32: return Literal(double(value.getf32())); + case ReinterpretFloat: return value.castToI32(); + case PromoteFloat32: return value.extendToF64(); default: abort(); } - return Literal(fixNaN(v, ret)); } if (value.type == f64) { - double v = value.getf64(); - double ret; switch (curr->op) { - // operate on bits directly, to avoid signalling bit being set on a float - case Neg: return Literal(uint64_t((value.reinterpreti64() ^ 0x8000000000000000ULL))).castToF64(); break; - case Abs: return Literal(uint64_t(value.reinterpreti64() & 0x7fffffffffffffffULL)).castToF64(); break; - case Ceil: ret = std::ceil(v); break; - case Floor: ret = std::floor(v); break; - case Trunc: ret = std::trunc(v); break; - case Nearest: ret = std::nearbyint(v); break; - case Sqrt: ret = std::sqrt(v); break; + case Neg: return value.neg(); + case Abs: return value.abs(); + case Ceil: return value.ceil(); + case Floor: return value.floor(); + case Trunc: return value.trunc(); + case Nearest: return value.nearbyint(); + case Sqrt: return value.sqrt(); case TruncSFloat64: return truncSFloat(curr, value); case TruncUFloat64: return truncUFloat(curr, value); - case ReinterpretFloat: return Literal(value.reinterpreti64()); - case DemoteFloat64: return Literal(float(value.getf64())); + case ReinterpretFloat: return value.castToI64(); + case DemoteFloat64: return value.truncateToF32(); default: abort(); } - return Literal(fixNaN(v, ret)); } abort(); } @@ -458,167 +448,104 @@ private: assert(left.type == curr->left->type); assert(right.type == curr->right->type); if (left.type == i32) { - 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 Add: return left.add(right); + case Sub: return left.sub(right); + case Mul: return left.mul(right); case DivS: { - 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); + if (right.getInteger() == 0) trap("i32.div_s by 0"); + if (left.getInteger() == std::numeric_limits<int32_t>::min() && right.getInteger() == -1) trap("i32.div_s overflow"); // signed division overflow + return left.divS(right); } case DivU: { - if (r == 0) trap("i32.div_u by 0"); - return Literal(l / r); + if (right.getInteger() == 0) trap("i32.div_u by 0"); + return left.divU(right); } case RemS: { - 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); + if (right.getInteger() == 0) trap("i32.rem_s by 0"); + if (left.getInteger() == std::numeric_limits<int32_t>::min() && right.getInteger() == -1) return Literal(int32_t(0)); + return left.remS(right); } case RemU: { - if (r == 0) trap("i32.rem_u by 0"); - return Literal(l % r); + if (right.getInteger() == 0) trap("i32.rem_u by 0"); + return left.remU(right); } - case And: return Literal(l & r); - case Or: return Literal(l | r); - case Xor: return Literal(l ^ r); - case Shl: { - r = r & 31; - return Literal(l << r); - } - case ShrU: { - r = r & 31; - return Literal(l >> r); - } - case ShrS: { - 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_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); + case And: return left.and_(right); + case Or: return left.or_(right); + case Xor: return left.xor_(right); + case Shl: return left.shl(right.and_(Literal(int32_t(31)))); + case ShrU: return left.shrU(right.and_(Literal(int32_t(31)))); + case ShrS: return left.shrS(right.and_(Literal(int32_t(31)))); + case Eq: return left.eq(right); + case Ne: return left.ne(right); + case LtS: return left.ltS(right); + case LtU: return left.ltU(right); + case LeS: return left.leS(right); + case LeU: return left.leU(right); + case GtS: return left.gtS(right); + case GtU: return left.gtU(right); + case GeS: return left.geS(right); + case GeU: return left.geU(right); default: abort(); } } else if (left.type == i64) { - 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 Add: return left.add(right); + case Sub: return left.sub(right); + case Mul: return left.mul(right); case DivS: { - 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); + if (right.getInteger() == 0) trap("i64.div_s by 0"); + if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL) trap("i64.div_s overflow"); // signed division overflow + return left.divS(right); } case DivU: { - if (r == 0) trap("i64.div_u by 0"); - return Literal(l / r); + if (right.getInteger() == 0) trap("i64.div_u by 0"); + return left.divU(right); } case RemS: { - 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); + if (right.getInteger() == 0) trap("i64.rem_s by 0"); + if (left.getInteger() == LLONG_MIN && right.getInteger() == -1LL) return Literal(int64_t(0)); + return left.remS(right); } case RemU: { - if (r == 0) trap("i64.rem_u by 0"); - return Literal(l % r); - } - case And: return Literal(l & r); - case Or: return Literal(l | r); - case Xor: return Literal(l ^ r); - case Shl: { - r = r & 63; - return Literal(l << r); + if (right.getInteger() == 0) trap("i64.rem_u by 0"); + return left.remU(right); } - case ShrU: { - r = r & 63; - return Literal(l >> r); - } - case ShrS: { - 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_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); + case And: return left.and_(right); + case Or: return left.or_(right); + case Xor: return left.xor_(right); + case Shl: return left.shl(right.and_(Literal(int64_t(63)))); + case ShrU: return left.shrU(right.and_(Literal(int64_t(63)))); + case ShrS: return left.shrS(right.and_(Literal(int64_t(63)))); + case Eq: return left.eq(right); + case Ne: return left.ne(right); + case LtS: return left.ltS(right); + case LtU: return left.ltU(right); + case LeS: return left.leS(right); + case LeU: return left.leU(right); + case GtS: return left.gtS(right); + case GtU: return left.gtU(right); + case GeS: return left.geS(right); + case GeU: return left.geU(right); default: abort(); } - } else if (left.type == f32) { - float l = left.getf32(), r = right.getf32(); - float ret; + } else if (left.type == f32 || left.type == f64) { switch (curr->op) { - case Add: ret = l + r; break; - case Sub: ret = l - r; break; - case Mul: ret = l * r; break; - case Div: ret = l / r; break; - // operate on bits directly, to avoid signalling bit being set on a float - case CopySign: return Literal((left.reinterpreti32() & 0x7fffffff) | (right.reinterpreti32() & 0x80000000)).castToF32(); break; - case Min: { - if (l == r && l == 0) ret = 1/l < 0 ? l : r; - else ret = std::min(l, r); - break; - } - case Max: { - if (l == r && l == 0) ret = 1/l < 0 ? r : l; - else ret = std::max(l, r); - break; - } - case Eq: return Literal(l == r); - case Ne: return Literal(l != r); - case Lt: return Literal(l < r); - case Le: return Literal(l <= r); - case Gt: return Literal(l > r); - case Ge: return Literal(l >= r); - default: abort(); - } - return Literal(fixNaN(l, r, ret)); - } else if (left.type == f64) { - double l = left.getf64(), r = right.getf64(); - double ret; - switch (curr->op) { - case Add: ret = l + r; break; - case Sub: ret = l - r; break; - case Mul: ret = l * r; break; - case Div: ret = l / r; break; - // operate on bits directly, to avoid signalling bit being set on a float - case CopySign: return Literal((left.reinterpreti64() & 0x7fffffffffffffffUL) | (right.reinterpreti64() & 0x8000000000000000UL)).castToF64(); break; - case Min: { - if (l == r && l == 0) ret = 1/l < 0 ? l : r; - else ret = std::min(l, r); - break; - } - case Max: { - if (l == r && l == 0) ret = 1/l < 0 ? r : l; - else ret = std::max(l, r); - break; - } - case Eq: return Literal(l == r); - case Ne: return Literal(l != r); - case Lt: return Literal(l < r); - case Le: return Literal(l <= r); - case Gt: return Literal(l > r); - case Ge: return Literal(l >= r); + case Add: return left.add(right); + case Sub: return left.sub(right); + case Mul: return left.mul(right); + case Div: return left.div(right); + case CopySign: return left.copysign(right); + case Min: return left.min(right); + case Max: return left.max(right); + case Eq: return left.eq(right); + case Ne: return left.ne(right); + case Lt: return left.lt(right); + case Le: return left.le(right); + case Gt: return left.gt(right); + case Ge: return left.ge(right); default: abort(); } - return Literal(fixNaN(l, r, ret)); } abort(); } @@ -680,47 +607,11 @@ private: return Flow(); } - float fixNaN(float u, float result) { - if (!isnan(result)) return result; - bool unan = isnan(u); - if (!unan) { - return Literal((int32_t)0x7fc00000).reinterpretf32(); - } - return result; - } - - double fixNaN(double u, double result) { - if (!isnan(result)) return result; - bool unan = isnan(u); - if (!unan) { - return Literal((int64_t)0x7ff8000000000000LL).reinterpretf64(); - } - return result; - } - - float fixNaN(float l, float r, float result) { - bool lnan = isnan(l), rnan = isnan(r); - if (!isnan(result) && !lnan && !rnan) return result; - if (!lnan && !rnan) { - return Literal((int32_t)0x7fc00000).reinterpretf32(); - } - return Literal(Literal(lnan ? l : r).reinterpreti32() | 0xc00000).reinterpretf32(); - } - - double fixNaN(double l, double r, double result) { - bool lnan = isnan(l), rnan = isnan(r); - if (!isnan(result) && !lnan && !rnan) return result; - if (!lnan && !rnan) { - return Literal((int64_t)0x7ff8000000000000LL).reinterpretf64(); - } - return Literal(int64_t(Literal(lnan ? l : r).reinterpreti64() | 0x8000000000000LL)).reinterpretf64(); - } - Literal truncSFloat(Unary* curr, Literal value) { - double val = curr->op == TruncSFloat32 ? value.getf32() : value.getf64(); + double val = value.getFloat(); if (isnan(val)) trap("truncSFloat of nan"); if (curr->type == i32) { - if (val > (double)INT_MAX || val < (double)INT_MIN) trap("i32.truncSFloat overflow"); + if (val > (double)std::numeric_limits<int32_t>::max() || val < (double)std::numeric_limits<int32_t>::min()) trap("i32.truncSFloat overflow"); return Literal(int32_t(val)); } else { int64_t converted = val; @@ -730,10 +621,10 @@ private: } Literal truncUFloat(Unary* curr, Literal value) { - double val = curr->op == TruncUFloat32 ? value.getf32() : value.getf64(); + double val = value.getFloat(); if (isnan(val)) trap("truncUFloat of nan"); if (curr->type == i32) { - if (val > (double)UINT_MAX || val <= (double)-1) trap("i64.truncUFloat overflow"); + if (val > (double)std::numeric_limits<uint32_t>::max() || val <= (double)-1) trap("i64.truncUFloat overflow"); return Literal(uint32_t(val)); } else { uint64_t converted = val; |