diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/parsing.h | 323 | ||||
-rw-r--r-- | src/wasm/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/wasm/parsing.cpp | 141 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 205 |
4 files changed, 356 insertions, 314 deletions
diff --git a/src/parsing.h b/src/parsing.h index a8ed8b13f..d59b3bd7c 100644 --- a/src/parsing.h +++ b/src/parsing.h @@ -22,7 +22,6 @@ #include <sstream> #include <string> -#include "ir/branch-utils.h" #include "mixed_arena.h" #include "shared-constants.h" #include "support/colors.h" @@ -41,21 +40,7 @@ struct ParseException { ParseException(std::string text, size_t line, size_t col) : text(text), line(line), col(col) {} - void dump(std::ostream& o) const { - Colors::magenta(o); - o << "["; - Colors::red(o); - o << "parse exception: "; - Colors::green(o); - o << text; - if (line != size_t(-1)) { - Colors::normal(o); - o << " (at " << line << ":" << col << ")"; - } - Colors::magenta(o); - o << "]"; - Colors::normal(o); - } + void dump(std::ostream& o) const; }; struct MapParseException { @@ -64,224 +49,9 @@ struct MapParseException { MapParseException() : text("unknown parse error") {} MapParseException(std::string text) : text(text) {} - void dump(std::ostream& o) const { - Colors::magenta(o); - o << "["; - Colors::red(o); - o << "map parse exception: "; - Colors::green(o); - o << text; - Colors::magenta(o); - o << "]"; - Colors::normal(o); - } + void dump(std::ostream& o) const; }; -inline 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; -} - // Helper for parsers that may not have unique label names. This transforms // the names into unique ones, as required by Binaryen IR. struct UniqueNameMapper { @@ -292,96 +62,21 @@ struct UniqueNameMapper { Index otherIndex = 0; - Name getPrefixedName(Name prefix) { - if (reverseLabelMapping.find(prefix) == reverseLabelMapping.end()) { - return prefix; - } - // make sure to return a unique name not already on the stack - while (1) { - Name ret = Name(prefix.str + std::to_string(otherIndex++)); - if (reverseLabelMapping.find(ret) == reverseLabelMapping.end()) { - return ret; - } - } - } + Name getPrefixedName(Name prefix); // receives a source name. generates a unique name, pushes it, and returns it - Name pushLabelName(Name sName) { - Name name = getPrefixedName(sName); - labelStack.push_back(name); - labelMappings[sName].push_back(name); - reverseLabelMapping[name] = sName; - return name; - } + Name pushLabelName(Name sName); - void popLabelName(Name name) { - assert(labelStack.back() == name); - labelStack.pop_back(); - labelMappings[reverseLabelMapping[name]].pop_back(); - } + void popLabelName(Name name); - Name sourceToUnique(Name sName) { - // DELEGATE_CALLER_TARGET is a fake target used to denote delegating to the - // caller. We do not need to modify it, as it has no definitions, only uses. - if (sName == DELEGATE_CALLER_TARGET) { - return DELEGATE_CALLER_TARGET; - } - if (labelMappings.find(sName) == labelMappings.end()) { - throw ParseException("bad label in sourceToUnique"); - } - if (labelMappings[sName].empty()) { - throw ParseException("use of popped label in sourceToUnique"); - } - return labelMappings[sName].back(); - } + Name sourceToUnique(Name sName); - Name uniqueToSource(Name name) { - if (reverseLabelMapping.find(name) == reverseLabelMapping.end()) { - throw ParseException("label mismatch in uniqueToSource"); - } - return reverseLabelMapping[name]; - } + Name uniqueToSource(Name name); - void clear() { - labelStack.clear(); - labelMappings.clear(); - reverseLabelMapping.clear(); - } + void clear(); // Given an expression, ensures all names are unique - static void uniquify(Expression* curr) { - struct Walker - : public ControlFlowWalker<Walker, UnifiedExpressionVisitor<Walker>> { - UniqueNameMapper mapper; - - static void doPreVisitControlFlow(Walker* self, Expression** currp) { - BranchUtils::operateOnScopeNameDefs(*currp, [&](Name& name) { - if (name.is()) { - name = self->mapper.pushLabelName(name); - } - }); - } - - static void doPostVisitControlFlow(Walker* self, Expression** currp) { - BranchUtils::operateOnScopeNameDefs(*currp, [&](Name& name) { - if (name.is()) { - self->mapper.popLabelName(name); - } - }); - } - - void visitExpression(Expression* curr) { - BranchUtils::operateOnScopeNameUses(curr, [&](Name& name) { - if (name.is()) { - name = mapper.sourceToUnique(name); - } - }); - } - }; - - Walker walker; - walker.walk(curr); - } + static void uniquify(Expression* curr); }; } // namespace wasm diff --git a/src/wasm/CMakeLists.txt b/src/wasm/CMakeLists.txt index d24618c63..5547e0741 100644 --- a/src/wasm/CMakeLists.txt +++ b/src/wasm/CMakeLists.txt @@ -1,6 +1,7 @@ file(GLOB wasm_HEADERS ../*.h) set(wasm_SOURCES literal.cpp + parsing.cpp wasm.cpp wasm-binary.cpp wasm-debug.cpp diff --git a/src/wasm/parsing.cpp b/src/wasm/parsing.cpp new file mode 100644 index 000000000..dc0d332d9 --- /dev/null +++ b/src/wasm/parsing.cpp @@ -0,0 +1,141 @@ +/* + * Copyright 2021 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "parsing.h" +#include "ir/branch-utils.h" + +namespace wasm { + +void ParseException::dump(std::ostream& o) const { + Colors::magenta(o); + o << "["; + Colors::red(o); + o << "parse exception: "; + Colors::green(o); + o << text; + if (line != size_t(-1)) { + Colors::normal(o); + o << " (at " << line << ":" << col << ")"; + } + Colors::magenta(o); + o << "]"; + Colors::normal(o); +} + +void MapParseException::dump(std::ostream& o) const { + Colors::magenta(o); + o << "["; + Colors::red(o); + o << "map parse exception: "; + Colors::green(o); + o << text; + Colors::magenta(o); + o << "]"; + Colors::normal(o); +} + +// UniqueNameMapper + +Name UniqueNameMapper::getPrefixedName(Name prefix) { + if (reverseLabelMapping.find(prefix) == reverseLabelMapping.end()) { + return prefix; + } + // make sure to return a unique name not already on the stack + while (1) { + Name ret = Name(prefix.str + std::to_string(otherIndex++)); + if (reverseLabelMapping.find(ret) == reverseLabelMapping.end()) { + return ret; + } + } +} + +Name UniqueNameMapper::pushLabelName(Name sName) { + Name name = getPrefixedName(sName); + labelStack.push_back(name); + labelMappings[sName].push_back(name); + reverseLabelMapping[name] = sName; + return name; +} + +void UniqueNameMapper::popLabelName(Name name) { + assert(labelStack.back() == name); + labelStack.pop_back(); + labelMappings[reverseLabelMapping[name]].pop_back(); +} + +Name UniqueNameMapper::sourceToUnique(Name sName) { + // DELEGATE_CALLER_TARGET is a fake target used to denote delegating to the + // caller. We do not need to modify it, as it has no definitions, only uses. + if (sName == DELEGATE_CALLER_TARGET) { + return DELEGATE_CALLER_TARGET; + } + if (labelMappings.find(sName) == labelMappings.end()) { + throw ParseException("bad label in sourceToUnique"); + } + if (labelMappings[sName].empty()) { + throw ParseException("use of popped label in sourceToUnique"); + } + return labelMappings[sName].back(); +} + +Name UniqueNameMapper::uniqueToSource(Name name) { + if (reverseLabelMapping.find(name) == reverseLabelMapping.end()) { + throw ParseException("label mismatch in uniqueToSource"); + } + return reverseLabelMapping[name]; +} + +void UniqueNameMapper::clear() { + labelStack.clear(); + labelMappings.clear(); + reverseLabelMapping.clear(); +} + +void UniqueNameMapper::uniquify(Expression* curr) { + struct Walker + : public ControlFlowWalker<Walker, UnifiedExpressionVisitor<Walker>> { + UniqueNameMapper mapper; + + static void doPreVisitControlFlow(Walker* self, Expression** currp) { + BranchUtils::operateOnScopeNameDefs(*currp, [&](Name& name) { + if (name.is()) { + name = self->mapper.pushLabelName(name); + } + }); + } + + static void doPostVisitControlFlow(Walker* self, Expression** currp) { + BranchUtils::operateOnScopeNameDefs(*currp, [&](Name& name) { + if (name.is()) { + self->mapper.popLabelName(name); + } + }); + } + + void visitExpression(Expression* curr) { + BranchUtils::operateOnScopeNameUses(curr, [&](Name& name) { + if (name.is()) { + name = mapper.sourceToUnique(name); + } + }); + } + }; + + Walker walker; + walker.walk(curr); +} + +} // namespace wasm 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; |