blob: 8adad8eaa0de2bc183a764a335fcff45320e5319 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Mike Klein6ad99092016-10-26 10:35:22 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -07009
John Stilesfbd050b2020-08-03 13:21:46 -040010#include <memory>
John Stilesb8e010c2020-08-11 18:05:39 -040011#include <unordered_set>
John Stilesfbd050b2020-08-03 13:21:46 -040012
John Stiles270cec22021-02-17 12:59:36 -050013#include "src/core/SkScopeExit.h"
Leon Scrogginsb66214e2021-02-11 17:14:18 -050014#include "src/core/SkTraceEvent.h"
John Stilesb92641c2020-08-31 18:09:01 -040015#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/sksl/SkSLCFGGenerator.h"
17#include "src/sksl/SkSLCPPCodeGenerator.h"
18#include "src/sksl/SkSLGLSLCodeGenerator.h"
19#include "src/sksl/SkSLHCodeGenerator.h"
20#include "src/sksl/SkSLIRGenerator.h"
21#include "src/sksl/SkSLMetalCodeGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050022#include "src/sksl/SkSLOperators.h"
John Stiles270cec22021-02-17 12:59:36 -050023#include "src/sksl/SkSLProgramSettings.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040024#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050026#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "src/sksl/ir/SkSLEnum.h"
28#include "src/sksl/ir/SkSLExpression.h"
29#include "src/sksl/ir/SkSLExpressionStatement.h"
30#include "src/sksl/ir/SkSLFunctionCall.h"
31#include "src/sksl/ir/SkSLIntLiteral.h"
32#include "src/sksl/ir/SkSLModifiersDeclaration.h"
33#include "src/sksl/ir/SkSLNop.h"
34#include "src/sksl/ir/SkSLSymbolTable.h"
35#include "src/sksl/ir/SkSLTernaryExpression.h"
36#include "src/sksl/ir/SkSLUnresolvedFunction.h"
37#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040038#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070039
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040040#include <fstream>
41
Ethan Nicholasa11035b2019-11-26 16:27:47 -050042#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
43#include "include/gpu/GrContextOptions.h"
44#include "src/gpu/GrShaderCaps.h"
45#endif
46
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040047#ifdef SK_ENABLE_SPIRV_VALIDATION
48#include "spirv-tools/libspirv.hpp"
49#endif
50
Brian Osman3d87e9f2020-10-08 11:50:22 -040051#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040052
Brian Osman3d87e9f2020-10-08 11:50:22 -040053// In standalone mode, we load the textual sksl source files. GN generates or copies these files
54// to the skslc executable directory. The "data" in this mode is just the filename.
55#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
56
57#else
58
59// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040060#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
61#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
62#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
63#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050064#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050065#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040066#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
67
Brian Osman3d87e9f2020-10-08 11:50:22 -040068#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
69 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040070
71#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040072
ethannicholasb3058bd2016-07-01 08:22:01 -070073namespace SkSL {
74
John Stiles8ef4d6c2021-03-05 16:01:45 -050075// TODO(skia:11319): Set to `false` to disable control-flow analysis unilaterally.
76bool gSkSLControlFlowAnalysis = true;
77
John Stiles47c0a742021-02-09 09:30:35 -050078using RefKind = VariableReference::RefKind;
79
Brian Osman88cda172020-10-09 12:05:16 -040080class AutoSource {
81public:
82 AutoSource(Compiler* compiler, const String* source)
83 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
84 fCompiler->fSource = source;
85 }
86
87 ~AutoSource() { fCompiler->fSource = fOldSource; }
88
89 Compiler* fCompiler;
90 const String* fOldSource;
91};
92
John Stilesa935c3f2021-02-25 10:35:49 -050093class AutoProgramConfig {
94public:
95 AutoProgramConfig(std::shared_ptr<Context>& context, ProgramConfig* config)
96 : fContext(context.get()) {
97 SkASSERT(!fContext->fConfig);
98 fContext->fConfig = config;
99 }
100
101 ~AutoProgramConfig() {
102 fContext->fConfig = nullptr;
103 }
104
105 Context* fContext;
106};
107
John Stilesd6a5f4492021-02-11 15:46:11 -0500108Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesc1a98b82021-02-24 13:35:02 -0500109 : fContext(std::make_shared<Context>(/*errors=*/*this, *caps))
John Stiles7b920442020-12-17 10:43:41 -0500110 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -0500111 , fErrorCount(0) {
John Stilesc1a98b82021-02-24 13:35:02 -0500112 SkASSERT(caps);
John Stiles7c3515b2020-10-16 18:38:39 -0400113 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -0500114 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesc1a98b82021-02-24 13:35:02 -0500115 fIRGenerator = std::make_unique<IRGenerator>(fContext.get());
ethannicholasb3058bd2016-07-01 08:22:01 -0700116
John Stiles54e7c052021-01-11 14:22:36 -0500117#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700118
Brian Osmanb06301e2020-11-06 11:45:36 -0500119 const SkSL::Symbol* rootTypes[] = {
120 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500121
Brian Osmanb06301e2020-11-06 11:45:36 -0500122 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
123 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
124 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500125 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500126
Brian Osmanc0f2b642020-12-22 13:35:55 -0500127 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500128 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500129
Brian Osmanc63f4312020-12-23 11:44:14 -0500130 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700131
Brian Osman20fad322020-12-23 12:42:33 -0500132 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
133 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500134
135 TYPE(FragmentProcessor),
136 };
137
138 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500139 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
140 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
141 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
142 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
143 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
144
145 TYPE(GenUType), TYPE(UVec),
146 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
147
Brian Osmanc0f2b642020-12-22 13:35:55 -0500148 TYPE(Float2x3), TYPE(Float2x4),
149 TYPE(Float3x2), TYPE(Float3x4),
150 TYPE(Float4x2), TYPE(Float4x3),
151
Brian Osmanc63f4312020-12-23 11:44:14 -0500152 TYPE(Half2x3), TYPE(Half2x4),
153 TYPE(Half3x2), TYPE(Half3x4),
154 TYPE(Half4x2), TYPE(Half4x3),
155
Brian Osmanc0f2b642020-12-22 13:35:55 -0500156 TYPE(Mat), TYPE(HMat),
157
Brian Osmanb06301e2020-11-06 11:45:36 -0500158 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
159 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500160 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500161
162 TYPE(ISampler2D),
Brian Osmanb06301e2020-11-06 11:45:36 -0500163 TYPE(SubpassInput), TYPE(SubpassInputMS),
164
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 TYPE(Sampler),
166 TYPE(Texture2D),
167 };
168
169 for (const SkSL::Symbol* type : rootTypes) {
170 fRootSymbolTable->addWithoutOwnership(type);
171 }
172 for (const SkSL::Symbol* type : privateTypes) {
173 fPrivateSymbolTable->addWithoutOwnership(type);
174 }
175
176#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700177
Brian Osman3887a012020-09-30 13:22:27 -0400178 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
179 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500180 fPrivateSymbolTable->add(
181 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500182 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500183 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500184 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500185 /*builtin=*/false,
186 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500187
Brian Osman3d87e9f2020-10-08 11:50:22 -0400188 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500189 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700190}
191
John Stilesdd13dba2020-10-29 10:45:34 -0400192Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700193
Brian Osman56269982020-11-20 12:38:07 -0500194const ParsedModule& Compiler::loadGPUModule() {
195 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500196 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500197 }
198 return fGPUModule;
199}
200
201const ParsedModule& Compiler::loadFragmentModule() {
202 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500203 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500204 this->loadGPUModule());
205 }
206 return fFragmentModule;
207}
208
209const ParsedModule& Compiler::loadVertexModule() {
210 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500211 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500212 this->loadGPUModule());
213 }
214 return fVertexModule;
215}
216
Brian Osman88cda172020-10-09 12:05:16 -0400217const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400218 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500219 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500220 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400221 }
Brian Osman88cda172020-10-09 12:05:16 -0400222 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400223}
224
Brian Osman88cda172020-10-09 12:05:16 -0400225const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400226 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500227 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500228 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400229 }
Brian Osman88cda172020-10-09 12:05:16 -0400230 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400231}
232
Brian Osmanb06301e2020-11-06 11:45:36 -0500233const ParsedModule& Compiler::loadPublicModule() {
234 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500235 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500236 }
237 return fPublicModule;
238}
239
Brian Osman91946752020-12-21 13:20:40 -0500240const ParsedModule& Compiler::loadRuntimeEffectModule() {
241 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500242 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500243 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400244
Brian Osman91946752020-12-21 13:20:40 -0500245 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500246 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400247
John Stiles54e7c052021-01-11 14:22:36 -0500248 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
249 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
250 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400251
John Stiles54e7c052021-01-11 14:22:36 -0500252 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
253 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
254 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400255
John Stiles54e7c052021-01-11 14:22:36 -0500256 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
257 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
258 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400259 }
Brian Osman91946752020-12-21 13:20:40 -0500260 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400261}
262
John Stilesdbd4e6f2021-02-16 13:29:15 -0500263const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400264 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500265 case ProgramKind::kVertex: return this->loadVertexModule(); break;
266 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
267 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
268 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
269 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
270 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400271 }
272 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400273}
274
John Stilesdbd4e6f2021-02-16 13:29:15 -0500275LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400276 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500277 std::shared_ptr<SymbolTable> base,
278 bool dehydrate) {
279 if (dehydrate) {
280 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
281 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
282 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
283 // contain the union of all known types, so this is safe. If we ever have types that only
284 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
285 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500286 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400287 }
John Stilesa935c3f2021-02-25 10:35:49 -0500288 SkASSERT(base);
289
290 // Built-in modules always use default program settings.
291 ProgramConfig config;
292 config.fKind = kind;
293 config.fSettings.fReplaceSettings = !dehydrate;
294 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400295
296#if defined(SKSL_STANDALONE)
297 SkASSERT(data.fPath);
298 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400299 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
300 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400301 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400302 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400303 abort();
304 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400305 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400306 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500307
John Stiles881a10c2020-09-19 10:13:24 -0400308 SkASSERT(fIRGenerator->fCanInline);
309 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500310
Brian Osman88cda172020-10-09 12:05:16 -0400311 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500312 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
313 source->c_str(), source->length(),
314 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400315 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500316 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400317 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400318 if (this->fErrorCount) {
319 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400320 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400321 }
Brian Osman88cda172020-10-09 12:05:16 -0400322 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400323#else
324 SkASSERT(data.fData && (data.fSize != 0));
325 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
326 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500327 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400328 fModifiers.push_back(fIRGenerator->releaseModifiers());
329#endif
330
331 return module;
332}
333
John Stilesdbd4e6f2021-02-16 13:29:15 -0500334ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500335 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500336 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400337
338 // For modules that just declare (but don't define) intrinsic functions, there will be no new
339 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500340 if (module.fElements.empty()) {
341 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400342 }
343
344 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
345
346 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
347 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500348 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400349 switch (element->kind()) {
350 case ProgramElement::Kind::kFunction: {
351 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400352 SkASSERT(f.declaration().isBuiltin());
353 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400354 break;
355 }
John Stiles569249b2020-11-03 12:18:22 -0500356 case ProgramElement::Kind::kFunctionPrototype: {
357 // These are already in the symbol table.
358 break;
359 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400360 case ProgramElement::Kind::kEnum: {
361 const Enum& e = element->as<Enum>();
362 SkASSERT(e.isBuiltin());
363 intrinsics->insertOrDie(e.typeName(), std::move(element));
364 break;
365 }
366 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400367 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
368 const Variable& var = global.declaration()->as<VarDeclaration>().var();
369 SkASSERT(var.isBuiltin());
370 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400371 break;
372 }
373 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400374 const Variable& var = element->as<InterfaceBlock>().variable();
375 SkASSERT(var.isBuiltin());
376 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400377 break;
378 }
379 default:
380 printf("Unsupported element: %s\n", element->description().c_str());
381 SkASSERT(false);
382 break;
383 }
384 }
385
Brian Osman0006ad02020-11-18 15:38:39 -0500386 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400387}
388
John Stilese6150002020-10-05 12:03:53 -0400389void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700390 BasicBlock& block = cfg->fBlocks[blockId];
391
392 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500393 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700394 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500395 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700396 }
397
398 // propagate definitions to exits
399 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400400 if (exitId == blockId) {
401 continue;
402 }
ethannicholas22f939e2016-10-13 13:25:34 -0700403 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500404 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400405 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
406 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400407 // exit has no definition for it, just copy it and reprocess exit block
408 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500409 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700410 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500411 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400412 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700413 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400414 // definition has changed, merge and reprocess the exit block
415 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500416 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400417 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500418 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400419 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500420 }
ethannicholas22f939e2016-10-13 13:25:34 -0700421 }
422 }
John Stiles65b48272020-12-22 17:18:34 -0500423 }
ethannicholas22f939e2016-10-13 13:25:34 -0700424 }
425}
426
Ethan Nicholascb670962017-04-20 19:31:52 -0400427/**
428 * Returns true if assigning to this lvalue has no effect.
429 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400430static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400431 switch (lvalue.kind()) {
432 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400433 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400434 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400435 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400436 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400437 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400438 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400439 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400440 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400441 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400442 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400443 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400444 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400445 return !t.test()->hasSideEffects() &&
446 is_dead(*t.ifTrue(), usage) &&
447 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500448 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400449 default:
John Stileseada7bc2021-02-02 16:29:32 -0500450 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500451 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400452 }
453}
ethannicholas22f939e2016-10-13 13:25:34 -0700454
Ethan Nicholascb670962017-04-20 19:31:52 -0400455/**
456 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
457 * to a dead target and lack of side effects on the left hand side.
458 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400459static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
John Stiles45990502021-02-16 10:55:27 -0500460 if (!b.getOperator().isAssignment()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400461 return false;
462 }
John Stiles2d4f9592020-10-30 10:29:12 -0400463 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400464}
465
John Stiles0ac6c152021-02-10 14:04:24 -0500466static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500467 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles95d0bad2021-03-01 17:02:28 -0500468 Analysis::IsSelfAssignment(*b.left(), *b.right());
John Stiles0ac6c152021-02-10 14:04:24 -0500469}
470
Ethan Nicholascb670962017-04-20 19:31:52 -0400471void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500472 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400473
474 // We set bits in the "processed" set after a block has been scanned.
475 SkBitSet processedSet(cfg->fBlocks.size());
476 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
477 processedSet.set(*blockId);
478 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700479 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400480}
481
482/**
483 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
484 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
485 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
486 * need to be regenerated).
487 */
John Stilesafbf8992020-08-18 10:08:21 -0400488static bool try_replace_expression(BasicBlock* b,
489 std::vector<BasicBlock::Node>::iterator* iter,
490 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400491 std::unique_ptr<Expression>* target = (*iter)->expression();
492 if (!b->tryRemoveExpression(iter)) {
493 *target = std::move(*newExpression);
494 return false;
495 }
496 *target = std::move(*newExpression);
497 return b->tryInsertExpression(iter, target);
498}
499
500/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400501 * Returns true if the expression is a constant numeric literal with the specified value, or a
502 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400503 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400504template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400505static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400506 switch (expr.kind()) {
507 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400508 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400509
Ethan Nicholase6592142020-09-08 10:22:09 -0400510 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400511 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400512
Ethan Nicholase6592142020-09-08 10:22:09 -0400513 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400514 const Constructor& constructor = expr.as<Constructor>();
515 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400516 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400517 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400518 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500519 if (constructor.componentType().isFloat()) {
520 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400521 if (constructor.getFVecComponent(i) != value) {
522 return false;
523 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500524 }
525 return true;
526 } else if (constructor.componentType().isInteger()) {
527 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400528 if (constructor.getIVecComponent(i) != value) {
529 return false;
530 }
531 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500532 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400533 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500534 // Other types (e.g. boolean) might occur, but aren't supported here.
535 return false;
John Stiles9d944232020-08-19 09:56:49 -0400536
Ethan Nicholase6592142020-09-08 10:22:09 -0400537 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400538 SkASSERT(constructor.arguments().size() == 1);
539 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400540
541 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400542 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400543 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400544 }
545 return false;
546 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400547 default:
548 return false;
549 }
550}
551
552/**
553 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
554 * and CFG structures).
555 */
John Stilesafbf8992020-08-18 10:08:21 -0400556static void delete_left(BasicBlock* b,
557 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400558 Compiler::OptimizationContext* optimizationContext) {
559 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400560 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400561 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400562 Expression& left = *bin.left();
563 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400564 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400565 bool result;
John Stiles45990502021-02-16 10:55:27 -0500566 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400567 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400568 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400569 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400570 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400571 // Remove references within LHS.
572 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400573 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400574 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400575 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400576 return;
577 }
578 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400579 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400580 return;
581 }
582 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400583 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400584 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400585 return;
586 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400587 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400588 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400589}
590
591/**
592 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
593 * CFG structures).
594 */
John Stilesafbf8992020-08-18 10:08:21 -0400595static void delete_right(BasicBlock* b,
596 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400597 Compiler::OptimizationContext* optimizationContext) {
598 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400599 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400600 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400601 std::unique_ptr<Expression>& leftPointer = bin.left();
602 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400603 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400604 // Remove references within RHS.
605 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400606 if (!b->tryRemoveExpressionBefore(iter, &right)) {
607 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400608 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400609 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400610 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400611 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400612 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400613 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400614 return;
615 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400616 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400617 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400618 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400619 return;
620 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400621 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400622 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400623}
624
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400625/**
626 * Constructs the specified type using a single argument.
627 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400628static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400629 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400630 args.push_back(std::move(v));
John Stiles54f00492021-02-19 11:46:10 -0500631 return std::make_unique<Constructor>(/*offset=*/-1, *type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400632}
633
634/**
635 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
636 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
637 */
638static void vectorize(BasicBlock* b,
639 std::vector<BasicBlock::Node>::iterator* iter,
640 const Type& type,
641 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400642 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400643 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500644 SkASSERT(type.isVector());
645 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400646 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400647 std::unique_ptr<Expression>* target = (*iter)->expression();
648 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400649 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400650 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400651 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400652 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400653 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400654 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400655 }
656 }
657}
658
659/**
660 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
661 * left to yield vec<n>(x).
662 */
663static void vectorize_left(BasicBlock* b,
664 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400665 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400666 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400667 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400668 optimizationContext->fUsage->remove(bin.right().get());
669 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400670}
671
672/**
673 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
674 * right to yield vec<n>(y).
675 */
676static void vectorize_right(BasicBlock* b,
677 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400678 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400679 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400680 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400681 optimizationContext->fUsage->remove(bin.left().get());
682 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400683}
684
Ethan Nicholascb670962017-04-20 19:31:52 -0400685void Compiler::simplifyExpression(DefinitionMap& definitions,
686 BasicBlock& b,
687 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400688 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400689 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400690 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500691
Ethan Nicholascb670962017-04-20 19:31:52 -0400692 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400693 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
694 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400695 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400696 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400697 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400698 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400699 // Remove references within 'expr', add references within 'optimized'
700 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400701 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400702 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400703 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400704 }
John Stiles70025e52020-09-28 16:08:58 -0400705 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400706 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400707 }
708 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400709 switch (expr->kind()) {
710 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400711 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400712 const Variable* var = ref.variable();
John Stiles8ef4d6c2021-03-05 16:01:45 -0500713 if (gSkSLControlFlowAnalysis &&
714 fContext->fConfig->fSettings.fDeadCodeElimination &&
John Stiles66c53b92021-02-20 08:00:43 -0500715 ref.refKind() != VariableReference::RefKind::kWrite &&
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400716 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500717 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400718 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
719 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000720 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400721 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400722 }
723 break;
724 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400725 case Expression::Kind::kTernary: {
John Stiles28054ad2021-03-05 15:22:48 -0500726 // TODO(skia:11319): this optimization logic is redundant with the optimization code
727 // found in SkSLTernaryExpression.cpp.
728
John Stiles403a3632020-08-20 12:11:48 -0400729 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400730 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400731 // ternary has a constant test, replace it with either the true or
732 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400733 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400734 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400735 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400736 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400737 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400738 optimizationContext->fUpdated = true;
739 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400740 }
741 break;
742 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400743 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400744 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500745 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400746 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400747 break;
748 }
John Stiles8f440b42021-03-05 16:48:56 -0500749
750 // TODO(skia:11319): this optimization logic is redundant with the optimization code
751 // found in ConstantFolder.cpp.
John Stiles2d4f9592020-10-30 10:29:12 -0400752 Expression& left = *bin->left();
753 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400754 const Type& leftType = left.type();
755 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400756 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500757 if ((!leftType.isScalar() && !leftType.isVector()) ||
758 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400759 break;
760 }
John Stiles45990502021-02-16 10:55:27 -0500761 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400762 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400763 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500764 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400765 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400766 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400767 } else {
768 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400769 // 1 * float4(x) -> float4(x)
770 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400771 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400772 }
773 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400774 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500775 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400776 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400777 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400778 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400779 } else {
780 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400781 // float4(0) * x -> float4(0)
782 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400783 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400784 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500785 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400786 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400787 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400788 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500789 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400790 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400791 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400792 } else {
793 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400794 // float4(x) * 1 -> float4(x)
795 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400796 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400797 }
798 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400799 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500800 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400801 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400802 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400803 } else {
804 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400805 // x * float4(0) -> float4(0)
806 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400807 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400808 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500809 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400810 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400811 }
812 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400813 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400814 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500815 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400816 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400817 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400818 } else {
819 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400820 // 0 + float4(x) -> float4(x)
821 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400822 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400823 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400824 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500825 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400826 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400827 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400828 } else {
829 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400830 // float4(x) + 0 -> float4(x)
831 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400832 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400833 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400834 }
835 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400836 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400837 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500838 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400839 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400840 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400841 } else {
842 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400843 // float4(x) - 0 -> float4(x)
844 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400845 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400846 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400847 }
848 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400849 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400850 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500851 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400852 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400853 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400854 } else {
855 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400856 // float4(x) / 1 -> float4(x)
857 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400858 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400859 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400860 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500861 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400862 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400863 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400864 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400865 } else {
866 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400867 // float4(0) / x -> float4(0)
868 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400869 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400870 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500871 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400872 }
873 }
874 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400875 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400876 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500877 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400878 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400879 }
880 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400881 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400882 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500883 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400884 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400885 }
886 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400887 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400888 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500889 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400890 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400891 }
892 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400893 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400894 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500895 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400896 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400897 }
898 break;
899 default:
900 break;
901 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400902 break;
903 }
John Stilesf5c1d042020-11-21 23:26:07 -0500904 case Expression::Kind::kConstructor: {
John Stilesb9e4f642021-03-05 09:11:38 -0500905 // TODO(skia:11319): this optimization logic is redundant with the optimization code
906 // found in SkSLConstructor.cpp.
907
John Stilesf5c1d042020-11-21 23:26:07 -0500908 // Find constructors embedded inside constructors and flatten them out where possible.
909 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
910 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
911 // Leave single-argument constructors alone, though. These might be casts or splats.
912 Constructor& c = expr->as<Constructor>();
913 if (c.type().columns() > 1) {
914 // Inspect each constructor argument to see if it's a candidate for flattening.
915 // Remember matched arguments in a bitfield, "argsToOptimize".
916 int argsToOptimize = 0;
917 int currBit = 1;
918 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
919 if (arg->is<Constructor>()) {
920 Constructor& inner = arg->as<Constructor>();
921 if (inner.arguments().size() > 1 &&
922 inner.type().componentType() == c.type().componentType()) {
923 argsToOptimize |= currBit;
924 }
925 }
926 currBit <<= 1;
927 }
928 if (argsToOptimize) {
929 // We found at least one argument that could be flattened out. Re-walk the
930 // constructor args and flatten the candidates we found during our initial pass.
931 ExpressionArray flattened;
932 flattened.reserve_back(c.type().columns());
933 currBit = 1;
934 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
935 if (argsToOptimize & currBit) {
936 Constructor& inner = arg->as<Constructor>();
937 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
938 flattened.push_back(innerArg->clone());
939 }
940 } else {
941 flattened.push_back(arg->clone());
942 }
943 currBit <<= 1;
944 }
John Stiles54f00492021-02-19 11:46:10 -0500945 std::unique_ptr<Expression> replacement = std::make_unique<Constructor>(
946 c.fOffset, c.type(), std::move(flattened));
John Stiles1b91c0e2021-02-11 11:43:09 -0500947 // We're replacing an expression with a cloned version; we'll need a rescan.
948 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
949 // reference counts.
950 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500951 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500952 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500953 break;
954 }
955 }
956 break;
957 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400958 case Expression::Kind::kSwizzle: {
John Stilesf04e09c2021-03-05 13:13:14 -0500959 // TODO(skia:11319): this optimization logic is redundant with the optimization code
960 // found in SkSLSwizzle.cpp.
961
John Stiles403a3632020-08-20 12:11:48 -0400962 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500963 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400964 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400965 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400966 for (int i = 0; i < (int) s.components().size(); ++i) {
967 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400968 identity = false;
969 break;
970 }
971 }
972 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400973 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400974 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400975 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400976 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400977 return;
978 }
John Stiles70025e52020-09-28 16:08:58 -0400979 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400980 break;
981 }
982 }
John Stiles108bbe22020-11-18 11:10:38 -0500983 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
984 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400985 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400986 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400987 for (int c : s.components()) {
988 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400989 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400990 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400991 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500992 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500993 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500994 try_replace_expression(&b, iter, &replacement);
995 optimizationContext->fUpdated = true;
996 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -0500997 break;
998 }
999 // Optimize swizzles of constructors.
1000 if (s.base()->is<Constructor>()) {
1001 Constructor& base = s.base()->as<Constructor>();
1002 std::unique_ptr<Expression> replacement;
1003 const Type& componentType = base.type().componentType();
1004 int swizzleSize = s.components().size();
1005
1006 // The IR generator has already converted any zero/one swizzle components into
1007 // constructors containing zero/one args. Confirm that this is true by checking that
1008 // our swizzle components are all `xyzw` (values 0 through 3).
1009 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1010 [](int8_t c) { return c >= 0 && c <= 3; }));
1011
John Stiles9aeed132020-11-24 17:36:06 -05001012 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001013 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1014 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001015 const Expression& argument = *base.arguments().front();
1016 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1017 /*rows=*/1);
1018 replacement = Constructor::SimplifyConversion(constructorType, argument);
1019 if (!replacement) {
1020 ExpressionArray newArgs;
1021 newArgs.push_back(argument.clone());
John Stiles54f00492021-02-19 11:46:10 -05001022 replacement = std::make_unique<Constructor>(base.fOffset, constructorType,
John Stilesf0cb7332021-01-08 18:39:00 -05001023 std::move(newArgs));
1024 }
John Stiles108bbe22020-11-18 11:10:38 -05001025
John Stilesa60ac0c2020-12-22 08:59:51 -05001026 // We're replacing an expression with a cloned version; we'll need a rescan.
1027 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1028 // reference counts.
1029 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001030 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001031 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001032 break;
1033 }
1034
John Stiles0777ac42020-11-19 11:06:47 -05001035 // Swizzles can duplicate some elements and discard others, e.g.
1036 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1037 // - Expressions with side effects need to occur exactly once, even if they
1038 // would otherwise be swizzle-eliminated
1039 // - Non-trivial expressions should not be repeated, but elimination is OK.
1040 //
1041 // Look up the argument for the constructor at each index. This is typically simple
1042 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1043 // seems. This example would result in:
1044 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1045 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1046 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1047 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1048 struct ConstructorArgMap {
1049 int8_t fArgIndex;
1050 int8_t fComponent;
1051 };
1052
1053 int numConstructorArgs = base.type().columns();
1054 ConstructorArgMap argMap[4] = {};
1055 int writeIdx = 0;
1056 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1057 const Expression& expr = *base.arguments()[argIdx];
1058 int argWidth = expr.type().columns();
1059 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1060 argMap[writeIdx].fArgIndex = argIdx;
1061 argMap[writeIdx].fComponent = componentIdx;
1062 ++writeIdx;
1063 }
1064 }
1065 SkASSERT(writeIdx == numConstructorArgs);
1066
1067 // Count up the number of times each constructor argument is used by the
1068 // swizzle.
1069 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1070 // - bar.yz is referenced 3 times, by `.x_xy`
1071 // - half(foo) is referenced 1 time, by `._w__`
1072 int8_t exprUsed[4] = {};
1073 for (int c : s.components()) {
1074 exprUsed[argMap[c].fArgIndex]++;
1075 }
1076
1077 bool safeToOptimize = true;
1078 for (int index = 0; index < numConstructorArgs; ++index) {
1079 int8_t constructorArgIndex = argMap[index].fArgIndex;
1080 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1081
1082 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001083 if (exprUsed[constructorArgIndex] > 1 &&
1084 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001085 safeToOptimize = false;
1086 break;
1087 }
1088 // Check that side-effect-bearing expressions are swizzled in exactly once.
1089 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1090 safeToOptimize = false;
1091 break;
1092 }
1093 }
1094
1095 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001096 struct ReorderedArgument {
1097 int8_t fArgIndex;
1098 ComponentArray fComponents;
1099 };
1100 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001101 for (int c : s.components()) {
1102 const ConstructorArgMap& argument = argMap[c];
1103 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1104
John Stiles9aeed132020-11-24 17:36:06 -05001105 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001106 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001107 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001108 reorderedArgs.push_back({argument.fArgIndex,
1109 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001110 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001111 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001112 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001113 if (reorderedArgs.empty() ||
1114 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1115 // This can't be combined with the previous argument. Add a new one.
1116 reorderedArgs.push_back({argument.fArgIndex,
1117 ComponentArray{argument.fComponent}});
1118 } else {
1119 // Since we know this argument uses components, it should already
1120 // have at least one component set.
1121 SkASSERT(!reorderedArgs.back().fComponents.empty());
1122 // Build up the current argument with one more component.
1123 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1124 }
John Stiles0777ac42020-11-19 11:06:47 -05001125 }
1126 }
John Stilesd9076cb2020-11-19 12:18:36 -05001127
1128 // Convert our reordered argument list to an actual array of expressions, with
1129 // the new order and any new inner swizzles that need to be applied. Note that
1130 // we expect followup passes to clean up the inner swizzles.
1131 ExpressionArray newArgs;
1132 newArgs.reserve_back(swizzleSize);
1133 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1134 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1135 if (reorderedArg.fComponents.empty()) {
1136 newArgs.push_back(baseArg.clone());
1137 } else {
1138 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1139 reorderedArg.fComponents));
1140 }
1141 }
1142
1143 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001144 replacement = std::make_unique<Constructor>(
1145 base.fOffset,
John Stiles54f00492021-02-19 11:46:10 -05001146 componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
John Stiles0777ac42020-11-19 11:06:47 -05001147 std::move(newArgs));
1148
John Stilesa60ac0c2020-12-22 08:59:51 -05001149 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001150 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001151
1152 // We're replacing an expression with a cloned version; we'll need a rescan.
1153 try_replace_expression(&b, iter, &replacement);
1154 optimizationContext->fUpdated = true;
1155 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001156 }
John Stiles108bbe22020-11-18 11:10:38 -05001157 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001158 }
John Stiles30212b72020-06-11 17:55:07 -04001159 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001160 }
1161 default:
1162 break;
1163 }
1164}
1165
1166void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001167 BasicBlock& b,
1168 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001169 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001170 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001171 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001172 switch (stmt->kind()) {
1173 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001174 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001175 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001176 (!varDecl.value() ||
1177 !varDecl.value()->hasSideEffects())) {
1178 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001179 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001180 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001181 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001182 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001183 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001184 // There can still be (soon to be removed) references to the variable at this point.
1185 // Allowing the VarDeclaration to be destroyed here will break those variable's
1186 // initialValue()s, so we hang on to them until optimization is finished.
1187 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1188 usage);
1189 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001190 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001191 }
1192 break;
1193 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001194 case Statement::Kind::kIf: {
John Stiles4633c912021-03-03 16:13:45 -05001195 // TODO(skia:11319): this optimization logic is redundant with the optimization code
1196 // found in IfStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001197 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001198 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001199 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001200 if (i.test()->as<BoolLiteral>().value()) {
1201 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001202 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001203 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001204 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001205 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001206 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001207 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001208 }
1209 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001210 optimizationContext->fUpdated = true;
1211 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001212 break;
1213 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001214 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001215 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001216 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001217 optimizationContext->fUpdated = true;
1218 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001219 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001220 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001221 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001222 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001223 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001224 (*iter)->setStatement(
1225 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001226 } else {
1227 // no if, no else, no test side effects, kill the whole if
1228 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001229 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001230 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001231 optimizationContext->fUpdated = true;
1232 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001233 }
1234 break;
1235 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001236 case Statement::Kind::kSwitch: {
John Stiles642cde22021-02-23 14:57:01 -05001237 // TODO(skia:11319): this optimization logic is redundant with the static-switch
1238 // optimization code found in SwitchStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001239 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001240 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001241 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001242 // switch is constant, replace it with the case that matches
1243 bool found = false;
1244 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001245 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1246 if (!c->value()) {
1247 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001248 continue;
1249 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001250 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001251 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001252 if (caseValue == switchValue) {
John Stiles642cde22021-02-23 14:57:01 -05001253 std::unique_ptr<Statement> newBlock =
1254 SwitchStatement::BlockForCase(&s.cases(), c.get(), s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001255 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001256 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001257 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001258 break;
1259 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001260 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001261 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001262 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1263 if (didInsert) {
1264 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001265 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001266 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001267 }
1268 return; // can't simplify
1269 }
1270 }
1271 }
1272 if (!found) {
1273 // no matching case. use default if it exists, or kill the whole thing
1274 if (defaultCase) {
John Stiles642cde22021-02-23 14:57:01 -05001275 std::unique_ptr<Statement> newBlock =
1276 SwitchStatement::BlockForCase(&s.cases(), defaultCase, s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001277 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001278 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001279 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001280 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001281 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001282 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1283 if (didInsert) {
1284 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001285 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001286 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001287 }
1288 return; // can't simplify
1289 }
1290 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001291 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001292 }
1293 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001294 optimizationContext->fUpdated = true;
1295 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001296 }
1297 break;
1298 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001299 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001300 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001301 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001302 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001303 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001304 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001305 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001306 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001307 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001308 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001309 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001310 }
1311 break;
1312 }
1313 default:
1314 break;
1315 }
1316}
1317
Brian Osman010ce6a2020-10-19 16:34:10 -04001318bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001319 bool madeChanges = false;
1320
Ethan Nicholascb670962017-04-20 19:31:52 -04001321 CFG cfg = CFGGenerator().getCFG(f);
1322 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001323
John Stiles8ef4d6c2021-03-05 16:01:45 -05001324 if (gSkSLControlFlowAnalysis && fContext->fConfig->fSettings.fDeadCodeElimination) {
John Stiles66c53b92021-02-20 08:00:43 -05001325 // Check for unreachable code.
1326 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
1327 const BasicBlock& block = cfg.fBlocks[i];
1328 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
1329 const BasicBlock::Node& node = block.fNodes[0];
1330 int offset = node.isStatement() ? (*node.statement())->fOffset
1331 : (*node.expression())->fOffset;
1332 this->error(offset, String("unreachable"));
1333 }
ethannicholas22f939e2016-10-13 13:25:34 -07001334 }
1335 }
1336 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001337 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001338 }
1339
Ethan Nicholascb670962017-04-20 19:31:52 -04001340 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001341 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001342 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001343 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001344 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001345 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001346 cfg = CFGGenerator().getCFG(f);
1347 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001348 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001349 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001350
John Stiles7d3f0892020-11-03 11:35:01 -05001351 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001352 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001353
1354 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1355 if (eliminatedBlockIds.test(blockId)) {
1356 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1357 optimizationContext.fUpdated = true;
1358 optimizationContext.fNeedsRescan = true;
1359 break;
1360 }
1361
1362 BasicBlock& b = cfg.fBlocks[blockId];
John Stiles8ef4d6c2021-03-05 16:01:45 -05001363 if (gSkSLControlFlowAnalysis && fContext->fConfig->fSettings.fDeadCodeElimination) {
John Stiles66c53b92021-02-20 08:00:43 -05001364 if (blockId > 0 && !b.fIsReachable) {
1365 // Block was reachable before optimization, but has since become unreachable. In
1366 // addition to being dead code, it's broken - since control flow can't reach it,
1367 // no prior variable definitions can reach it, and therefore variables might
1368 // look to have not been properly assigned. Kill it by replacing all statements
1369 // with Nops.
1370 for (BasicBlock::Node& node : b.fNodes) {
1371 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
1372 // Eliminating a node runs the risk of eliminating that node's exits as
1373 // well. Keep track of this and do a rescan if we are about to access
1374 // one of these.
1375 for (BlockId id : b.fExits) {
1376 eliminatedBlockIds.set(id);
1377 }
1378 node.setStatement(std::make_unique<Nop>(), usage);
1379 madeChanges = true;
John Stiles7d3f0892020-11-03 11:35:01 -05001380 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001381 }
John Stiles66c53b92021-02-20 08:00:43 -05001382 continue;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001383 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001384 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001385 DefinitionMap definitions = b.fBefore;
1386
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001387 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1388 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001389 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001390 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001391 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001392 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001393 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001394 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001395 break;
1396 }
John Stilese8a24922021-02-08 17:54:08 -05001397 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001398 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001399
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001400 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001401 break;
1402 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001403 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001404 madeChanges |= optimizationContext.fUpdated;
1405 } while (optimizationContext.fUpdated);
1406 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001407
John Stiles0cc193a2020-09-09 09:39:34 -04001408 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001409}
1410
Brian Osman32d53552020-09-23 13:55:20 -04001411std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001412 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001413 String text,
1414 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001415 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osmand010f652021-02-24 13:59:39 -05001416 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001417
John Stilesdbd4e6f2021-02-16 13:29:15 -05001418 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001419
Brian Osman0006ad02020-11-18 15:38:39 -05001420 // Loading and optimizing our base module might reset the inliner, so do that first,
1421 // *then* configure the inliner with the settings for this program.
1422 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1423
John Stiles270cec22021-02-17 12:59:36 -05001424 // Update our context to point to the program configuration for the duration of compilation.
1425 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -05001426 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -05001427
ethannicholasb3058bd2016-07-01 08:22:01 -07001428 fErrorText = "";
1429 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -05001430 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -04001431
1432 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001433 std::unique_ptr<String> textPtr(new String(std::move(text)));
1434 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001435
John Stiles5c7bb322020-10-22 11:09:15 -04001436 // Enable node pooling while converting and optimizing the program for a performance boost.
1437 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001438 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -05001439 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -05001440 pool = Pool::Create();
1441 pool->attachToThread();
1442 }
John Stilesd1204642021-02-17 16:30:02 -05001443 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
1444 textPtr->c_str(), textPtr->size(),
1445 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -05001446 auto program = std::make_unique<Program>(std::move(textPtr),
1447 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -04001448 fContext,
1449 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001450 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001451 std::move(ir.fModifiers),
1452 std::move(ir.fSymbolTable),
1453 std::move(pool),
1454 ir.fInputs);
1455 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001456 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001457 // Do not return programs that failed to compile.
John Stilescbd65752021-02-24 14:14:14 +00001458 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001459 // Do not return programs that failed to optimize.
1460 } else {
1461 // We have a successful program!
1462 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001463 }
John Stiles5c7bb322020-10-22 11:09:15 -04001464
Brian Osman28f702c2021-02-02 11:52:07 -05001465 if (program->fPool) {
1466 program->fPool->detachFromThread();
1467 }
John Stiles5c7bb322020-10-22 11:09:15 -04001468 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001469}
1470
John Stilesbb1505f2021-02-12 09:17:53 -05001471void Compiler::verifyStaticTests(const Program& program) {
1472 class StaticTestVerifier : public ProgramVisitor {
1473 public:
1474 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1475
1476 using ProgramVisitor::visitProgramElement;
1477
1478 bool visitStatement(const Statement& stmt) override {
1479 switch (stmt.kind()) {
1480 case Statement::Kind::kIf:
1481 if (stmt.as<IfStatement>().isStatic()) {
1482 fReporter->error(stmt.fOffset, "static if has non-static test");
1483 }
1484 break;
1485
1486 case Statement::Kind::kSwitch:
1487 if (stmt.as<SwitchStatement>().isStatic()) {
1488 fReporter->error(stmt.fOffset, "static switch has non-static test");
1489 }
1490 break;
1491
1492 default:
1493 break;
1494 }
1495 return INHERITED::visitStatement(stmt);
1496 }
1497
John Stiles59e34562021-02-12 16:56:39 -05001498 bool visitExpression(const Expression&) override {
1499 // We aren't looking for anything inside an Expression, so skip them entirely.
1500 return false;
1501 }
1502
John Stilesbb1505f2021-02-12 09:17:53 -05001503 private:
1504 using INHERITED = ProgramVisitor;
1505 ErrorReporter* fReporter;
1506 };
1507
1508 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -05001509 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -05001510 return;
1511 }
1512
1513 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1514 StaticTestVerifier visitor{this};
1515 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1516 if (element->is<FunctionDefinition>()) {
1517 visitor.visitProgramElement(*element);
1518 }
1519 }
1520}
1521
Brian Osman0006ad02020-11-18 15:38:39 -05001522bool Compiler::optimize(LoadedModule& module) {
1523 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -05001524
John Stiles270cec22021-02-17 12:59:36 -05001525 // Create a temporary program configuration with default settings.
1526 ProgramConfig config;
1527 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -05001528 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -05001529
John Stilesd1204642021-02-17 16:30:02 -05001530 // Reset the Inliner.
1531 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -05001532
1533 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -05001534
1535 while (fErrorCount == 0) {
1536 bool madeChanges = false;
1537
1538 // Scan and optimize based on the control-flow graph for each function.
John Stiles8ef4d6c2021-03-05 16:01:45 -05001539 if (gSkSLControlFlowAnalysis && config.fSettings.fControlFlowAnalysis) {
John Stilesa935c3f2021-02-25 10:35:49 -05001540 for (const auto& element : module.fElements) {
1541 if (element->is<FunctionDefinition>()) {
1542 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1543 }
Brian Osman0006ad02020-11-18 15:38:39 -05001544 }
1545 }
1546
1547 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001548 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001549
1550 if (!madeChanges) {
1551 break;
1552 }
1553 }
1554 return fErrorCount == 0;
1555}
1556
Ethan Nicholas00543112018-07-31 09:44:36 -04001557bool Compiler::optimize(Program& program) {
1558 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -04001559 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001560
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001561 while (fErrorCount == 0) {
1562 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001563
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001564 // Scan and optimize based on the control-flow graph for each function.
John Stiles8ef4d6c2021-03-05 16:01:45 -05001565 if (gSkSLControlFlowAnalysis && program.fConfig->fSettings.fControlFlowAnalysis) {
John Stiles0c7312a2021-02-24 11:31:32 -05001566 for (const auto& element : program.ownedElements()) {
1567 if (element->is<FunctionDefinition>()) {
1568 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
1569 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001570 }
1571 }
1572
1573 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001574 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001575
1576 // Remove dead functions. We wait until after analysis so that we still report errors,
1577 // even in unused code.
John Stiles270cec22021-02-17 12:59:36 -05001578 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001579 auto isDeadFunction = [&](const ProgramElement* element) {
1580 if (!element->is<FunctionDefinition>()) {
1581 return false;
1582 }
1583 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1584 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1585 usage->remove(*element);
1586 madeChanges = true;
1587 return true;
1588 }
1589 return false;
1590 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001591 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001592 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001593 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001594 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001595 }),
1596 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001597 program.fSharedElements.erase(
1598 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1599 isDeadFunction),
1600 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001601 }
1602
John Stiles270cec22021-02-17 12:59:36 -05001603 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001604 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001605 auto isDeadVariable = [&](const ProgramElement* element) {
1606 if (!element->is<GlobalVarDeclaration>()) {
1607 return false;
1608 }
1609 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1610 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1611 if (usage->isDead(varDecl.var())) {
1612 madeChanges = true;
1613 return true;
1614 }
1615 return false;
1616 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001617 program.fElements.erase(
1618 std::remove_if(program.fElements.begin(), program.fElements.end(),
1619 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001620 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001621 }),
1622 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001623 program.fSharedElements.erase(
1624 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1625 isDeadVariable),
1626 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001627 }
John Stiles73a6bff2020-09-09 13:40:37 -04001628
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001629 if (!madeChanges) {
1630 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001631 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001632 }
John Stilesbb1505f2021-02-12 09:17:53 -05001633
1634 if (fErrorCount == 0) {
1635 this->verifyStaticTests(program);
1636 }
1637
Ethan Nicholas00543112018-07-31 09:44:36 -04001638 return fErrorCount == 0;
1639}
1640
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001641#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1642
Ethan Nicholas00543112018-07-31 09:44:36 -04001643bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001644#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001645 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001646 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001647 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001648 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -05001649 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001650 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001651 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001652 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001653 String errors;
1654 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1655 const char* m) {
1656 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001657 };
1658 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001659
1660 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1661 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1662 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1663 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1664
1665 if (!result) {
1666#if defined(SKSL_STANDALONE)
1667 // Convert the string-stream to a SPIR-V disassembly.
1668 std::string disassembly;
1669 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1670 errors.append(disassembly);
1671 }
1672 this->error(-1, errors);
1673#else
1674 SkDEBUGFAILF("%s", errors.c_str());
1675#endif
1676 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001677 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001678 }
1679#else
Brian Osman88cda172020-10-09 12:05:16 -04001680 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001681 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001682 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001683#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001684 return result;
1685}
1686
Ethan Nicholas00543112018-07-31 09:44:36 -04001687bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001688 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001689 bool result = this->toSPIRV(program, buffer);
1690 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001691 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001692 }
1693 return result;
1694}
1695
Ethan Nicholas00543112018-07-31 09:44:36 -04001696bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osmand010f652021-02-24 13:59:39 -05001697 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001698 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001699 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001700 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001701 return result;
1702}
1703
Ethan Nicholas00543112018-07-31 09:44:36 -04001704bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001705 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001706 bool result = this->toGLSL(program, buffer);
1707 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001708 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001709 }
1710 return result;
1711}
1712
Brian Osmanc0243912020-02-19 15:35:26 -05001713bool Compiler::toHLSL(Program& program, String* out) {
1714 String spirv;
1715 if (!this->toSPIRV(program, &spirv)) {
1716 return false;
1717 }
1718
1719 return SPIRVtoHLSL(spirv, out);
1720}
1721
Ethan Nicholas00543112018-07-31 09:44:36 -04001722bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001723 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001724 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001725 return result;
1726}
1727
Ethan Nicholas00543112018-07-31 09:44:36 -04001728bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001729 StringStream buffer;
1730 bool result = this->toMetal(program, buffer);
1731 if (result) {
1732 *out = buffer.str();
1733 }
1734 return result;
1735}
1736
Greg Daniela28ea672020-09-25 11:12:56 -04001737#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001738bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001739 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001740 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001741 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001742 return result;
1743}
1744
Ethan Nicholas00543112018-07-31 09:44:36 -04001745bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001746 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001747 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001748 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001749 return result;
1750}
Greg Daniela28ea672020-09-25 11:12:56 -04001751#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001752
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001753#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001754
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001755Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001756 if (fSource && offset >= 0) {
1757 int line = 1;
1758 int column = 1;
1759 for (int i = 0; i < offset; i++) {
1760 if ((*fSource)[i] == '\n') {
1761 ++line;
1762 column = 1;
1763 }
1764 else {
1765 ++column;
1766 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001767 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001768 return Position(line, column);
1769 } else {
1770 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001771 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001772}
1773
1774void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001775 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001776 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001777 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001778 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001779}
1780
John Stiles8d3642e2021-01-22 09:50:04 -05001781void Compiler::setErrorCount(int c) {
1782 if (c < fErrorCount) {
1783 fErrorText.resize(fErrorTextLength[c]);
1784 fErrorTextLength.resize(c);
1785 fErrorCount = c;
1786 }
1787}
1788
Ethan Nicholas95046142021-01-07 10:57:27 -05001789String Compiler::errorText(bool showCount) {
1790 if (showCount) {
1791 this->writeErrorCount();
1792 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001793 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001794 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001795 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001796 return result;
1797}
1798
1799void Compiler::writeErrorCount() {
1800 if (fErrorCount) {
1801 fErrorText += to_string(fErrorCount) + " error";
1802 if (fErrorCount > 1) {
1803 fErrorText += "s";
1804 }
1805 fErrorText += "\n";
1806 }
1807}
1808
John Stilesa6841be2020-08-06 14:11:56 -04001809} // namespace SkSL