6d5323981bb691f18c2460fa4031fb9d3e162a83
[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 "WHLSLAutoInitializeVariables.h"
33 #include "WHLSLCheckDuplicateFunctions.h"
34 #include "WHLSLChecker.h"
35 #include "WHLSLComputeDimensions.h"
36 #include "WHLSLFunctionStageChecker.h"
37 #include "WHLSLHighZombieFinder.h"
38 #include "WHLSLLiteralTypeChecker.h"
39 #include "WHLSLMetalCodeGenerator.h"
40 #include "WHLSLNameResolver.h"
41 #include "WHLSLParser.h"
42 #include "WHLSLPreserveVariableLifetimes.h"
43 #include "WHLSLProgram.h"
44 #include "WHLSLPropertyResolver.h"
45 #include "WHLSLRecursionChecker.h"
46 #include "WHLSLRecursiveTypeChecker.h"
47 #include "WHLSLSemanticMatcher.h"
48 #include "WHLSLStandardLibrary.h"
49 #include "WHLSLStatementBehaviorChecker.h"
50 #include "WHLSLSynthesizeArrayOperatorLength.h"
51 #include "WHLSLSynthesizeConstructors.h"
52 #include "WHLSLSynthesizeEnumerationFunctions.h"
53 #include "WHLSLSynthesizeStructureAccessors.h"
54 #include <wtf/Optional.h>
55
56 namespace WebCore {
57
58 namespace WHLSL {
59
60 static constexpr bool dumpASTBeforeEachPass = false;
61 static constexpr bool dumpASTAfterParsing = false;
62 static constexpr bool dumpASTAtEnd = false;
63 static constexpr bool alwaysDumpPassFailures = false;
64 static constexpr bool dumpPassFailure = dumpASTBeforeEachPass || dumpASTAfterParsing || dumpASTAtEnd || alwaysDumpPassFailures;
65
66 static bool dumpASTIfNeeded(bool shouldDump, Program& program, const char* message)
67 {
68     if (shouldDump) {
69         dataLogLn(message);
70         dumpAST(program);
71         return true;
72     }
73
74     return false;
75 }
76
77 static bool dumpASTAfterParsingIfNeeded(Program& program)
78 {
79     return dumpASTIfNeeded(dumpASTAfterParsing, program, "AST after parsing");
80 }
81
82 static bool dumpASTBetweenEachPassIfNeeded(Program& program, const char* message)
83 {
84     return dumpASTIfNeeded(dumpASTBeforeEachPass, program, message);
85 }
86
87 static bool dumpASTAtEndIfNeeded(Program& program)
88 {
89     return dumpASTIfNeeded(dumpASTAtEnd, program, "AST at end");
90 }
91
92 #define RUN_PASS(pass, ...) \
93     do { \
94         dumpASTBetweenEachPassIfNeeded(program, "AST before " # pass); \
95         if (!pass(__VA_ARGS__)) { \
96             if (dumpPassFailure) \
97                 dataLogLn("failed pass: " # pass); \
98             return WTF::nullopt; \
99         } \
100     } while (0)
101     
102
103 static Optional<Program> prepareShared(String& whlslSource)
104 {
105     Program program;
106     Parser parser;
107     auto standardLibrary = String::fromUTF8(WHLSLStandardLibrary, sizeof(WHLSLStandardLibrary));
108     auto parseStdLibFailure = parser.parse(program, standardLibrary, Parser::Mode::StandardLibrary);
109     if (!ASSERT_DISABLED && parseStdLibFailure) {
110         dataLogLn("failed to parse the standard library: ", *parseStdLibFailure);
111         RELEASE_ASSERT_NOT_REACHED();
112     }
113     if (auto parseFailure = parser.parse(program, whlslSource, Parser::Mode::User)) {
114         if (dumpPassFailure)
115             dataLogLn("failed to parse the program: ", *parseFailure);
116         return WTF::nullopt;
117     }
118
119     if (!dumpASTBetweenEachPassIfNeeded(program, "AST after parsing"))
120         dumpASTAfterParsingIfNeeded(program);
121
122     NameResolver nameResolver(program.nameContext());
123     RUN_PASS(resolveNamesInTypes, program, nameResolver);
124     RUN_PASS(checkRecursiveTypes, program);
125     RUN_PASS(synthesizeStructureAccessors, program);
126     RUN_PASS(synthesizeEnumerationFunctions, program);
127     RUN_PASS(synthesizeArrayOperatorLength, program);
128     RUN_PASS(resolveTypeNamesInFunctions, program, nameResolver);
129     RUN_PASS(synthesizeConstructors, program);
130     RUN_PASS(resolveCallsInFunctions, program, nameResolver);
131     RUN_PASS(checkDuplicateFunctions, program);
132
133     RUN_PASS(check, program);
134
135     checkLiteralTypes(program);
136     autoInitializeVariables(program);
137     resolveProperties(program);
138     findHighZombies(program);
139     RUN_PASS(checkStatementBehavior, program);
140     RUN_PASS(checkRecursion, program);
141     RUN_PASS(checkFunctionStages, program);
142     preserveVariableLifetimes(program);
143
144     dumpASTAtEndIfNeeded(program);
145
146     return program;
147 }
148
149 Optional<RenderPrepareResult> prepare(String& whlslSource, RenderPipelineDescriptor& renderPipelineDescriptor)
150 {
151     auto program = prepareShared(whlslSource);
152     if (!program)
153         return WTF::nullopt;
154     auto matchedSemantics = matchSemantics(*program, renderPipelineDescriptor);
155     if (!matchedSemantics)
156         return WTF::nullopt;
157
158     auto generatedCode = Metal::generateMetalCode(*program, WTFMove(*matchedSemantics), renderPipelineDescriptor.layout);
159
160     RenderPrepareResult result;
161     result.metalSource = WTFMove(generatedCode.metalSource);
162     result.mangledVertexEntryPointName = WTFMove(generatedCode.mangledVertexEntryPointName);
163     result.mangledFragmentEntryPointName = WTFMove(generatedCode.mangledFragmentEntryPointName);
164     return result;
165 }
166
167 Optional<ComputePrepareResult> prepare(String& whlslSource, ComputePipelineDescriptor& computePipelineDescriptor)
168 {
169     auto program = prepareShared(whlslSource);
170     if (!program)
171         return WTF::nullopt;
172     auto matchedSemantics = matchSemantics(*program, computePipelineDescriptor);
173     if (!matchedSemantics)
174         return WTF::nullopt;
175     auto computeDimensions = WHLSL::computeDimensions(*program, *matchedSemantics->shader);
176     if (!computeDimensions)
177         return WTF::nullopt;
178
179     auto generatedCode = Metal::generateMetalCode(*program, WTFMove(*matchedSemantics), computePipelineDescriptor.layout);
180
181     ComputePrepareResult result;
182     result.metalSource = WTFMove(generatedCode.metalSource);
183     result.mangledEntryPointName = WTFMove(generatedCode.mangledEntryPointName);
184     result.computeDimensions = WTFMove(*computeDimensions);
185     return result;
186 }
187
188 } // namespace WHLSL
189
190 } // namespace WebCore
191
192 #endif // ENABLE(WEBGPU)