Changeset 209083 in webkit


Ignore:
Timestamp:
Nov 29, 2016 11:37:00 AM (7 years ago)
Author:
keith_miller@apple.com
Message:

Add simple way to implement Wasm ops that require more than one B3 opcode
https://bugs.webkit.org/show_bug.cgi?id=165129

Reviewed by Geoffrey Garen.

JSTests:

  • wasm/function-tests/eqz.js: Added.
  • wasm/function-tests/max.js: Added.
  • wasm/function-tests/min.js: Added.
  • wasm/wasm.json:

Source/JavaScriptCore:

This patch adds a simple way to show the B3IRGenerator opcode script how
to generate code for Wasm opcodes that do not have a one to one mapping.
The syntax is pretty simple right now. There are only three things one
can use as of this patch (although more things might be added in the future)
1) Wasm opcode arguments: These are referred to as @<argument_number>. For example,

I32.sub would map to Sub(@0, @1).

2) 32-bit int constants: These are reffered to as i32(<value>). For example, i32.inc

would map to Add(@0, i32(1))

3) B3 opcodes: These are referred to as the B3 opcode name followed by the B3Value's constructor

arguments. A value may take the result of another value as an argument. For example, you can do
Div(Mul(@0, Add(@0, i32(1))), i32(2)) if there was a b3 opcode that computed the sum from 1 to n.

These scripts are used to implement Wasm's eqz and floating point max/min opcodes. This patch
also adds missing support for the Wasm Neg opcodes.

  • jsc.cpp:

(box):
(functionTestWasmModuleFunctions):

  • wasm/WasmB3IRGenerator.cpp:

(JSC::Wasm::toB3Op): Deleted.

  • wasm/WasmFunctionParser.h:

(JSC::Wasm::FunctionParser<Context>::parseBody):

  • wasm/WasmModuleParser.cpp:

(JSC::Wasm::ModuleParser::parseType):

  • wasm/WasmParser.h:

(JSC::Wasm::Parser::parseUInt8):
(JSC::Wasm::Parser::parseValueType):

  • wasm/generateWasmB3IRGeneratorInlinesHeader.py:

(Source):
(Source.init):
(read):
(lex):
(CodeGenerator):
(CodeGenerator.init):
(CodeGenerator.advance):
(CodeGenerator.token):
(CodeGenerator.parseError):
(CodeGenerator.consume):
(CodeGenerator.generateParameters):
(CodeGenerator.generateOpcode):
(CodeGenerator.generate):
(temp):
(generateB3OpCode):
(generateI32ConstCode):
(generateB3Code):
(generateSimpleCode):

  • wasm/wasm.json:
