[WHLSL] Parsing and lexing the standard library is slow
[WebKit-https.git] / Source / WebCore / Modules / webgpu / WHLSL / WHLSLPrepare.cpp
1 /*
2  * Copyright (C) 2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WHLSLPrepare.h"
28
29 #if ENABLE(WEBGPU)
30
31 #include "WHLSLASTDumper.h"
32 #include "WHLSLCheckDuplicateFunctions.h"
33 #include "WHLSLChecker.h"
34 #include "WHLSLFunctionStageChecker.h"
35 #include "WHLSLHighZombieFinder.h"
36 #include "WHLSLLiteralTypeChecker.h"
37 #include "WHLSLMetalCodeGenerator.h"
38 #include "WHLSLNameResolver.h"
39 #include "WHLSLParser.h"
40 #include "WHLSLPreserveVariableLifetimes.h"
41 #include "WHLSLProgram.h"
42 #include "WHLSLPropertyResolver.h"
43 #include "WHLSLRecursionChecker.h"
44 #include "WHLSLRecursiveTypeChecker.h"
45 #include "WHLSLSemanticMatcher.h"
46 #include "WHLSLStandardLibrary.h"
47 #include "WHLSLStatementBehaviorChecker.h"
48 #include "WHLSLSynthesizeArrayOperatorLength.h"
49 #include "WHLSLSynthesizeConstructors.h"
50 #include "WHLSLSynthesizeEnumerationFunctions.h"
51 #include "WHLSLSynthesizeStructureAccessors.h"
52 #include <wtf/Optional.h>
53
54 namespace WebCore {
55
56 namespace WHLSL {
57
58 static constexpr bool dumpASTBeforeEachPass = false;
59 static constexpr bool dumpASTAfterParsing = false;
60 static constexpr bool dumpASTAtEnd = false;
61 static constexpr bool alwaysDumpPassFailures = true;
62 static constexpr bool dumpPassFailure = dumpASTBeforeEachPass || dumpASTAfterParsing || dumpASTAtEnd || alwaysDumpPassFailures;
63
64 static bool dumpASTIfNeeded(bool shouldDump, Program& program, const char* message)
65 {
66     if (shouldDump) {
67         dataLogLn(message);
68         dumpAST(program);
69         return true;
70     }
71
72     return false;
73 }
74
75 static bool dumpASTAfterParsingIfNeeded(Program& program)
76 {
77     return dumpASTIfNeeded(dumpASTAfterParsing, program, "AST after parsing");
78 }
79
80 static bool dumpASTBetweenEachPassIfNeeded(Program& program, const char* message)
81 {
82     return dumpASTIfNeeded(dumpASTBeforeEachPass, program, message);
83 }
84
85 static bool dumpASTAtEndIfNeeded(Program& program)
86 {
87     return dumpASTIfNeeded(dumpASTAtEnd, program, "AST at end");
88 }
89
90 #define RUN_PASS(pass, ...) \
91     do { \
92         dumpASTBetweenEachPassIfNeeded(program, "AST before " # pass); \
93         if (!pass(__VA_ARGS__)) { \
94             if (dumpPassFailure) \
95                 dataLogLn("failed pass: " # pass); \
96             return WTF::nullopt; \
97         } \
98     } while (0)
99     
100
101 static Optional<Program> prepareShared(String& whlslSource)
102 {
103     Program program;
104     Parser parser;
105     auto standardLibrary = String::fromUTF8(WHLSLStandardLibrary, sizeof(WHLSLStandardLibrary));
106     auto parseStdLibFailure = parser.parse(program, standardLibrary, Parser::Mode::StandardLibrary);
107     if (!ASSERT_DISABLED && parseStdLibFailure) {
108         dataLogLn("failed to parse the standard library: ", *parseStdLibFailure);
109         RELEASE_ASSERT_NOT_REACHED();
110     }
111     if (auto parseFailure = parser.parse(program, whlslSource, Parser::Mode::User)) {
112         if (dumpPassFailure)
113             dataLogLn("failed to parse the program: ", *parseFailure);
114         return WTF::nullopt;
115     }
116
117     if (!dumpASTBetweenEachPassIfNeeded(program, "AST after parsing"))
118         dumpASTAfterParsingIfNeeded(program);
119
120     NameResolver nameResolver(program.nameContext());
121     RUN_PASS(resolveNamesInTypes, program, nameResolver);
122     RUN_PASS(checkRecursiveTypes, program);
123     RUN_PASS(synthesizeStructureAccessors, program);
124     RUN_PASS(synthesizeEnumerationFunctions, program);
125     RUN_PASS(synthesizeArrayOperatorLength, program);
126     RUN_PASS(synthesizeConstructors, program);
127     RUN_PASS(resolveNamesInFunctions, program, nameResolver);
128     RUN_PASS(checkDuplicateFunctions, program);
129
130     RUN_PASS(check, program);
131
132     checkLiteralTypes(program);
133     resolveProperties(program);
134     findHighZombies(program);
135     RUN_PASS(checkStatementBehavior, program);
136     RUN_PASS(checkRecursion, program);
137     RUN_PASS(checkFunctionStages, program);
138     preserveVariableLifetimes(program);
139
140     dumpASTAtEndIfNeeded(program);
141
142     return program;
143 }
144
145 Optional<RenderPrepareResult> prepare(String& whlslSource, RenderPipelineDescriptor& renderPipelineDescriptor)
146 {
147     auto program = prepareShared(whlslSource);
148     if (!program)
149         return WTF::nullopt;
150     auto matchedSemantics = matchSemantics(*program, renderPipelineDescriptor);
151     if (!matchedSemantics)
152         return WTF::nullopt;
153
154     auto generatedCode = Metal::generateMetalCode(*program, WTFMove(*matchedSemantics), renderPipelineDescriptor.layout);
155
156     RenderPrepareResult result;
157     result.metalSource = WTFMove(generatedCode.metalSource);
158     result.mangledVertexEntryPointName = WTFMove(generatedCode.mangledVertexEntryPointName);
159     result.mangledFragmentEntryPointName = WTFMove(generatedCode.mangledFragmentEntryPointName);
160     return result;
161 }
162
163 Optional<ComputePrepareResult> prepare(String& whlslSource, ComputePipelineDescriptor& computePipelineDescriptor)
164 {
165     auto program = prepareShared(whlslSource);
166     if (!program)
167         return WTF::nullopt;
168     auto matchedSemantics = matchSemantics(*program, computePipelineDescriptor);
169     if (!matchedSemantics)
170         return WTF::nullopt;
171
172     auto generatedCode = Metal::generateMetalCode(*program, WTFMove(*matchedSemantics), computePipelineDescriptor.layout);
173
174     ComputePrepareResult result;
175     result.metalSource = WTFMove(generatedCode.metalSource);
176     result.mangledEntryPointName = WTFMove(generatedCode.mangledEntryPointName);
177     return result;
178 }
179
180 } // namespace WHLSL
181
182 } // namespace WebCore
183
184 #endif // ENABLE(WEBGPU)