| #!/usr/bin/env python3 |
| |
| # Copyright (C) 2016 Apple Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions |
| # are met:n |
| # |
| # 1. Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # 2. Redistributions in binary form must reproduce the above copyright |
| # notice, this list of conditions and the following disclaimer in the |
| # documentation and/or other materials provided with the distribution. |
| # |
| # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| # This tool has a couple of helpful macros to process Wasm files from the wasm.json. |
| |
| from generateWasm import * |
| import optparse |
| import sys |
| import re |
| |
| parser = optparse.OptionParser(usage="usage: %prog <wasm.json> <WasmOps.h>") |
| (options, args) = parser.parse_args(sys.argv[0:]) |
| if len(args) != 3: |
| parser.error(parser.usage) |
| |
| wasm = Wasm(args[0], args[1]) |
| opcodes = wasm.opcodes |
| wasmB3IRGeneratorHFile = open(args[2], "w") |
| |
| opcodeRegex = re.compile('([a-zA-Z0-9]+)') |
| argumentRegex = re.compile(r'(\@[0-9]+)') |
| decimalRegex = re.compile('([-]?[0-9]+)') |
| whitespaceRegex = re.compile(r'\s+') |
| commaRegex = re.compile('(,)') |
| oparenRegex = re.compile(r'(\()') |
| cparenRegex = re.compile(r'(\))') |
| |
| |
| class Source: |
| def __init__(self, contents, offset=0): |
| self.contents = contents |
| self.offset = offset |
| |
| |
| def read(regex, source): |
| match = regex.match(source.contents, source.offset) |
| if not match: |
| return None |
| source.offset = match.end() |
| return match.group() |
| |
| |
| def lex(source): |
| result = [] |
| while source.offset != len(source.contents): |
| read(whitespaceRegex, source) |
| opcode = read(opcodeRegex, source) |
| if opcode: |
| result.append(opcode) |
| continue |
| |
| argument = read(argumentRegex, source) |
| if argument: |
| result.append(argument) |
| continue |
| |
| number = read(decimalRegex, source) |
| if number: |
| result.append(int(number)) |
| continue |
| |
| oparen = read(oparenRegex, source) |
| if oparen: |
| result.append(oparen) |
| continue |
| |
| cparen = read(cparenRegex, source) |
| if cparen: |
| result.append(cparen) |
| continue |
| |
| comma = read(commaRegex, source) |
| if comma: |
| # Skip commas |
| continue |
| |
| raise Exception("Lexing Error: could not lex token from: " + source.contents + " at offset: " + str(source.offset) + " (" + source.contents[source.offset:] + "). With tokens: [" + ", ".join(result) + "]") |
| return result |
| |
| |
| class CodeGenerator: |
| def __init__(self, tokens): |
| self.tokens = tokens |
| self.index = 0 |
| self.code = [] |
| |
| def advance(self): |
| self.index += 1 |
| |
| def token(self): |
| return self.tokens[self.index] |
| |
| def parseError(self, string): |
| raise Exception("Parse error " + string) |
| |
| def consume(self, string): |
| if self.token() != string: |
| self.parseError("Expected " + string + " but got " + self.token()) |
| self.advance() |
| |
| def generateParameters(self): |
| self.advance() |
| params = [] |
| tokens = self.tokens |
| while self.index < len(tokens): |
| if self.token() == ")": |
| self.advance() |
| return params |
| params.append(self.generateOpcode()) |
| self.parseError("Parsing arguments fell off end") |
| |
| def generateOpcode(self): |
| result = None |
| if self.token() == "i32" or self.token() == "i64": |
| type = "Int32" |
| if self.token() == "i64": |
| type = "Int64" |
| self.advance() |
| self.consume("(") |
| self.code.append(generateConstCode(self.index, self.token(), type)) |
| result = temp(self.index) |
| self.advance() |
| self.consume(")") |
| elif argumentRegex.match(self.token()): |
| result = "get(arg" + self.token()[1:] + ")" |
| self.advance() |
| else: |
| op = self.token() |
| index = self.index |
| self.advance() |
| params = self.generateParameters() |
| self.code.append(generateB3OpCode(index, op, params)) |
| result = temp(index) |
| |
| return result |
| |
| def makeResult(self, resultValue): |
| return resultValue + ";\n" + "result = push(resultValue->type());\n" + "m_currentBlock->appendNew<VariableValue>(m_proc, Set, origin(), result, resultValue);" |
| |
| def generate(self, wasmOp): |
| if len(self.tokens) == 1: |
| params = ["get(arg" + str(param) + ")" for param in range(len(wasmOp["parameter"]))] |
| return self.makeResult(" Value* resultValue = m_currentBlock->appendNew<Value>(m_proc, B3::" + self.token() + ", origin(), " + ", ".join(params) + ")") |
| result = self.generateOpcode() |
| self.code.append("Value* resultValue = " + result) |
| return self.makeResult(" " + " \n".join(self.code)) |
| |
| |
| def temp(index): |
| return "temp" + str(index) |
| |
| |
| def generateB3OpCode(index, op, params): |
| return "Value* " + temp(index) + " = m_currentBlock->appendNew<Value>(m_proc, B3::" + op + ", origin(), " + ", ".join(params) + ");" |
| |
| |
| def generateConstCode(index, value, type): |
| return "Value* " + temp(index) + " = constant(" + type + ", " + value + ");" |
| |
| |
| def generateB3Code(wasmOp, source): |
| tokens = lex(Source(source)) |
| parser = CodeGenerator(tokens) |
| return parser.generate(wasmOp) |
| |
| |
| def generateSimpleCode(op): |
| opcode = op["opcode"] |
| b3op = opcode["b3op"] |
| args = ["ExpressionType arg" + str(param) for param in range(len(opcode["parameter"]))] |
| args.append("ExpressionType& result") |
| return """ |
| template<> auto B3IRGenerator::addOp<OpType::""" + wasm.toCpp(op["name"]) + ">(" + ", ".join(args) + """) -> PartialResult |
| { |
| """ + generateB3Code(opcode, b3op) + """ |
| return { }; |
| } |
| """ |
| |
| |
| definitions = [generateSimpleCode(op) for op in wasm.opcodeIterator(lambda op: isSimple(op) and (isBinary(op) or isUnary(op)))] |
| contents = wasm.header + """ |
| |
| #pragma once |
| |
| #if ENABLE(WEBASSEMBLY) |
| |
| namespace JSC { namespace Wasm { |
| |
| """ + "".join(definitions) + """ |
| |
| } } // namespace JSC::Wasm |
| |
| #endif // ENABLE(WEBASSEMBLY) |
| |
| """ |
| |
| wasmB3IRGeneratorHFile.write(contents) |
| wasmB3IRGeneratorHFile.close() |