Location:
trunk
Files:
3 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r208953 r209083  
     12016-11-29  Keith Miller  <keith_miller@apple.com>
     2
     3        Add simple way to implement Wasm ops that require more than one B3 opcode
     4        https://bugs.webkit.org/show_bug.cgi?id=165129
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        * wasm/function-tests/eqz.js: Added.
     9        * wasm/function-tests/max.js: Added.
     10        * wasm/function-tests/min.js: Added.
     11        * wasm/wasm.json:
     12
    1132016-11-21  Yusuke Suzuki  <utatane.tea@gmail.com>
    214
  • trunk/JSTests/wasm/wasm.json

    r208855 r209083  
    121121        "i32.ctz":             { "category": "arithmetic", "value":  88, "return": ["i32"],      "parameter": ["i32"],                  "immediate": []                         },
    122122        "i32.popcnt":          { "category": "arithmetic", "value":  89, "return": ["i32"],      "parameter": ["i32"],                  "immediate": []                         },
    123         "i32.eqz":             { "category": "comparison", "value":  90, "return": ["bool"],     "parameter": ["i32"],                  "immediate": []                        },
     123        "i32.eqz":             { "category": "comparison", "value":  90, "return": ["bool"],     "parameter": ["i32"],                  "immediate": [], "b3op": "Equal(i32(0), @0)" },
    124124        "i64.add":             { "category": "arithmetic", "value":  91, "return": ["i64"],      "parameter": ["i64", "i64"],           "immediate": [], "b3op": "Add"          },
    125125        "i64.sub":             { "category": "arithmetic", "value":  92, "return": ["i64"],      "parameter": ["i64", "i64"],           "immediate": [], "b3op": "Sub"          },
     
    150150        "i64.ctz":             { "category": "arithmetic", "value": 115, "return": ["i64"],      "parameter": ["i64"],                  "immediate": []                         },
    151151        "i64.popcnt":          { "category": "arithmetic", "value": 116, "return": ["i64"],      "parameter": ["i64"],                  "immediate": []                         },
    152         "i64.eqz":             { "category": "comparison", "value": 186, "return": ["bool"],     "parameter": ["i64"],                  "immediate": []                        },
     152        "i64.eqz":             { "category": "comparison", "value": 186, "return": ["bool"],     "parameter": ["i64"],                  "immediate": [], "b3op": "Equal(i32(0), @0)" },
    153153        "f32.add":             { "category": "arithmetic", "value": 117, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Add"          },
    154154        "f32.sub":             { "category": "arithmetic", "value": 118, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Sub"          },
    155155        "f32.mul":             { "category": "arithmetic", "value": 119, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Mul"          },
    156156        "f32.div":             { "category": "arithmetic", "value": 120, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Div"          },
    157         "f32.min":             { "category": "arithmetic", "value": 121, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": []                        },
    158         "f32.max":             { "category": "arithmetic", "value": 122, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": []                        },
     157        "f32.min":             { "category": "arithmetic", "value": 121, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Select(LessThan(@0, @1), @0, @1)" },
     158        "f32.max":             { "category": "arithmetic", "value": 122, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Select(LessThan(@0, @1), @1, @0)" },
    159159        "f32.abs":             { "category": "arithmetic", "value": 123, "return": ["f32"],      "parameter": ["f32"],                  "immediate": [], "b3op": "Abs"          },
    160         "f32.neg":             { "category": "arithmetic", "value": 124, "return": ["f32"],      "parameter": ["f32"],                  "immediate": []                         },
     160        "f32.neg":             { "category": "arithmetic", "value": 124, "return": ["f32"],      "parameter": ["f32"],                  "immediate": [], "b3op": "Neg"          },
    161161        "f32.copysign":        { "category": "arithmetic", "value": 125, "return": ["f32"],      "parameter": ["f32"],                  "immediate": []                         },
    162162        "f32.ceil":            { "category": "arithmetic", "value": 126, "return": ["f32"],      "parameter": ["f32"],                  "immediate": [], "b3op": "Ceil"         },
     
    175175        "f64.mul":             { "category": "arithmetic", "value": 139, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": [], "b3op": "Mul"          },
    176176        "f64.div":             { "category": "arithmetic", "value": 140, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": [], "b3op": "Div"          },
    177         "f64.min":             { "category": "arithmetic", "value": 141, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": []                        },
    178         "f64.max":             { "category": "arithmetic", "value": 142, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": []                        },
     177        "f64.min":             { "category": "arithmetic", "value": 141, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": [], "b3op": "Select(LessThan(@0, @1), @0, @1)" },
     178        "f64.max":             { "category": "arithmetic", "value": 142, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": [], "b3op": "Select(LessThan(@0, @1), @1, @0)" },
    179179        "f64.abs":             { "category": "arithmetic", "value": 143, "return": ["f64"],      "parameter": ["f64"],                  "immediate": [], "b3op": "Abs"          },
    180         "f64.neg":             { "category": "arithmetic", "value": 144, "return": ["f64"],      "parameter": ["f64"],                  "immediate": []                         },
     180        "f64.neg":             { "category": "arithmetic", "value": 144, "return": ["f64"],      "parameter": ["f64"],                  "immediate": [], "b3op": "Neg"          },
    181181        "f64.copysign":        { "category": "arithmetic", "value": 145, "return": ["f64"],      "parameter": ["f64"],                  "immediate": []                         },
    182182        "f64.ceil":            { "category": "arithmetic", "value": 146, "return": ["f64"],      "parameter": ["f64"],                  "immediate": [], "b3op": "Ceil"         },
  • trunk/Source/JavaScriptCore/ChangeLog

    r209080 r209083  
     12016-11-29  Keith Miller  <keith_miller@apple.com>
     2
     3        Add simple way to implement Wasm ops that require more than one B3 opcode
     4        https://bugs.webkit.org/show_bug.cgi?id=165129
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        This patch adds a simple way to show the B3IRGenerator opcode script how
     9        to generate code for Wasm opcodes that do not have a one to one mapping.
     10        The syntax is pretty simple right now. There are only three things one
     11        can use as of this patch (although more things might be added in the future)
     12        1) Wasm opcode arguments: These are referred to as @<argument_number>. For example,
     13           I32.sub would map to Sub(@0, @1).
     14        2) 32-bit int constants: These are reffered to as i32(<value>). For example, i32.inc
     15           would map to Add(@0, i32(1))
     16        3) B3 opcodes: These are referred to as the B3 opcode name followed by the B3Value's constructor
     17           arguments. A value may take the result of another value as an argument. For example, you can do
     18           Div(Mul(@0, Add(@0, i32(1))), i32(2)) if there was a b3 opcode that computed the sum from 1 to n.
     19
     20        These scripts are used to implement Wasm's eqz and floating point max/min opcodes. This patch
     21        also adds missing support for the Wasm Neg opcodes.
     22
     23        * jsc.cpp:
     24        (box):
     25        (functionTestWasmModuleFunctions):
     26        * wasm/WasmB3IRGenerator.cpp:
     27        (JSC::Wasm::toB3Op): Deleted.
     28        * wasm/WasmFunctionParser.h:
     29        (JSC::Wasm::FunctionParser<Context>::parseBody):
     30        * wasm/WasmModuleParser.cpp:
     31        (JSC::Wasm::ModuleParser::parseType):
     32        * wasm/WasmParser.h:
     33        (JSC::Wasm::Parser::parseUInt8):
     34        (JSC::Wasm::Parser::parseValueType):
     35        * wasm/generateWasmB3IRGeneratorInlinesHeader.py:
     36        (Source):
     37        (Source.__init__):
     38        (read):
     39        (lex):
     40        (CodeGenerator):
     41        (CodeGenerator.__init__):
     42        (CodeGenerator.advance):
     43        (CodeGenerator.token):
     44        (CodeGenerator.parseError):
     45        (CodeGenerator.consume):
     46        (CodeGenerator.generateParameters):
     47        (CodeGenerator.generateOpcode):
     48        (CodeGenerator.generate):
     49        (temp):
     50        (generateB3OpCode):
     51        (generateI32ConstCode):
     52        (generateB3Code):
     53        (generateSimpleCode):
     54        * wasm/wasm.json:
     55
    1562016-11-29  Mark Lam  <mark.lam@apple.com>
    257
  • trunk/Source/JavaScriptCore/jsc.cpp

    r208985 r209083  
    25102510
    25112511    RELEASE_ASSERT(typeString == "f64");
    2512     return value;
     2512    return JSValue::decode(bitwise_cast<uint64_t>(value.asNumber()));
    25132513}
    25142514
     
    25492549    Wasm::Plan plan(&vm, static_cast<uint8_t*>(source->vector()), source->length());
    25502550    plan.run();
    2551     if (plan.failed())
     2551    if (plan.failed()) {
     2552        dataLogLn("failed to parse module: ", plan.errorMessage());
    25522553        CRASH();
     2554    }
    25532555
    25542556    if (plan.compiledFunctionCount() != functionCount)
  • trunk/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp

    r208821 r209083  
    6060}
    6161
    62 inline B3::Opcode toB3Op(BinaryOpType op)
    63 {
    64     switch (op) {
    65 #define CREATE_CASE(name, op, b3op) case BinaryOpType::name: return b3op;
    66     FOR_EACH_WASM_BINARY_OP(CREATE_CASE)
    67 #undef CREATE_CASE
    68     }
    69     RELEASE_ASSERT_NOT_REACHED();
    70 }
    71 
    72 inline B3::Opcode toB3Op(UnaryOpType op)
    73 {
    74     switch (op) {
    75 #define CREATE_CASE(name, op, b3op) case UnaryOpType::name: return b3op;
    76     FOR_EACH_WASM_UNARY_OP(CREATE_CASE)
    77 #undef CREATE_CASE
    78     }
    79     RELEASE_ASSERT_NOT_REACHED();
    80 }
    81 
    8262class B3IRGenerator {
    8363public:
  • trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h

    r208821 r209083  
    124124    while (true) {
    125125        uint8_t op;
    126         if (!parseUInt7(op) || !isValidOpType(op)) {
     126        if (!parseUInt8(op) || !isValidOpType(op)) {
    127127            if (verbose)
    128128                WTF::dataLogLn("attempted to decode invalid op: ", RawPointer(reinterpret_cast<void*>(op)), " at offset: ", RawPointer(reinterpret_cast<void*>(m_offset)));
     
    351351    case OpType::Block: {
    352352        Type inlineSignature;
    353         if (!parseValueType(inlineSignature))
     353        if (!parseResultType(inlineSignature))
    354354            return false;
    355355
     
    361361    case OpType::Loop: {
    362362        Type inlineSignature;
    363         if (!parseValueType(inlineSignature))
     363        if (!parseResultType(inlineSignature))
    364364            return false;
    365365
     
    371371    case OpType::If: {
    372372        Type inlineSignature;
    373         if (!parseValueType(inlineSignature))
     373        if (!parseResultType(inlineSignature))
    374374            return false;
    375375
  • trunk/Source/JavaScriptCore/wasm/WasmModuleParser.cpp

    r208627 r209083  
    186186
    187187        for (unsigned i = 0; i != argumentCount; ++i) {
    188             uint8_t argumentType;
    189             if (!parseUInt7(argumentType) || !isValueType(static_cast<Type>(argumentType)))
    190                 return false;
    191             argumentTypes.uncheckedAppend(static_cast<Type>(argumentType));
     188            Type argumentType;
     189            if (!parseResultType(argumentType))
     190                return false;
     191            argumentTypes.uncheckedAppend(argumentType);
    192192        }
    193193
  • trunk/Source/JavaScriptCore/wasm/WasmParser.h

    r208567 r209083  
    5050    bool WARN_UNUSED_RETURN parseInt7(int8_t&);
    5151    bool WARN_UNUSED_RETURN parseUInt7(uint8_t&);
     52    bool WARN_UNUSED_RETURN parseUInt8(uint8_t&);
    5253    bool WARN_UNUSED_RETURN parseUInt32(uint32_t&);
    5354    bool WARN_UNUSED_RETURN parseVarUInt32(uint32_t&);
    5455    bool WARN_UNUSED_RETURN parseVarUInt64(uint64_t&);
    5556
     57    bool WARN_UNUSED_RETURN parseResultType(Type&);
    5658    bool WARN_UNUSED_RETURN parseValueType(Type&);
    5759    bool WARN_UNUSED_RETURN parseExternalKind(External::Kind&);
     
    132134}
    133135
     136ALWAYS_INLINE bool Parser::parseUInt8(uint8_t& result)
     137{
     138    if (m_offset >= length())
     139        return false;
     140    result = source()[m_offset++];
     141    return true;
     142}
     143
    134144ALWAYS_INLINE bool Parser::parseInt7(int8_t& result)
    135145{
     
    158168}
    159169
    160 ALWAYS_INLINE bool Parser::parseValueType(Type& result)
     170ALWAYS_INLINE bool Parser::parseResultType(Type& result)
    161171{
    162172    uint8_t value;
    163173    if (!parseUInt7(value))
    164174        return false;
    165     if (value >= static_cast<uint8_t>(Type::LastValueType))
     175    if (value > static_cast<uint8_t>(Type::LastValueType))
    166176        return false;
    167177    result = static_cast<Type>(value);
    168178    return true;
     179}
     180
     181ALWAYS_INLINE bool Parser::parseValueType(Type& result)
     182{
     183    return parseResultType(result) && isValueType(result);
    169184}
    170185   
  • trunk/Source/JavaScriptCore/wasm/generateWasmB3IRGeneratorInlinesHeader.py

    r208821 r209083  
    2929import optparse
    3030import sys
     31import re
    3132
    3233parser = optparse.OptionParser(usage="usage: %prog <wasm.json> <WasmOps.h>")
     
    3839opcodes = wasm.opcodes
    3940wasmB3IRGeneratorHFile = open(args[2], "w")
     41
     42opcodeRegex = re.compile('([a-zA-Z0-9]+)')
     43argumentRegex = re.compile('(\@[0-9]+)')
     44decimalRegex = re.compile('([-]?[0-9]+)')
     45whitespaceRegex = re.compile('\s+')
     46commaRegex = re.compile('(,)')
     47oparenRegex = re.compile('(\()')
     48cparenRegex = re.compile('(\))')
     49
     50
     51class Source:
     52    def __init__(self, contents, offset=0):
     53        self.contents = contents
     54        self.offset = offset
     55
     56
     57def read(regex, source):
     58    match = regex.match(source.contents, source.offset)
     59    if not match:
     60        return None
     61    source.offset = match.end()
     62    return match.group()
     63
     64
     65def lex(source):
     66    result = []
     67    while source.offset != len(source.contents):
     68        read(whitespaceRegex, source)
     69        opcode = read(opcodeRegex, source)
     70        if opcode:
     71            result.append(opcode)
     72            continue
     73
     74        argument = read(argumentRegex, source)
     75        if argument:
     76            result.append(argument)
     77            continue
     78
     79        number = read(decimalRegex, source)
     80        if number:
     81            result.append(int(number))
     82            continue
     83
     84        oparen = read(oparenRegex, source)
     85        if oparen:
     86            result.append(oparen)
     87            continue
     88
     89        cparen = read(cparenRegex, source)
     90        if cparen:
     91            result.append(cparen)
     92            continue
     93
     94        comma = read(commaRegex, source)
     95        if comma:
     96            # Skip commas
     97            continue
     98
     99        raise Exception("Lexing Error: could not lex token from: " + source.contents + " at offset: " + str(source.offset) + " (" + source.contents[source.offset:] + "). With tokens: [" + ", ".join(result) + "]")
     100    return result
     101
     102
     103class CodeGenerator:
     104    def __init__(self, tokens):
     105        self.tokens = tokens
     106        self.index = 0
     107        self.code = []
     108
     109    def advance(self):
     110        self.index += 1
     111
     112    def token(self):
     113        return self.tokens[self.index]
     114
     115    def parseError(self, string):
     116        raise Exception("Parse error " + string)
     117
     118    def consume(self, string):
     119        if self.token() != string:
     120            self.parseError("Expected " + string + " but got " + self.token())
     121        self.advance()
     122
     123    def generateParameters(self):
     124        self.advance()
     125        params = []
     126        tokens = self.tokens
     127        while self.index < len(tokens):
     128            if self.token() == ")":
     129                self.advance()
     130                return params
     131            params.append(self.generateOpcode())
     132        self.parseError("Parsing arguments fell off end")
     133
     134    def generateOpcode(self):
     135        result = None
     136        if self.token() == "i32":
     137            self.advance()
     138            self.consume("(")
     139            self.code.append(generateI32ConstCode(self.index, self.token()))
     140            result = temp(self.index)
     141            self.advance()
     142            self.consume(")")
     143        elif argumentRegex.match(self.token()):
     144            result = "arg" + self.token()[1:]
     145            self.advance()
     146        else:
     147            op = self.token()
     148            index = self.index
     149            self.advance()
     150            params = self.generateParameters()
     151            self.code.append(generateB3OpCode(index, op, params))
     152            result = temp(index)
     153
     154        return result
     155
     156    def generate(self, wasmOp):
     157        if len(self.tokens) == 1:
     158            params = ["arg" + str(param) for param in range(len(wasmOp["parameter"]))]
     159            return "    result = m_currentBlock->appendNew<Value>(m_proc, B3::" + self.token() + ", Origin(), " + ", ".join(params) + ")"
     160        result = self.generateOpcode()
     161        self.code.append("result = " + result)
     162        return "    " + "    \n".join(self.code)
     163
     164
     165def temp(index):
     166    return "temp" + str(index)
     167
     168
     169def generateB3OpCode(index, op, params):
     170    return "Value* " + temp(index) + " = m_currentBlock->appendNew<Value>(m_proc, B3::" + op + ", Origin(), " + ", ".join(params) + ");"
     171
     172
     173def generateI32ConstCode(index, value):
     174    return "Value* " + temp(index) + " = m_currentBlock->appendIntConstant(m_proc, Origin(), B3::Int32, " + value + ");"
     175
     176
     177def generateB3Code(wasmOp, source):
     178    tokens = lex(Source(source))
     179    parser = CodeGenerator(tokens)
     180    return parser.generate(wasmOp)
    40181
    41182
     
    45186    args = ["ExpressionType arg" + str(param) for param in range(len(opcode["parameter"]))]
    46187    args.append("ExpressionType& result")
    47     params = ["arg" + str(param) for param in range(len(opcode["parameter"]))]
    48188    return """
    49189template<> bool B3IRGenerator::addOp<OpType::""" + wasm.toCpp(op["name"]) + ">(" + ", ".join(args) + """)
    50190{
    51     result = m_currentBlock->appendNew<Value>(m_proc, B3::""" + opcode["b3op"] + ", Origin(), " + ", ".join(params) + """);
     191""" + generateB3Code(opcode, b3op) + """;
    52192    return true;
    53193}
    54194"""
    55195
     196
    56197definitions = [generateSimpleCode(op) for op in wasm.opcodeIterator(lambda op: isSimple(op) and (isBinary(op) or isUnary(op)))]
    57198contents = wasm.header + """
  • trunk/Source/JavaScriptCore/wasm/wasm.json

    r208855 r209083  
    121121        "i32.ctz":             { "category": "arithmetic", "value":  88, "return": ["i32"],      "parameter": ["i32"],                  "immediate": []                         },
    122122        "i32.popcnt":          { "category": "arithmetic", "value":  89, "return": ["i32"],      "parameter": ["i32"],                  "immediate": []                         },
    123         "i32.eqz":             { "category": "comparison", "value":  90, "return": ["bool"],     "parameter": ["i32"],                  "immediate": []                        },
     123        "i32.eqz":             { "category": "comparison", "value":  90, "return": ["bool"],     "parameter": ["i32"],                  "immediate": [], "b3op": "Equal(i32(0), @0)" },
    124124        "i64.add":             { "category": "arithmetic", "value":  91, "return": ["i64"],      "parameter": ["i64", "i64"],           "immediate": [], "b3op": "Add"          },
    125125        "i64.sub":             { "category": "arithmetic", "value":  92, "return": ["i64"],      "parameter": ["i64", "i64"],           "immediate": [], "b3op": "Sub"          },
     
    150150        "i64.ctz":             { "category": "arithmetic", "value": 115, "return": ["i64"],      "parameter": ["i64"],                  "immediate": []                         },
    151151        "i64.popcnt":          { "category": "arithmetic", "value": 116, "return": ["i64"],      "parameter": ["i64"],                  "immediate": []                         },
    152         "i64.eqz":             { "category": "comparison", "value": 186, "return": ["bool"],     "parameter": ["i64"],                  "immediate": []                        },
     152        "i64.eqz":             { "category": "comparison", "value": 186, "return": ["bool"],     "parameter": ["i64"],                  "immediate": [], "b3op": "Equal(i32(0), @0)" },
    153153        "f32.add":             { "category": "arithmetic", "value": 117, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Add"          },
    154154        "f32.sub":             { "category": "arithmetic", "value": 118, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Sub"          },
    155155        "f32.mul":             { "category": "arithmetic", "value": 119, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Mul"          },
    156156        "f32.div":             { "category": "arithmetic", "value": 120, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Div"          },
    157         "f32.min":             { "category": "arithmetic", "value": 121, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": []                        },
    158         "f32.max":             { "category": "arithmetic", "value": 122, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": []                        },
     157        "f32.min":             { "category": "arithmetic", "value": 121, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Select(LessThan(@0, @1), @0, @1)" },
     158        "f32.max":             { "category": "arithmetic", "value": 122, "return": ["f32"],      "parameter": ["f32", "f32"],           "immediate": [], "b3op": "Select(LessThan(@0, @1), @1, @0)" },
    159159        "f32.abs":             { "category": "arithmetic", "value": 123, "return": ["f32"],      "parameter": ["f32"],                  "immediate": [], "b3op": "Abs"          },
    160         "f32.neg":             { "category": "arithmetic", "value": 124, "return": ["f32"],      "parameter": ["f32"],                  "immediate": []                         },
     160        "f32.neg":             { "category": "arithmetic", "value": 124, "return": ["f32"],      "parameter": ["f32"],                  "immediate": [], "b3op": "Neg"          },
    161161        "f32.copysign":        { "category": "arithmetic", "value": 125, "return": ["f32"],      "parameter": ["f32"],                  "immediate": []                         },
    162162        "f32.ceil":            { "category": "arithmetic", "value": 126, "return": ["f32"],      "parameter": ["f32"],                  "immediate": [], "b3op": "Ceil"         },
     
    175175        "f64.mul":             { "category": "arithmetic", "value": 139, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": [], "b3op": "Mul"          },
    176176        "f64.div":             { "category": "arithmetic", "value": 140, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": [], "b3op": "Div"          },
    177         "f64.min":             { "category": "arithmetic", "value": 141, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": []                        },
    178         "f64.max":             { "category": "arithmetic", "value": 142, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": []                        },
     177        "f64.min":             { "category": "arithmetic", "value": 141, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": [], "b3op": "Select(LessThan(@0, @1), @0, @1)" },
     178        "f64.max":             { "category": "arithmetic", "value": 142, "return": ["f64"],      "parameter": ["f64", "f64"],           "immediate": [], "b3op": "Select(LessThan(@0, @1), @1, @0)" },
    179179        "f64.abs":             { "category": "arithmetic", "value": 143, "return": ["f64"],      "parameter": ["f64"],                  "immediate": [], "b3op": "Abs"          },
    180         "f64.neg":             { "category": "arithmetic", "value": 144, "return": ["f64"],      "parameter": ["f64"],                  "immediate": []                         },
     180        "f64.neg":             { "category": "arithmetic", "value": 144, "return": ["f64"],      "parameter": ["f64"],                  "immediate": [], "b3op": "Neg"          },
    181181        "f64.copysign":        { "category": "arithmetic", "value": 145, "return": ["f64"],      "parameter": ["f64"],                  "immediate": []                         },
    182182        "f64.ceil":            { "category": "arithmetic", "value": 146, "return": ["f64"],      "parameter": ["f64"],                  "immediate": [], "b3op": "Ceil"         },
Note: See TracChangeset for help on using the changeset viewer.