diff options
Diffstat (limited to 'src/wasm/wasm-s-parser.cpp')
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 3874bd2c0..87a6e7abd 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -1456,6 +1456,211 @@ Expression* SExpressionWasmBuilder::makeThenOrElse(Element& s) { return ret; } +static Expression* +parseConst(cashew::IString s, Type type, MixedArena& allocator) { + const char* str = s.str; + auto ret = allocator.alloc<Const>(); + ret->type = type; + if (type.isFloat()) { + if (s == _INFINITY) { + switch (type.getBasic()) { + case Type::f32: + ret->value = Literal(std::numeric_limits<float>::infinity()); + break; + case Type::f64: + ret->value = Literal(std::numeric_limits<double>::infinity()); + break; + default: + return nullptr; + } + // std::cerr << "make constant " << str << " ==> " << ret->value << '\n'; + return ret; + } + if (s == NEG_INFINITY) { + switch (type.getBasic()) { + case Type::f32: + ret->value = Literal(-std::numeric_limits<float>::infinity()); + break; + case Type::f64: + ret->value = Literal(-std::numeric_limits<double>::infinity()); + break; + default: + return nullptr; + } + // std::cerr << "make constant " << str << " ==> " << ret->value << '\n'; + return ret; + } + if (s == _NAN) { + switch (type.getBasic()) { + case Type::f32: + ret->value = Literal(float(std::nan(""))); + break; + case Type::f64: + ret->value = Literal(double(std::nan(""))); + break; + default: + return nullptr; + } + // std::cerr << "make constant " << str << " ==> " << ret->value << '\n'; + return ret; + } + bool negative = str[0] == '-'; + const char* positive = negative ? str + 1 : str; + if (!negative) { + if (positive[0] == '+') { + positive++; + } + } + if (positive[0] == 'n' && positive[1] == 'a' && positive[2] == 'n') { + const char* modifier = positive[3] == ':' ? positive + 4 : nullptr; + if (!(modifier ? positive[4] == '0' && positive[5] == 'x' : 1)) { + throw ParseException("bad nan input"); + } + switch (type.getBasic()) { + case Type::f32: { + uint32_t pattern; + if (modifier) { + std::istringstream istr(modifier); + istr >> std::hex >> pattern; + if (istr.fail()) { + throw ParseException("invalid f32 format"); + } + pattern |= 0x7f800000U; + } else { + pattern = 0x7fc00000U; + } + if (negative) { + pattern |= 0x80000000U; + } + if (!std::isnan(bit_cast<float>(pattern))) { + pattern |= 1U; + } + ret->value = Literal(pattern).castToF32(); + break; + } + case Type::f64: { + uint64_t pattern; + if (modifier) { + std::istringstream istr(modifier); + istr >> std::hex >> pattern; + if (istr.fail()) { + throw ParseException("invalid f64 format"); + } + pattern |= 0x7ff0000000000000ULL; + } else { + pattern = 0x7ff8000000000000UL; + } + if (negative) { + pattern |= 0x8000000000000000ULL; + } + if (!std::isnan(bit_cast<double>(pattern))) { + pattern |= 1ULL; + } + ret->value = Literal(pattern).castToF64(); + break; + } + default: + return nullptr; + } + // std::cerr << "make constant " << str << " ==> " << ret->value << '\n'; + return ret; + } + if (s == NEG_NAN) { + switch (type.getBasic()) { + case Type::f32: + ret->value = Literal(float(-std::nan(""))); + break; + case Type::f64: + ret->value = Literal(double(-std::nan(""))); + break; + default: + return nullptr; + } + // std::cerr << "make constant " << str << " ==> " << ret->value << '\n'; + return ret; + } + } + switch (type.getBasic()) { + case Type::i32: { + if ((str[0] == '0' && str[1] == 'x') || + (str[0] == '-' && str[1] == '0' && str[2] == 'x')) { + bool negative = str[0] == '-'; + if (negative) { + str++; + } + std::istringstream istr(str); + uint32_t temp; + istr >> std::hex >> temp; + if (istr.fail()) { + throw ParseException("invalid i32 format"); + } + ret->value = Literal(negative ? -temp : temp); + } else { + std::istringstream istr(str[0] == '-' ? str + 1 : str); + uint32_t temp; + istr >> temp; + if (istr.fail()) { + throw ParseException("invalid i32 format"); + } + ret->value = Literal(str[0] == '-' ? -temp : temp); + } + break; + } + case Type::i64: { + if ((str[0] == '0' && str[1] == 'x') || + (str[0] == '-' && str[1] == '0' && str[2] == 'x')) { + bool negative = str[0] == '-'; + if (negative) { + str++; + } + std::istringstream istr(str); + uint64_t temp; + istr >> std::hex >> temp; + if (istr.fail()) { + throw ParseException("invalid i64 format"); + } + ret->value = Literal(negative ? -temp : temp); + } else { + std::istringstream istr(str[0] == '-' ? str + 1 : str); + uint64_t temp; + istr >> temp; + if (istr.fail()) { + throw ParseException("invalid i64 format"); + } + ret->value = Literal(str[0] == '-' ? -temp : temp); + } + break; + } + case Type::f32: { + char* end; + ret->value = Literal(strtof(str, &end)); + break; + } + case Type::f64: { + char* end; + ret->value = Literal(strtod(str, &end)); + break; + } + case Type::v128: + case Type::funcref: + case Type::externref: + case Type::anyref: + case Type::eqref: + case Type::i31ref: + case Type::dataref: + WASM_UNREACHABLE("unexpected const type"); + case Type::none: + case Type::unreachable: { + return nullptr; + } + } + if (ret->value.type != type) { + throw ParseException("parsed type does not match expected type"); + } + // std::cerr << "make constant " << str << " ==> " << ret->value << '\n'; + return ret; +} + template<int Lanes> static Literal makeLanes(Element& s, MixedArena& allocator, Type lane_t) { std::array<Literal, Lanes> lanes; |