⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 246579 in webkit


Ignore:
Timestamp:
Jun 18, 2019, 7:36:42 PM (7 years ago)
Author:
sbarati@apple.com
Message:

[WHLSL] Support matrices
https://bugs.webkit.org/show_bug.cgi?id=198876
<rdar://problem/51768882>

Reviewed by Dean Jackson and Myles Maxfield.

Source/WebCore:

This patch adds in support for matrices to WHLSL. Most matrix related code
is defined by the standard library. This patch just needed to add support
for the native functions operator[] and operator[]= on matrix types. The only
native functions that are named operator[] and operator[]= are for matrix
operations, so we strongly assume when generating code for native operator[] and
operator[]= that we're dealing with matrix types.

operator[]= ignores the write if the index is out of bounds. operator[]
returns a zeroed vector if the index is out of bounds.

This patch also incorporates two bug fixes:

  1. This patch takes Robin's patch in https://bugs.webkit.org/show_bug.cgi?id=198313 to ensure

we don't have pointers to values in a hash map. This was needed in this patch
otherwise we'd crash parsing the standard library.

  1. This patch fixes how we handle "break" in metal codegen. When I first

implemented break, I strongly assumed we were in a loop. However, break
can be either from a loop or from switch. This patch teaches the metal code
generator to track which context we're in and to emit code accordingly.

Tests: webgpu/whlsl-matrix-2.html

webgpu/whlsl-matrix.html

  • Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:

(WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
(WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop):

  • Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp:

(WebCore::WHLSL::Metal::generateMetalCodeShared):

  • Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp:

(WebCore::WHLSL::Metal::writeNativeFunction):

  • Modules/webgpu/WHLSL/WHLSLChecker.cpp:

(WebCore::WHLSL::Checker::assignTypes):
(WebCore::WHLSL::Checker::getInfo):
(WebCore::WHLSL::Checker::assignType):
(WebCore::WHLSL::Checker::forwardType):

  • Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt:

LayoutTests:

  • webgpu/whlsl-matrix-2-expected.txt: Added.
  • webgpu/whlsl-matrix-2.html: Added.
  • webgpu/whlsl-matrix-expected.txt: Added.
  • webgpu/whlsl-matrix.html: Added.
Location:
trunk
Files:
4 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r246576 r246579  
     12019-06-18  Saam Barati  <sbarati@apple.com>
     2
     3        [WHLSL] Support matrices
     4        https://bugs.webkit.org/show_bug.cgi?id=198876
     5        <rdar://problem/51768882>
     6
     7        Reviewed by Dean Jackson and Myles Maxfield.
     8
     9        * webgpu/whlsl-matrix-2-expected.txt: Added.
     10        * webgpu/whlsl-matrix-2.html: Added.
     11        * webgpu/whlsl-matrix-expected.txt: Added.
     12        * webgpu/whlsl-matrix.html: Added.
     13
    1142019-06-18  Russell Epstein  <russell_e@apple.com>
    215
  • trunk/Source/WebCore/ChangeLog

    r246578 r246579  
     12019-06-18  Saam Barati  <sbarati@apple.com>
     2
     3        [WHLSL] Support matrices
     4        https://bugs.webkit.org/show_bug.cgi?id=198876
     5        <rdar://problem/51768882>
     6
     7        Reviewed by Dean Jackson and Myles Maxfield.
     8
     9        This patch adds in support for matrices to WHLSL. Most matrix related code
     10        is defined by the standard library. This patch just needed to add support
     11        for the native functions operator[] and operator[]= on matrix types. The only
     12        native functions that are named operator[] and operator[]= are for matrix
     13        operations, so we strongly assume when generating code for native operator[] and
     14        operator[]= that we're dealing with matrix types.
     15       
     16        operator[]= ignores the write if the index is out of bounds. operator[]
     17        returns a zeroed vector if the index is out of bounds. 
     18       
     19        This patch also incorporates two bug fixes:
     20        1. This patch takes Robin's patch in https://bugs.webkit.org/show_bug.cgi?id=198313 to ensure
     21        we don't have pointers to values in a hash map. This was needed in this patch
     22        otherwise we'd crash parsing the standard library.
     23       
     24        2. This patch fixes how we handle "break" in metal codegen. When I first
     25        implemented break, I strongly assumed we were in a loop. However, break
     26        can be either from a loop or from switch. This patch teaches the metal code
     27        generator to track which context we're in and to emit code accordingly.
     28
     29        Tests: webgpu/whlsl-matrix-2.html
     30               webgpu/whlsl-matrix.html
     31
     32        * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
     33        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
     34        (WebCore::WHLSL::Metal::FunctionDefinitionWriter::emitLoop):
     35        * Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp:
     36        (WebCore::WHLSL::Metal::generateMetalCodeShared):
     37        * Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp:
     38        (WebCore::WHLSL::Metal::writeNativeFunction):
     39        * Modules/webgpu/WHLSL/WHLSLChecker.cpp:
     40        (WebCore::WHLSL::Checker::assignTypes):
     41        (WebCore::WHLSL::Checker::getInfo):
     42        (WebCore::WHLSL::Checker::assignType):
     43        (WebCore::WHLSL::Checker::forwardType):
     44        * Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt:
     45
    1462019-06-18  Yusuke Suzuki  <ysuzuki@apple.com>
    247
  • trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp

    r246438 r246579  
    192192    }
    193193
     194    enum class BreakContext {
     195        Loop,
     196        Switch
     197    };
     198
     199    Optional<BreakContext> m_currentBreakContext;
     200
    194201    Intrinsics& m_intrinsics;
    195202    TypeNamer& m_typeNamer;
     
    272279void FunctionDefinitionWriter::visit(AST::Break&)
    273280{
    274     ASSERT(m_breakOutOfCurrentLoopEarlyVariable.length());
    275     m_stringBuilder.append(makeString(m_breakOutOfCurrentLoopEarlyVariable, " = true;\n"));
    276     m_stringBuilder.append("break;\n");
     281    ASSERT(m_currentBreakContext);
     282    switch (*m_currentBreakContext) {
     283    case BreakContext::Switch:
     284        m_stringBuilder.append("break;\n");
     285        break;
     286    case BreakContext::Loop:
     287        ASSERT(m_breakOutOfCurrentLoopEarlyVariable.length());
     288        m_stringBuilder.append(makeString(m_breakOutOfCurrentLoopEarlyVariable, " = true;\n"));
     289        m_stringBuilder.append("break;\n");
     290        break;
     291    }
    277292}
    278293
     
    308323
    309324    m_stringBuilder.append("do {\n");
     325    SetForScope<Optional<BreakContext>> breakContext(m_currentBreakContext, BreakContext::Loop);
    310326    checkErrorAndVisit(body);
    311327    m_stringBuilder.append("} while(false); \n");
     
    394410    else
    395411        m_stringBuilder.append("default:\n");
     412    SetForScope<Optional<BreakContext>> breakContext(m_currentBreakContext, BreakContext::Switch);
    396413    checkErrorAndVisit(switchCase.block());
    397414    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195812 Figure out whether we need to break or fallthrough.
    398     notImplemented();
    399415}
    400416
  • trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLMetalCodeGenerator.cpp

    r243091 r246579  
    3131#include "WHLSLFunctionWriter.h"
    3232#include "WHLSLTypeNamer.h"
     33#include <wtf/DataLog.h>
    3334#include <wtf/text/StringBuilder.h>
    3435
     
    3839
    3940namespace Metal {
     41
     42static constexpr bool dumpMetalCode = false;
    4043
    4144static String generateMetalCodeShared(String&& metalTypes, String&& metalFunctions)
     
    5457    stringBuilder.append(WTFMove(metalTypes));
    5558    stringBuilder.append(WTFMove(metalFunctions));
     59
     60    if (dumpMetalCode) {
     61        dataLogLn("Generated Metal code: ");
     62        dataLogLn(stringBuilder.toString());
     63    }
     64
    5665    return stringBuilder.toString();
    5766}
  • trunk/Source/WebCore/Modules/webgpu/WHLSL/Metal/WHLSLNativeFunctionWriter.cpp

    r246490 r246579  
    226226    }
    227227
     228    auto numberOfMatrixRows = [&] {
     229        auto& typeReference = downcast<AST::TypeReference>(*nativeFunctionDeclaration.parameters()[0]->type());
     230        auto& matrixType = downcast<AST::NativeTypeDeclaration>(downcast<AST::TypeReference>(downcast<AST::TypeDefinition>(typeReference.resolvedType()).type()).resolvedType());
     231        ASSERT(matrixType.name() == "matrix");
     232        ASSERT(matrixType.typeArguments().size() == 3);
     233        return String::number(WTF::get<AST::ConstantExpression>(matrixType.typeArguments()[1]).integerLiteral().value());
     234    };
     235
     236    if (nativeFunctionDeclaration.name() == "operator[]") {
     237        ASSERT(nativeFunctionDeclaration.parameters().size() == 2);
     238        auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
     239        auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
     240        auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
     241        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i) {\n"));
     242        stringBuilder.append(makeString("    if (i < ", numberOfMatrixRows(), ") return m[i];\n"));
     243        stringBuilder.append(makeString("    return ", metalReturnName, "(0);\n"));
     244        stringBuilder.append("}\n");
     245        return stringBuilder.toString();
     246    }
     247
     248    if (nativeFunctionDeclaration.name() == "operator[]=") {
     249        ASSERT(nativeFunctionDeclaration.parameters().size() == 3);
     250        auto metalParameter1Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[0]->type());
     251        auto metalParameter2Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[1]->type());
     252        auto metalParameter3Name = typeNamer.mangledNameForType(*nativeFunctionDeclaration.parameters()[2]->type());
     253        auto metalReturnName = typeNamer.mangledNameForType(nativeFunctionDeclaration.type());
     254        stringBuilder.append(makeString(metalReturnName, ' ', outputFunctionName, '(', metalParameter1Name, " m, ", metalParameter2Name, " i, ", metalParameter3Name, " v) {\n"));
     255        stringBuilder.append(makeString("    if (i < ", numberOfMatrixRows(), ") m[i] = v;\n"));
     256        stringBuilder.append("    return m;\n");
     257        stringBuilder.append("}\n");
     258        return stringBuilder.toString();
     259    }
     260
    228261    if (nativeFunctionDeclaration.isOperator()) {
    229262        if (nativeFunctionDeclaration.parameters().size() == 1) {
  • trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLChecker.cpp

    r246515 r246579  
    508508    void finishVisiting(AST::PropertyAccessExpression&, ResolvingType* additionalArgumentType = nullptr);
    509509
    510     HashMap<AST::Expression*, ResolvingType> m_typeMap;
     510    HashMap<AST::Expression*, std::unique_ptr<ResolvingType>> m_typeMap;
    511511    HashMap<AST::Expression*, AST::TypeAnnotation> m_typeAnnotations;
    512512    HashSet<String> m_vertexEntryPoints;
     
    538538{
    539539    for (auto& keyValuePair : m_typeMap) {
    540         auto success = keyValuePair.value.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& unnamedType) -> bool {
     540        auto success = keyValuePair.value->visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& unnamedType) -> bool {
    541541            keyValuePair.key->setType(unnamedType->clone());
    542542            return true;
     
    781781        return WTF::nullopt;
    782782    }
    783     return {{ typeIterator->value, typeAnnotationIterator->value }};
     783    return {{ *typeIterator->value, typeAnnotationIterator->value }};
    784784}
    785785
     
    803803void Checker::assignType(AST::Expression& expression, UniqueRef<AST::UnnamedType>&& unnamedType, AST::TypeAnnotation typeAnnotation = AST::RightValue())
    804804{
    805     auto addResult = m_typeMap.add(&expression, WTFMove(unnamedType));
     805    auto addResult = m_typeMap.add(&expression, std::make_unique<ResolvingType>(WTFMove(unnamedType)));
    806806    ASSERT_UNUSED(addResult, addResult.isNewEntry);
    807807    auto typeAnnotationAddResult = m_typeAnnotations.add(&expression, WTFMove(typeAnnotation));
     
    811811void Checker::assignType(AST::Expression& expression, RefPtr<ResolvableTypeReference>&& resolvableTypeReference, AST::TypeAnnotation typeAnnotation = AST::RightValue())
    812812{
    813     auto addResult = m_typeMap.add(&expression, WTFMove(resolvableTypeReference));
     813    auto addResult = m_typeMap.add(&expression, std::make_unique<ResolvingType>(WTFMove(resolvableTypeReference)));
    814814    ASSERT_UNUSED(addResult, addResult.isNewEntry);
    815815    auto typeAnnotationAddResult = m_typeAnnotations.add(&expression, WTFMove(typeAnnotation));
     
    820820{
    821821    resolvingType.visit(WTF::makeVisitor([&](UniqueRef<AST::UnnamedType>& result) {
    822         auto addResult = m_typeMap.add(&expression, result->clone());
     822        auto addResult = m_typeMap.add(&expression, std::make_unique<ResolvingType>(result->clone()));
    823823        ASSERT_UNUSED(addResult, addResult.isNewEntry);
    824824    }, [&](RefPtr<ResolvableTypeReference>& result) {
    825         auto addResult = m_typeMap.add(&expression, result.copyRef());
     825        auto addResult = m_typeMap.add(&expression, std::make_unique<ResolvingType>(result.copyRef()));
    826826        ASSERT_UNUSED(addResult, addResult.isNewEntry);
    827827    }));
  • trunk/Source/WebCore/Modules/webgpu/WHLSL/WHLSLStandardLibrary.txt

    r246543 r246579  
    626626}
    627627
     628native float3 operator[](float2x3, uint);
     629native float2x3 operator[]=(float2x3, uint, float3);
     630float operator[](float3 v, uint index) {
     631    switch (index) {
     632        case 0:
     633            return v.x;
     634        case 1:
     635            return v.y;
     636        case 2:
     637            return v.z;
     638        default:
     639            break;
     640    }
     641    return 0.0;
     642}
     643float3 operator[]=(float3 v, uint index, float a) {
     644    switch (index) {
     645        case 0:
     646            v.x = a;
     647            break;
     648        case 1:
     649            v.y = a;
     650            break;
     651        case 2:
     652            v.z = a;
     653            break;
     654        default:
     655            break;
     656    }
     657    return v;
     658}
     659float2x3 operator+(float2x3 a, float2x3 b) {
     660    float2x3 result;
     661    result[0][0] = a[0][0] + b[0][0];
     662    result[0][1] = a[0][1] + b[0][1];
     663    result[0][2] = a[0][2] + b[0][2];
     664    result[1][0] = a[1][0] + b[1][0];
     665    result[1][1] = a[1][1] + b[1][1];
     666    result[1][2] = a[1][2] + b[1][2];
     667    return result;
     668}
     669float2x3 operator*(float2x3 a, float b) {
     670    float2x3 result;
     671    result[0][0] = a[0][0] * b;
     672    result[0][1] = a[0][1] * b;
     673    result[0][2] = a[0][2] * b;
     674    result[1][0] = a[1][0] * b;
     675    result[1][1] = a[1][1] * b;
     676    result[1][2] = a[1][2] * b;
     677    return result;
     678}
     679float2x3 operator+(float2x3 a, float b) {
     680    float2x3 result;
     681    result[0][0] = a[0][0] + b;
     682    result[0][1] = a[0][1] + b;
     683    result[0][2] = a[0][2] + b;
     684    result[1][0] = a[1][0] + b;
     685    result[1][1] = a[1][1] + b;
     686    result[1][2] = a[1][2] + b;
     687    return result;
     688}
     689float2x3 operator-(float2x3 a, float b) {
     690    float2x3 result;
     691    result[0][0] = a[0][0] - b;
     692    result[0][1] = a[0][1] - b;
     693    result[0][2] = a[0][2] - b;
     694    result[1][0] = a[1][0] - b;
     695    result[1][1] = a[1][1] - b;
     696    result[1][2] = a[1][2] - b;
     697    return result;
     698}
     699
     700typedef float4x4 = matrix<float, 4, 4>;
     701native float4 operator[](float4x4, uint);
     702native float4x4 operator[]=(float4x4, uint, float4);
     703
     704float operator[](float4 v, uint index) {
     705    switch (index) {
     706        case 0:
     707            return v.x;
     708        case 1:
     709            return v.y;
     710        case 2:
     711            return v.z;
     712        case 3:
     713            return v.w;
     714        default:
     715            break;
     716    }
     717    float result;
     718    return result;
     719}
     720
     721float4 operator[]=(float4 v, uint index, float a) {
     722    switch (index) {
     723        case 0:
     724            v.x = a;
     725            break;
     726        case 1:
     727            v.y = a;
     728            break;
     729        case 2:
     730            v.z = a;
     731            break;
     732        case 3:
     733            v.w = a;
     734            break;
     735        default:
     736            break;
     737    }
     738    return v;
     739}
     740
     741float4 mul(float4x4 x, float4 y) {
     742    float4 result;
     743    result[0] = 0;
     744    result[0] = result[0] + x[0][0] * y[0];
     745    result[0] = result[0] + x[0][1] * y[1];
     746    result[0] = result[0] + x[0][2] * y[2];
     747    result[0] = result[0] + x[0][3] * y[3];
     748    result[1] = 0;
     749    result[1] = result[1] + x[1][0] * y[0];
     750    result[1] = result[1] + x[1][1] * y[1];
     751    result[1] = result[1] + x[1][2] * y[2];
     752    result[1] = result[1] + x[1][3] * y[3];
     753    result[2] = 0;
     754    result[2] = result[2] + x[2][0] * y[0];
     755    result[2] = result[2] + x[2][1] * y[1];
     756    result[2] = result[2] + x[2][2] * y[2];
     757    result[2] = result[2] + x[2][3] * y[3];
     758    result[3] = 0;
     759    result[3] = result[3] + x[3][0] * y[0];
     760    result[3] = result[3] + x[3][1] * y[1];
     761    result[3] = result[3] + x[3][2] * y[2];
     762    result[3] = result[3] + x[3][3] * y[3];
     763    return result;
     764}
     765
     766float4x4 mul(float4x4 x, float4x4 y) {
     767    float4x4 result;
     768    result[0][0] = 0;
     769    result[0][0] = result[0][0] + x[0][0] * y[0][0];
     770    result[0][0] = result[0][0] + x[0][1] * y[1][0];
     771    result[0][0] = result[0][0] + x[0][2] * y[2][0];
     772    result[0][0] = result[0][0] + x[0][3] * y[3][0];
     773    result[0][1] = 0;
     774    result[0][1] = result[0][1] + x[0][0] * y[0][1];
     775    result[0][1] = result[0][1] + x[0][1] * y[1][1];
     776    result[0][1] = result[0][1] + x[0][2] * y[2][1];
     777    result[0][1] = result[0][1] + x[0][3] * y[3][1];
     778    result[0][2] = 0;
     779    result[0][2] = result[0][2] + x[0][0] * y[0][2];
     780    result[0][2] = result[0][2] + x[0][1] * y[1][2];
     781    result[0][2] = result[0][2] + x[0][2] * y[2][2];
     782    result[0][2] = result[0][2] + x[0][3] * y[3][2];
     783    result[0][3] = 0;
     784    result[0][3] = result[0][3] + x[0][0] * y[0][3];
     785    result[0][3] = result[0][3] + x[0][1] * y[1][3];
     786    result[0][3] = result[0][3] + x[0][2] * y[2][3];
     787    result[0][3] = result[0][3] + x[0][3] * y[3][3];
     788    result[1][0] = 0;
     789    result[1][0] = result[1][0] + x[1][0] * y[0][0];
     790    result[1][0] = result[1][0] + x[1][1] * y[1][0];
     791    result[1][0] = result[1][0] + x[1][2] * y[2][0];
     792    result[1][0] = result[1][0] + x[1][3] * y[3][0];
     793    result[1][1] = 0;
     794    result[1][1] = result[1][1] + x[1][0] * y[0][1];
     795    result[1][1] = result[1][1] + x[1][1] * y[1][1];
     796    result[1][1] = result[1][1] + x[1][2] * y[2][1];
     797    result[1][1] = result[1][1] + x[1][3] * y[3][1];
     798    result[1][2] = 0;
     799    result[1][2] = result[1][2] + x[1][0] * y[0][2];
     800    result[1][2] = result[1][2] + x[1][1] * y[1][2];
     801    result[1][2] = result[1][2] + x[1][2] * y[2][2];
     802    result[1][2] = result[1][2] + x[1][3] * y[3][2];
     803    result[1][3] = 0;
     804    result[1][3] = result[1][3] + x[1][0] * y[0][3];
     805    result[1][3] = result[1][3] + x[1][1] * y[1][3];
     806    result[1][3] = result[1][3] + x[1][2] * y[2][3];
     807    result[1][3] = result[1][3] + x[1][3] * y[3][3];
     808    result[2][0] = 0;
     809    result[2][0] = result[2][0] + x[2][0] * y[0][0];
     810    result[2][0] = result[2][0] + x[2][1] * y[1][0];
     811    result[2][0] = result[2][0] + x[2][2] * y[2][0];
     812    result[2][0] = result[2][0] + x[2][3] * y[3][0];
     813    result[2][1] = 0;
     814    result[2][1] = result[2][1] + x[2][0] * y[0][1];
     815    result[2][1] = result[2][1] + x[2][1] * y[1][1];
     816    result[2][1] = result[2][1] + x[2][2] * y[2][1];
     817    result[2][1] = result[2][1] + x[2][3] * y[3][1];
     818    result[2][2] = 0;
     819    result[2][2] = result[2][2] + x[2][0] * y[0][2];
     820    result[2][2] = result[2][2] + x[2][1] * y[1][2];
     821    result[2][2] = result[2][2] + x[2][2] * y[2][2];
     822    result[2][2] = result[2][2] + x[2][3] * y[3][2];
     823    result[2][3] = 0;
     824    result[2][3] = result[2][3] + x[2][0] * y[0][3];
     825    result[2][3] = result[2][3] + x[2][1] * y[1][3];
     826    result[2][3] = result[2][3] + x[2][2] * y[2][3];
     827    result[2][3] = result[2][3] + x[2][3] * y[3][3];
     828    result[3][0] = 0;
     829    result[3][0] = result[3][0] + x[3][0] * y[0][0];
     830    result[3][0] = result[3][0] + x[3][1] * y[1][0];
     831    result[3][0] = result[3][0] + x[3][2] * y[2][0];
     832    result[3][0] = result[3][0] + x[3][3] * y[3][0];
     833    result[3][1] = 0;
     834    result[3][1] = result[3][1] + x[3][0] * y[0][1];
     835    result[3][1] = result[3][1] + x[3][1] * y[1][1];
     836    result[3][1] = result[3][1] + x[3][2] * y[2][1];
     837    result[3][1] = result[3][1] + x[3][3] * y[3][1];
     838    result[3][2] = 0;
     839    result[3][2] = result[3][2] + x[3][0] * y[0][2];
     840    result[3][2] = result[3][2] + x[3][1] * y[1][2];
     841    result[3][2] = result[3][2] + x[3][2] * y[2][2];
     842    result[3][2] = result[3][2] + x[3][3] * y[3][2];
     843    result[3][3] = 0;
     844    result[3][3] = result[3][3] + x[3][0] * y[0][3];
     845    result[3][3] = result[3][3] + x[3][1] * y[1][3];
     846    result[3][3] = result[3][3] + x[3][2] * y[2][3];
     847    result[3][3] = result[3][3] + x[3][3] * y[3][3];
     848    return result;
     849}
     850
    628851// FIXME: https://bugs.webkit.org/show_bug.cgi?id=192890 Insert the rest of the standard library once the parser is fast enough
Note: See TracChangeset for help on using the changeset viewer.