blob: d6b2e74d0b264e6c9fef1ad8cd1050ebdce0958e [file] [log] [blame]
/*
* Copyright (C) 2019 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:
* 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 INC. 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 INC. 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.
*/
#include "config.h"
#include "WHLSLPrepare.h"
#if ENABLE(WEBGPU)
#include "WHLSLASTDumper.h"
#include "WHLSLAutoInitializeVariables.h"
#include "WHLSLCheckDuplicateFunctions.h"
#include "WHLSLChecker.h"
#include "WHLSLComputeDimensions.h"
#include "WHLSLFunctionStageChecker.h"
#include "WHLSLHighZombieFinder.h"
#include "WHLSLLiteralTypeChecker.h"
#include "WHLSLMetalCodeGenerator.h"
#include "WHLSLNameResolver.h"
#include "WHLSLParser.h"
#include "WHLSLPreserveVariableLifetimes.h"
#include "WHLSLProgram.h"
#include "WHLSLPropertyResolver.h"
#include "WHLSLRecursionChecker.h"
#include "WHLSLRecursiveTypeChecker.h"
#include "WHLSLSemanticMatcher.h"
#include "WHLSLStandardLibrary.h"
#include "WHLSLStatementBehaviorChecker.h"
#include "WHLSLSynthesizeArrayOperatorLength.h"
#include "WHLSLSynthesizeConstructors.h"
#include "WHLSLSynthesizeEnumerationFunctions.h"
#include "WHLSLSynthesizeStructureAccessors.h"
#include <wtf/Optional.h>
namespace WebCore {
namespace WHLSL {
static constexpr bool dumpASTBeforeEachPass = false;
static constexpr bool dumpASTAfterParsing = false;
static constexpr bool dumpASTAtEnd = false;
static constexpr bool alwaysDumpPassFailures = false;
static constexpr bool dumpPassFailure = dumpASTBeforeEachPass || dumpASTAfterParsing || dumpASTAtEnd || alwaysDumpPassFailures;
static bool dumpASTIfNeeded(bool shouldDump, Program& program, const char* message)
{
if (shouldDump) {
dataLogLn(message);
dumpAST(program);
return true;
}
return false;
}
static bool dumpASTAfterParsingIfNeeded(Program& program)
{
return dumpASTIfNeeded(dumpASTAfterParsing, program, "AST after parsing");
}
static bool dumpASTBetweenEachPassIfNeeded(Program& program, const char* message)
{
return dumpASTIfNeeded(dumpASTBeforeEachPass, program, message);
}
static bool dumpASTAtEndIfNeeded(Program& program)
{
return dumpASTIfNeeded(dumpASTAtEnd, program, "AST at end");
}
#define RUN_PASS(pass, ...) \
do { \
dumpASTBetweenEachPassIfNeeded(program, "AST before " # pass); \
if (!pass(__VA_ARGS__)) { \
if (dumpPassFailure) \
dataLogLn("failed pass: " # pass); \
return WTF::nullopt; \
} \
} while (0)
static Optional<Program> prepareShared(String& whlslSource)
{
Program program;
Parser parser;
auto standardLibrary = String::fromUTF8(WHLSLStandardLibrary, sizeof(WHLSLStandardLibrary));
auto parseStdLibFailure = parser.parse(program, standardLibrary, Parser::Mode::StandardLibrary);
if (!ASSERT_DISABLED && parseStdLibFailure) {
dataLogLn("failed to parse the standard library: ", *parseStdLibFailure);
RELEASE_ASSERT_NOT_REACHED();
}
if (auto parseFailure = parser.parse(program, whlslSource, Parser::Mode::User)) {
if (dumpPassFailure)
dataLogLn("failed to parse the program: ", *parseFailure);
return WTF::nullopt;
}
if (!dumpASTBetweenEachPassIfNeeded(program, "AST after parsing"))
dumpASTAfterParsingIfNeeded(program);
NameResolver nameResolver(program.nameContext());
RUN_PASS(resolveNamesInTypes, program, nameResolver);
RUN_PASS(checkRecursiveTypes, program);
RUN_PASS(synthesizeStructureAccessors, program);
RUN_PASS(synthesizeEnumerationFunctions, program);
RUN_PASS(synthesizeArrayOperatorLength, program);
RUN_PASS(synthesizeConstructors, program);
RUN_PASS(resolveNamesInFunctions, program, nameResolver);
RUN_PASS(checkDuplicateFunctions, program);
RUN_PASS(check, program);
checkLiteralTypes(program);
autoInitializeVariables(program);
resolveProperties(program);
findHighZombies(program);
RUN_PASS(checkStatementBehavior, program);
RUN_PASS(checkRecursion, program);
RUN_PASS(checkFunctionStages, program);
preserveVariableLifetimes(program);
dumpASTAtEndIfNeeded(program);
return program;
}
Optional<RenderPrepareResult> prepare(String& whlslSource, RenderPipelineDescriptor& renderPipelineDescriptor)
{
auto program = prepareShared(whlslSource);
if (!program)
return WTF::nullopt;
auto matchedSemantics = matchSemantics(*program, renderPipelineDescriptor);
if (!matchedSemantics)
return WTF::nullopt;
auto generatedCode = Metal::generateMetalCode(*program, WTFMove(*matchedSemantics), renderPipelineDescriptor.layout);
RenderPrepareResult result;
result.metalSource = WTFMove(generatedCode.metalSource);
result.mangledVertexEntryPointName = WTFMove(generatedCode.mangledVertexEntryPointName);
result.mangledFragmentEntryPointName = WTFMove(generatedCode.mangledFragmentEntryPointName);
return result;
}
Optional<ComputePrepareResult> prepare(String& whlslSource, ComputePipelineDescriptor& computePipelineDescriptor)
{
auto program = prepareShared(whlslSource);
if (!program)
return WTF::nullopt;
auto matchedSemantics = matchSemantics(*program, computePipelineDescriptor);
if (!matchedSemantics)
return WTF::nullopt;
auto computeDimensions = WHLSL::computeDimensions(*program, *matchedSemantics->shader);
if (!computeDimensions)
return WTF::nullopt;
auto generatedCode = Metal::generateMetalCode(*program, WTFMove(*matchedSemantics), computePipelineDescriptor.layout);
ComputePrepareResult result;
result.metalSource = WTFMove(generatedCode.metalSource);
result.mangledEntryPointName = WTFMove(generatedCode.mangledEntryPointName);
result.computeDimensions = WTFMove(*computeDimensions);
return result;
}
} // namespace WHLSL
} // namespace WebCore
#endif // ENABLE(WEBGPU)