blob: 3cdf0e0faa0b1c505af7dc03553617194bdc1666 [file] [log] [blame]
#!/usr/bin/env python
# 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('(\@[0-9]+)')
decimalRegex = re.compile('([-]?[0-9]+)')
whitespaceRegex = re.compile('\s+')
commaRegex = re.compile('(,)')
oparenRegex = re.compile('(\()')
cparenRegex = re.compile('(\))')
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 = "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 generate(self, wasmOp):
if len(self.tokens) == 1:
params = ["arg" + str(param) for param in range(len(wasmOp["parameter"]))]
return " result = m_currentBlock->appendNew<Value>(m_proc, B3::" + self.token() + ", origin(), " + ", ".join(params) + ")"
result = self.generateOpcode()
self.code.append("result = " + result)
return " " + " \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()