blob: fae1562ea0feb32accf3d30be919290cdd15b7b1 [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 Stiles7247b482021-03-08 10:40:35 -050075// Set these flags to `false` to disable optimization passes unilaterally.
76// These flags allow tools like Viewer or Nanobench to override the compiler's ProgramSettings.
77bool gSkSLOptimizer = true;
78bool gSkSLInliner = true;
John Stiles8ef4d6c2021-03-05 16:01:45 -050079bool gSkSLControlFlowAnalysis = true;
80
John Stiles47c0a742021-02-09 09:30:35 -050081using RefKind = VariableReference::RefKind;
82
Brian Osman88cda172020-10-09 12:05:16 -040083class AutoSource {
84public:
85 AutoSource(Compiler* compiler, const String* source)
86 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
87 fCompiler->fSource = source;
88 }
89
90 ~AutoSource() { fCompiler->fSource = fOldSource; }
91
92 Compiler* fCompiler;
93 const String* fOldSource;
94};
95
John Stilesa935c3f2021-02-25 10:35:49 -050096class AutoProgramConfig {
97public:
98 AutoProgramConfig(std::shared_ptr<Context>& context, ProgramConfig* config)
99 : fContext(context.get()) {
100 SkASSERT(!fContext->fConfig);
101 fContext->fConfig = config;
102 }
103
104 ~AutoProgramConfig() {
105 fContext->fConfig = nullptr;
106 }
107
108 Context* fContext;
109};
110
John Stilesd6a5f4492021-02-11 15:46:11 -0500111Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesc1a98b82021-02-24 13:35:02 -0500112 : fContext(std::make_shared<Context>(/*errors=*/*this, *caps))
John Stiles7b920442020-12-17 10:43:41 -0500113 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -0500114 , fErrorCount(0) {
John Stilesc1a98b82021-02-24 13:35:02 -0500115 SkASSERT(caps);
John Stiles7c3515b2020-10-16 18:38:39 -0400116 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -0500117 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesc1a98b82021-02-24 13:35:02 -0500118 fIRGenerator = std::make_unique<IRGenerator>(fContext.get());
ethannicholasb3058bd2016-07-01 08:22:01 -0700119
John Stiles54e7c052021-01-11 14:22:36 -0500120#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -0700121
Brian Osmanb06301e2020-11-06 11:45:36 -0500122 const SkSL::Symbol* rootTypes[] = {
123 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500124
Brian Osmanb06301e2020-11-06 11:45:36 -0500125 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
126 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
127 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500128 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500129
Brian Osmanc0f2b642020-12-22 13:35:55 -0500130 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500131 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500132
Brian Osmanc63f4312020-12-23 11:44:14 -0500133 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700134
Brian Osman20fad322020-12-23 12:42:33 -0500135 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
136 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500137
138 TYPE(FragmentProcessor),
139 };
140
141 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500142 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
143 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
144 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
145 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
146 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
147
148 TYPE(GenUType), TYPE(UVec),
149 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
150
Brian Osmanc0f2b642020-12-22 13:35:55 -0500151 TYPE(Float2x3), TYPE(Float2x4),
152 TYPE(Float3x2), TYPE(Float3x4),
153 TYPE(Float4x2), TYPE(Float4x3),
154
Brian Osmanc63f4312020-12-23 11:44:14 -0500155 TYPE(Half2x3), TYPE(Half2x4),
156 TYPE(Half3x2), TYPE(Half3x4),
157 TYPE(Half4x2), TYPE(Half4x3),
158
Brian Osmanc0f2b642020-12-22 13:35:55 -0500159 TYPE(Mat), TYPE(HMat),
160
Brian Osmanb06301e2020-11-06 11:45:36 -0500161 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
162 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500163 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500164
165 TYPE(ISampler2D),
Brian Osmanb06301e2020-11-06 11:45:36 -0500166 TYPE(SubpassInput), TYPE(SubpassInputMS),
167
Brian Osmanb06301e2020-11-06 11:45:36 -0500168 TYPE(Sampler),
169 TYPE(Texture2D),
170 };
171
172 for (const SkSL::Symbol* type : rootTypes) {
173 fRootSymbolTable->addWithoutOwnership(type);
174 }
175 for (const SkSL::Symbol* type : privateTypes) {
176 fPrivateSymbolTable->addWithoutOwnership(type);
177 }
178
179#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700180
Brian Osman3887a012020-09-30 13:22:27 -0400181 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
182 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500183 fPrivateSymbolTable->add(
184 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500185 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500186 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500187 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500188 /*builtin=*/false,
189 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500190
Brian Osman3d87e9f2020-10-08 11:50:22 -0400191 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500192 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700193}
194
John Stilesdd13dba2020-10-29 10:45:34 -0400195Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700196
Brian Osman56269982020-11-20 12:38:07 -0500197const ParsedModule& Compiler::loadGPUModule() {
198 if (!fGPUModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500199 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500200 }
201 return fGPUModule;
202}
203
204const ParsedModule& Compiler::loadFragmentModule() {
205 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500206 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500207 this->loadGPUModule());
208 }
209 return fFragmentModule;
210}
211
212const ParsedModule& Compiler::loadVertexModule() {
213 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500214 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500215 this->loadGPUModule());
216 }
217 return fVertexModule;
218}
219
Brian Osman88cda172020-10-09 12:05:16 -0400220const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400221 if (!fGeometryModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500222 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500223 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400224 }
Brian Osman88cda172020-10-09 12:05:16 -0400225 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400226}
227
Brian Osman88cda172020-10-09 12:05:16 -0400228const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400229 if (!fFPModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500230 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500231 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400232 }
Brian Osman88cda172020-10-09 12:05:16 -0400233 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400234}
235
Brian Osmanb06301e2020-11-06 11:45:36 -0500236const ParsedModule& Compiler::loadPublicModule() {
237 if (!fPublicModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500238 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500239 }
240 return fPublicModule;
241}
242
Brian Osman91946752020-12-21 13:20:40 -0500243const ParsedModule& Compiler::loadRuntimeEffectModule() {
244 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500245 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500246 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400247
Brian Osman91946752020-12-21 13:20:40 -0500248 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500249 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400250
John Stiles54e7c052021-01-11 14:22:36 -0500251 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
252 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
253 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400254
John Stiles54e7c052021-01-11 14:22:36 -0500255 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
256 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
257 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400258
John Stiles54e7c052021-01-11 14:22:36 -0500259 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
260 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
261 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400262 }
Brian Osman91946752020-12-21 13:20:40 -0500263 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400264}
265
John Stilesdbd4e6f2021-02-16 13:29:15 -0500266const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400267 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500268 case ProgramKind::kVertex: return this->loadVertexModule(); break;
269 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
270 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
271 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
272 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
273 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400274 }
275 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400276}
277
John Stilesdbd4e6f2021-02-16 13:29:15 -0500278LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400279 ModuleData data,
John Stilesa935c3f2021-02-25 10:35:49 -0500280 std::shared_ptr<SymbolTable> base,
281 bool dehydrate) {
282 if (dehydrate) {
283 // NOTE: This is a workaround. When dehydrating includes, skslc doesn't know which module
284 // it's preparing, nor what the correct base module is. We can't use 'Root', because many
285 // GPU intrinsics reference private types, like samplers or textures. Today, 'Private' does
286 // contain the union of all known types, so this is safe. If we ever have types that only
287 // exist in 'Public' (for example), this logic needs to be smarter (by choosing the correct
288 // base for the module we're compiling).
Brian Osmanb06301e2020-11-06 11:45:36 -0500289 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400290 }
John Stilesa935c3f2021-02-25 10:35:49 -0500291 SkASSERT(base);
292
293 // Built-in modules always use default program settings.
294 ProgramConfig config;
295 config.fKind = kind;
296 config.fSettings.fReplaceSettings = !dehydrate;
297 AutoProgramConfig autoConfig(fContext, &config);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400298
299#if defined(SKSL_STANDALONE)
300 SkASSERT(data.fPath);
301 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400302 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
303 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400304 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400305 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400306 abort();
307 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400308 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400309 AutoSource as(this, source);
John Stilesd1204642021-02-17 16:30:02 -0500310
John Stiles881a10c2020-09-19 10:13:24 -0400311 SkASSERT(fIRGenerator->fCanInline);
312 fIRGenerator->fCanInline = false;
John Stilesd1204642021-02-17 16:30:02 -0500313
Brian Osman88cda172020-10-09 12:05:16 -0400314 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
John Stilesd1204642021-02-17 16:30:02 -0500315 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/true,
316 source->c_str(), source->length(),
317 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400318 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500319 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400320 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400321 if (this->fErrorCount) {
322 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400323 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400324 }
Brian Osman88cda172020-10-09 12:05:16 -0400325 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400326#else
327 SkASSERT(data.fData && (data.fSize != 0));
328 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
329 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500330 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400331 fModifiers.push_back(fIRGenerator->releaseModifiers());
332#endif
333
334 return module;
335}
336
John Stilesdbd4e6f2021-02-16 13:29:15 -0500337ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
John Stilesa935c3f2021-02-25 10:35:49 -0500338 LoadedModule module = this->loadModule(kind, data, base.fSymbols, /*dehydrate=*/false);
Brian Osman0006ad02020-11-18 15:38:39 -0500339 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400340
341 // For modules that just declare (but don't define) intrinsic functions, there will be no new
342 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500343 if (module.fElements.empty()) {
344 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400345 }
346
347 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
348
349 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
350 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500351 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400352 switch (element->kind()) {
353 case ProgramElement::Kind::kFunction: {
354 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400355 SkASSERT(f.declaration().isBuiltin());
356 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400357 break;
358 }
John Stiles569249b2020-11-03 12:18:22 -0500359 case ProgramElement::Kind::kFunctionPrototype: {
360 // These are already in the symbol table.
361 break;
362 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400363 case ProgramElement::Kind::kEnum: {
364 const Enum& e = element->as<Enum>();
365 SkASSERT(e.isBuiltin());
366 intrinsics->insertOrDie(e.typeName(), std::move(element));
367 break;
368 }
369 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400370 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
371 const Variable& var = global.declaration()->as<VarDeclaration>().var();
372 SkASSERT(var.isBuiltin());
373 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400374 break;
375 }
376 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400377 const Variable& var = element->as<InterfaceBlock>().variable();
378 SkASSERT(var.isBuiltin());
379 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400380 break;
381 }
382 default:
383 printf("Unsupported element: %s\n", element->description().c_str());
384 SkASSERT(false);
385 break;
386 }
387 }
388
Brian Osman0006ad02020-11-18 15:38:39 -0500389 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400390}
391
John Stilese6150002020-10-05 12:03:53 -0400392void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700393 BasicBlock& block = cfg->fBlocks[blockId];
394
395 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500396 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700397 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500398 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700399 }
400
401 // propagate definitions to exits
402 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400403 if (exitId == blockId) {
404 continue;
405 }
ethannicholas22f939e2016-10-13 13:25:34 -0700406 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500407 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400408 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
409 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400410 // exit has no definition for it, just copy it and reprocess exit block
411 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500412 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700413 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500414 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400415 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700416 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400417 // definition has changed, merge and reprocess the exit block
418 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500419 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400420 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500421 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400422 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500423 }
ethannicholas22f939e2016-10-13 13:25:34 -0700424 }
425 }
John Stiles65b48272020-12-22 17:18:34 -0500426 }
ethannicholas22f939e2016-10-13 13:25:34 -0700427 }
428}
429
Ethan Nicholascb670962017-04-20 19:31:52 -0400430/**
431 * Returns true if assigning to this lvalue has no effect.
432 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400433static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400434 switch (lvalue.kind()) {
435 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400436 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400437 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400438 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400439 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400440 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400441 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400442 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400443 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400444 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400445 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400446 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400447 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400448 return !t.test()->hasSideEffects() &&
449 is_dead(*t.ifTrue(), usage) &&
450 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500451 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400452 default:
John Stileseada7bc2021-02-02 16:29:32 -0500453 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500454 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400455 }
456}
ethannicholas22f939e2016-10-13 13:25:34 -0700457
Ethan Nicholascb670962017-04-20 19:31:52 -0400458/**
459 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
460 * to a dead target and lack of side effects on the left hand side.
461 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400462static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
John Stiles45990502021-02-16 10:55:27 -0500463 if (!b.getOperator().isAssignment()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400464 return false;
465 }
John Stiles2d4f9592020-10-30 10:29:12 -0400466 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400467}
468
John Stiles0ac6c152021-02-10 14:04:24 -0500469static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500470 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles95d0bad2021-03-01 17:02:28 -0500471 Analysis::IsSelfAssignment(*b.left(), *b.right());
John Stiles0ac6c152021-02-10 14:04:24 -0500472}
473
Ethan Nicholascb670962017-04-20 19:31:52 -0400474void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500475 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400476
477 // We set bits in the "processed" set after a block has been scanned.
478 SkBitSet processedSet(cfg->fBlocks.size());
479 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
480 processedSet.set(*blockId);
481 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700482 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400483}
484
485/**
486 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
487 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
488 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
489 * need to be regenerated).
490 */
John Stilesafbf8992020-08-18 10:08:21 -0400491static bool try_replace_expression(BasicBlock* b,
492 std::vector<BasicBlock::Node>::iterator* iter,
493 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400494 std::unique_ptr<Expression>* target = (*iter)->expression();
495 if (!b->tryRemoveExpression(iter)) {
496 *target = std::move(*newExpression);
497 return false;
498 }
499 *target = std::move(*newExpression);
500 return b->tryInsertExpression(iter, target);
501}
502
503/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400504 * Returns true if the expression is a constant numeric literal with the specified value, or a
505 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400506 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400507template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400508static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400509 switch (expr.kind()) {
510 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400511 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400512
Ethan Nicholase6592142020-09-08 10:22:09 -0400513 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400514 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400515
Ethan Nicholase6592142020-09-08 10:22:09 -0400516 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400517 const Constructor& constructor = expr.as<Constructor>();
518 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400519 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400520 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400521 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500522 if (constructor.componentType().isFloat()) {
523 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400524 if (constructor.getFVecComponent(i) != value) {
525 return false;
526 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500527 }
528 return true;
529 } else if (constructor.componentType().isInteger()) {
530 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400531 if (constructor.getIVecComponent(i) != value) {
532 return false;
533 }
534 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500535 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400536 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500537 // Other types (e.g. boolean) might occur, but aren't supported here.
538 return false;
John Stiles9d944232020-08-19 09:56:49 -0400539
Ethan Nicholase6592142020-09-08 10:22:09 -0400540 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400541 SkASSERT(constructor.arguments().size() == 1);
542 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400543
544 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400545 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400546 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400547 }
548 return false;
549 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400550 default:
551 return false;
552 }
553}
554
555/**
556 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
557 * and CFG structures).
558 */
John Stilesafbf8992020-08-18 10:08:21 -0400559static void delete_left(BasicBlock* b,
560 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400561 Compiler::OptimizationContext* optimizationContext) {
562 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400563 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400564 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400565 Expression& left = *bin.left();
566 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400567 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400568 bool result;
John Stiles45990502021-02-16 10:55:27 -0500569 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400570 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400571 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400572 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400573 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400574 // Remove references within LHS.
575 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400576 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400577 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400578 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400579 return;
580 }
581 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400582 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400583 return;
584 }
585 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400586 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400587 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400588 return;
589 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400590 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400591 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400592}
593
594/**
595 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
596 * CFG structures).
597 */
John Stilesafbf8992020-08-18 10:08:21 -0400598static void delete_right(BasicBlock* b,
599 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400600 Compiler::OptimizationContext* optimizationContext) {
601 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400602 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400603 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400604 std::unique_ptr<Expression>& leftPointer = bin.left();
605 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400606 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400607 // Remove references within RHS.
608 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400609 if (!b->tryRemoveExpressionBefore(iter, &right)) {
610 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400611 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400612 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400613 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400614 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400615 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400616 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400617 return;
618 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400619 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400620 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400621 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400622 return;
623 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400624 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400625 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400626}
627
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400628/**
629 * Constructs the specified type using a single argument.
630 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400631static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400632 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400633 args.push_back(std::move(v));
John Stiles54f00492021-02-19 11:46:10 -0500634 return std::make_unique<Constructor>(/*offset=*/-1, *type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400635}
636
637/**
638 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
639 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
640 */
641static void vectorize(BasicBlock* b,
642 std::vector<BasicBlock::Node>::iterator* iter,
643 const Type& type,
644 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400645 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400646 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500647 SkASSERT(type.isVector());
648 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400649 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400650 std::unique_ptr<Expression>* target = (*iter)->expression();
651 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400652 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400653 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400654 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400655 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400656 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400657 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400658 }
659 }
660}
661
662/**
663 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
664 * left to yield vec<n>(x).
665 */
666static void vectorize_left(BasicBlock* b,
667 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400668 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400669 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400670 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400671 optimizationContext->fUsage->remove(bin.right().get());
672 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400673}
674
675/**
676 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
677 * right to yield vec<n>(y).
678 */
679static void vectorize_right(BasicBlock* b,
680 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400681 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400682 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400683 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400684 optimizationContext->fUsage->remove(bin.left().get());
685 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400686}
687
Ethan Nicholascb670962017-04-20 19:31:52 -0400688void Compiler::simplifyExpression(DefinitionMap& definitions,
689 BasicBlock& b,
690 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400691 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400692 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400693 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500694
Ethan Nicholascb670962017-04-20 19:31:52 -0400695 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400696 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
697 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400698 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400699 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400700 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400701 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400702 // Remove references within 'expr', add references within 'optimized'
703 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400704 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400705 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400706 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400707 }
John Stiles70025e52020-09-28 16:08:58 -0400708 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400709 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400710 }
711 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400712 switch (expr->kind()) {
713 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400714 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400715 const Variable* var = ref.variable();
John Stiles7247b482021-03-08 10:40:35 -0500716 if (fContext->fConfig->fSettings.fDeadCodeElimination &&
John Stiles66c53b92021-02-20 08:00:43 -0500717 ref.refKind() != VariableReference::RefKind::kWrite &&
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400718 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500719 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400720 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
721 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000722 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400723 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400724 }
725 break;
726 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400727 case Expression::Kind::kTernary: {
John Stiles28054ad2021-03-05 15:22:48 -0500728 // TODO(skia:11319): this optimization logic is redundant with the optimization code
729 // found in SkSLTernaryExpression.cpp.
730
John Stiles403a3632020-08-20 12:11:48 -0400731 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400732 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400733 // ternary has a constant test, replace it with either the true or
734 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400735 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400736 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400737 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400738 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400739 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400740 optimizationContext->fUpdated = true;
741 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400742 }
743 break;
744 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400745 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400746 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500747 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400748 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400749 break;
750 }
John Stiles8f440b42021-03-05 16:48:56 -0500751
752 // TODO(skia:11319): this optimization logic is redundant with the optimization code
753 // found in ConstantFolder.cpp.
John Stiles2d4f9592020-10-30 10:29:12 -0400754 Expression& left = *bin->left();
755 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400756 const Type& leftType = left.type();
757 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400758 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500759 if ((!leftType.isScalar() && !leftType.isVector()) ||
760 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400761 break;
762 }
John Stiles45990502021-02-16 10:55:27 -0500763 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400764 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400765 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500766 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400767 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400768 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400769 } else {
770 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400771 // 1 * float4(x) -> float4(x)
772 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400773 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400774 }
775 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400776 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500777 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400778 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400779 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400780 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400781 } else {
782 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400783 // float4(0) * x -> float4(0)
784 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400785 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400786 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500787 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400788 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400789 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400790 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500791 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400792 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400793 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400794 } else {
795 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400796 // float4(x) * 1 -> float4(x)
797 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400798 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400799 }
800 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400801 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500802 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400803 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400804 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400805 } else {
806 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400807 // x * float4(0) -> float4(0)
808 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400809 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400810 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500811 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400812 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400813 }
814 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400815 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400816 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500817 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400818 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400819 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400820 } else {
821 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400822 // 0 + float4(x) -> float4(x)
823 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400824 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400825 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400826 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500827 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400828 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400829 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400830 } else {
831 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400832 // float4(x) + 0 -> float4(x)
833 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400834 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400835 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400836 }
837 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400838 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400839 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500840 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400841 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400842 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400843 } else {
844 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400845 // float4(x) - 0 -> float4(x)
846 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400847 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400848 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400849 }
850 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400851 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400852 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500853 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400854 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400855 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400856 } else {
857 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400858 // float4(x) / 1 -> float4(x)
859 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400860 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400861 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400862 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500863 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400864 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400865 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400866 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400867 } else {
868 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400869 // float4(0) / x -> float4(0)
870 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400871 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400872 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500873 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400874 }
875 }
876 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400877 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400878 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500879 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400880 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400881 }
882 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400883 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400884 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500885 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400886 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400887 }
888 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400889 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400890 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500891 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400892 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400893 }
894 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400895 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400896 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500897 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400898 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400899 }
900 break;
901 default:
902 break;
903 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400904 break;
905 }
John Stilesf5c1d042020-11-21 23:26:07 -0500906 case Expression::Kind::kConstructor: {
John Stilesb9e4f642021-03-05 09:11:38 -0500907 // TODO(skia:11319): this optimization logic is redundant with the optimization code
908 // found in SkSLConstructor.cpp.
909
John Stilesf5c1d042020-11-21 23:26:07 -0500910 // Find constructors embedded inside constructors and flatten them out where possible.
911 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
912 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
913 // Leave single-argument constructors alone, though. These might be casts or splats.
914 Constructor& c = expr->as<Constructor>();
915 if (c.type().columns() > 1) {
916 // Inspect each constructor argument to see if it's a candidate for flattening.
917 // Remember matched arguments in a bitfield, "argsToOptimize".
918 int argsToOptimize = 0;
919 int currBit = 1;
920 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
921 if (arg->is<Constructor>()) {
922 Constructor& inner = arg->as<Constructor>();
923 if (inner.arguments().size() > 1 &&
924 inner.type().componentType() == c.type().componentType()) {
925 argsToOptimize |= currBit;
926 }
927 }
928 currBit <<= 1;
929 }
930 if (argsToOptimize) {
931 // We found at least one argument that could be flattened out. Re-walk the
932 // constructor args and flatten the candidates we found during our initial pass.
933 ExpressionArray flattened;
934 flattened.reserve_back(c.type().columns());
935 currBit = 1;
936 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
937 if (argsToOptimize & currBit) {
938 Constructor& inner = arg->as<Constructor>();
939 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
940 flattened.push_back(innerArg->clone());
941 }
942 } else {
943 flattened.push_back(arg->clone());
944 }
945 currBit <<= 1;
946 }
John Stiles54f00492021-02-19 11:46:10 -0500947 std::unique_ptr<Expression> replacement = std::make_unique<Constructor>(
948 c.fOffset, c.type(), std::move(flattened));
John Stiles1b91c0e2021-02-11 11:43:09 -0500949 // We're replacing an expression with a cloned version; we'll need a rescan.
950 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
951 // reference counts.
952 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500953 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500954 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500955 break;
956 }
957 }
958 break;
959 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400960 case Expression::Kind::kSwizzle: {
John Stilesf04e09c2021-03-05 13:13:14 -0500961 // TODO(skia:11319): this optimization logic is redundant with the optimization code
962 // found in SkSLSwizzle.cpp.
963
John Stiles403a3632020-08-20 12:11:48 -0400964 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500965 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400966 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400967 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400968 for (int i = 0; i < (int) s.components().size(); ++i) {
969 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400970 identity = false;
971 break;
972 }
973 }
974 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400975 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400976 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400977 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400978 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400979 return;
980 }
John Stiles70025e52020-09-28 16:08:58 -0400981 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400982 break;
983 }
984 }
John Stiles108bbe22020-11-18 11:10:38 -0500985 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
986 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400987 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400988 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400989 for (int c : s.components()) {
990 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400991 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400992 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400993 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500994 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500995 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500996 try_replace_expression(&b, iter, &replacement);
997 optimizationContext->fUpdated = true;
998 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -0500999 break;
1000 }
1001 // Optimize swizzles of constructors.
1002 if (s.base()->is<Constructor>()) {
1003 Constructor& base = s.base()->as<Constructor>();
1004 std::unique_ptr<Expression> replacement;
1005 const Type& componentType = base.type().componentType();
1006 int swizzleSize = s.components().size();
1007
1008 // The IR generator has already converted any zero/one swizzle components into
1009 // constructors containing zero/one args. Confirm that this is true by checking that
1010 // our swizzle components are all `xyzw` (values 0 through 3).
1011 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1012 [](int8_t c) { return c >= 0 && c <= 3; }));
1013
John Stiles9aeed132020-11-24 17:36:06 -05001014 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001015 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1016 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001017 const Expression& argument = *base.arguments().front();
1018 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1019 /*rows=*/1);
1020 replacement = Constructor::SimplifyConversion(constructorType, argument);
1021 if (!replacement) {
1022 ExpressionArray newArgs;
1023 newArgs.push_back(argument.clone());
John Stiles54f00492021-02-19 11:46:10 -05001024 replacement = std::make_unique<Constructor>(base.fOffset, constructorType,
John Stilesf0cb7332021-01-08 18:39:00 -05001025 std::move(newArgs));
1026 }
John Stiles108bbe22020-11-18 11:10:38 -05001027
John Stilesa60ac0c2020-12-22 08:59:51 -05001028 // We're replacing an expression with a cloned version; we'll need a rescan.
1029 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1030 // reference counts.
1031 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001032 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001033 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001034 break;
1035 }
1036
John Stiles0777ac42020-11-19 11:06:47 -05001037 // Swizzles can duplicate some elements and discard others, e.g.
1038 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1039 // - Expressions with side effects need to occur exactly once, even if they
1040 // would otherwise be swizzle-eliminated
1041 // - Non-trivial expressions should not be repeated, but elimination is OK.
1042 //
1043 // Look up the argument for the constructor at each index. This is typically simple
1044 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1045 // seems. This example would result in:
1046 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1047 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1048 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1049 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1050 struct ConstructorArgMap {
1051 int8_t fArgIndex;
1052 int8_t fComponent;
1053 };
1054
1055 int numConstructorArgs = base.type().columns();
1056 ConstructorArgMap argMap[4] = {};
1057 int writeIdx = 0;
1058 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1059 const Expression& expr = *base.arguments()[argIdx];
1060 int argWidth = expr.type().columns();
1061 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1062 argMap[writeIdx].fArgIndex = argIdx;
1063 argMap[writeIdx].fComponent = componentIdx;
1064 ++writeIdx;
1065 }
1066 }
1067 SkASSERT(writeIdx == numConstructorArgs);
1068
1069 // Count up the number of times each constructor argument is used by the
1070 // swizzle.
1071 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1072 // - bar.yz is referenced 3 times, by `.x_xy`
1073 // - half(foo) is referenced 1 time, by `._w__`
1074 int8_t exprUsed[4] = {};
1075 for (int c : s.components()) {
1076 exprUsed[argMap[c].fArgIndex]++;
1077 }
1078
1079 bool safeToOptimize = true;
1080 for (int index = 0; index < numConstructorArgs; ++index) {
1081 int8_t constructorArgIndex = argMap[index].fArgIndex;
1082 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1083
1084 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001085 if (exprUsed[constructorArgIndex] > 1 &&
1086 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001087 safeToOptimize = false;
1088 break;
1089 }
1090 // Check that side-effect-bearing expressions are swizzled in exactly once.
1091 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1092 safeToOptimize = false;
1093 break;
1094 }
1095 }
1096
1097 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001098 struct ReorderedArgument {
1099 int8_t fArgIndex;
1100 ComponentArray fComponents;
1101 };
1102 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001103 for (int c : s.components()) {
1104 const ConstructorArgMap& argument = argMap[c];
1105 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1106
John Stiles9aeed132020-11-24 17:36:06 -05001107 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001108 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001109 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001110 reorderedArgs.push_back({argument.fArgIndex,
1111 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001112 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001113 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001114 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001115 if (reorderedArgs.empty() ||
1116 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1117 // This can't be combined with the previous argument. Add a new one.
1118 reorderedArgs.push_back({argument.fArgIndex,
1119 ComponentArray{argument.fComponent}});
1120 } else {
1121 // Since we know this argument uses components, it should already
1122 // have at least one component set.
1123 SkASSERT(!reorderedArgs.back().fComponents.empty());
1124 // Build up the current argument with one more component.
1125 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1126 }
John Stiles0777ac42020-11-19 11:06:47 -05001127 }
1128 }
John Stilesd9076cb2020-11-19 12:18:36 -05001129
1130 // Convert our reordered argument list to an actual array of expressions, with
1131 // the new order and any new inner swizzles that need to be applied. Note that
1132 // we expect followup passes to clean up the inner swizzles.
1133 ExpressionArray newArgs;
1134 newArgs.reserve_back(swizzleSize);
1135 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1136 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1137 if (reorderedArg.fComponents.empty()) {
1138 newArgs.push_back(baseArg.clone());
1139 } else {
1140 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1141 reorderedArg.fComponents));
1142 }
1143 }
1144
1145 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001146 replacement = std::make_unique<Constructor>(
1147 base.fOffset,
John Stiles54f00492021-02-19 11:46:10 -05001148 componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
John Stiles0777ac42020-11-19 11:06:47 -05001149 std::move(newArgs));
1150
John Stilesa60ac0c2020-12-22 08:59:51 -05001151 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001152 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001153
1154 // We're replacing an expression with a cloned version; we'll need a rescan.
1155 try_replace_expression(&b, iter, &replacement);
1156 optimizationContext->fUpdated = true;
1157 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001158 }
John Stiles108bbe22020-11-18 11:10:38 -05001159 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001160 }
John Stiles30212b72020-06-11 17:55:07 -04001161 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001162 }
1163 default:
1164 break;
1165 }
1166}
1167
1168void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001169 BasicBlock& b,
1170 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001171 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001172 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001173 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001174 switch (stmt->kind()) {
1175 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001176 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001177 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001178 (!varDecl.value() ||
1179 !varDecl.value()->hasSideEffects())) {
1180 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001181 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001182 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001183 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001184 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001185 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001186 // There can still be (soon to be removed) references to the variable at this point.
1187 // Allowing the VarDeclaration to be destroyed here will break those variable's
1188 // initialValue()s, so we hang on to them until optimization is finished.
1189 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1190 usage);
1191 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001192 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001193 }
1194 break;
1195 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001196 case Statement::Kind::kIf: {
John Stiles4633c912021-03-03 16:13:45 -05001197 // TODO(skia:11319): this optimization logic is redundant with the optimization code
1198 // found in IfStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001199 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001200 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001201 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001202 if (i.test()->as<BoolLiteral>().value()) {
1203 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001204 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001205 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001206 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001207 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001208 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001209 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001210 }
1211 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001212 optimizationContext->fUpdated = true;
1213 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001214 break;
1215 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001216 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001217 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001218 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001219 optimizationContext->fUpdated = true;
1220 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001221 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001222 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001223 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001224 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001225 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001226 (*iter)->setStatement(
1227 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001228 } else {
1229 // no if, no else, no test side effects, kill the whole if
1230 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001231 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001232 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001233 optimizationContext->fUpdated = true;
1234 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001235 }
1236 break;
1237 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001238 case Statement::Kind::kSwitch: {
John Stiles642cde22021-02-23 14:57:01 -05001239 // TODO(skia:11319): this optimization logic is redundant with the static-switch
1240 // optimization code found in SwitchStatement.cpp.
John Stilesa5a97b42020-08-18 11:19:07 -04001241 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001242 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001243 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001244 // switch is constant, replace it with the case that matches
1245 bool found = false;
1246 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001247 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1248 if (!c->value()) {
1249 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001250 continue;
1251 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001252 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001253 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001254 if (caseValue == switchValue) {
John Stiles642cde22021-02-23 14:57:01 -05001255 std::unique_ptr<Statement> newBlock =
1256 SwitchStatement::BlockForCase(&s.cases(), c.get(), s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001257 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001258 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001259 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001260 break;
1261 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001262 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001263 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001264 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1265 if (didInsert) {
1266 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001267 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001268 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001269 }
1270 return; // can't simplify
1271 }
1272 }
1273 }
1274 if (!found) {
1275 // no matching case. use default if it exists, or kill the whole thing
1276 if (defaultCase) {
John Stiles642cde22021-02-23 14:57:01 -05001277 std::unique_ptr<Statement> newBlock =
1278 SwitchStatement::BlockForCase(&s.cases(), defaultCase, s.symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001279 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001280 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001281 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001282 if (s.isStatic() &&
John Stilesd1204642021-02-17 16:30:02 -05001283 !fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesd6a5f4492021-02-11 15:46:11 -05001284 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1285 if (didInsert) {
1286 this->error(s.fOffset, "static switch contains non-static "
John Stiles04ca41a2021-02-23 09:58:04 -05001287 "conditional exit");
John Stilesd6a5f4492021-02-11 15:46:11 -05001288 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001289 }
1290 return; // can't simplify
1291 }
1292 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001293 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001294 }
1295 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001296 optimizationContext->fUpdated = true;
1297 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001298 }
1299 break;
1300 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001301 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001302 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001303 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001304 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001305 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001306 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001307 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001308 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001309 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001310 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001311 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001312 }
1313 break;
1314 }
1315 default:
1316 break;
1317 }
1318}
1319
Brian Osman010ce6a2020-10-19 16:34:10 -04001320bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001321 bool madeChanges = false;
1322
Ethan Nicholascb670962017-04-20 19:31:52 -04001323 CFG cfg = CFGGenerator().getCFG(f);
1324 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001325
John Stiles7247b482021-03-08 10:40:35 -05001326 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
John Stiles66c53b92021-02-20 08:00:43 -05001327 // Check for unreachable code.
1328 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
1329 const BasicBlock& block = cfg.fBlocks[i];
1330 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
1331 const BasicBlock::Node& node = block.fNodes[0];
1332 int offset = node.isStatement() ? (*node.statement())->fOffset
1333 : (*node.expression())->fOffset;
1334 this->error(offset, String("unreachable"));
1335 }
ethannicholas22f939e2016-10-13 13:25:34 -07001336 }
1337 }
1338 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001339 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001340 }
1341
Ethan Nicholascb670962017-04-20 19:31:52 -04001342 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001343 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001344 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001345 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001346 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001347 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001348 cfg = CFGGenerator().getCFG(f);
1349 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001350 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001351 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001352
John Stiles7d3f0892020-11-03 11:35:01 -05001353 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001354 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001355
1356 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1357 if (eliminatedBlockIds.test(blockId)) {
1358 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1359 optimizationContext.fUpdated = true;
1360 optimizationContext.fNeedsRescan = true;
1361 break;
1362 }
1363
1364 BasicBlock& b = cfg.fBlocks[blockId];
John Stiles7247b482021-03-08 10:40:35 -05001365 if (fContext->fConfig->fSettings.fDeadCodeElimination) {
John Stiles66c53b92021-02-20 08:00:43 -05001366 if (blockId > 0 && !b.fIsReachable) {
1367 // Block was reachable before optimization, but has since become unreachable. In
1368 // addition to being dead code, it's broken - since control flow can't reach it,
1369 // no prior variable definitions can reach it, and therefore variables might
1370 // look to have not been properly assigned. Kill it by replacing all statements
1371 // with Nops.
1372 for (BasicBlock::Node& node : b.fNodes) {
1373 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
1374 // Eliminating a node runs the risk of eliminating that node's exits as
1375 // well. Keep track of this and do a rescan if we are about to access
1376 // one of these.
1377 for (BlockId id : b.fExits) {
1378 eliminatedBlockIds.set(id);
1379 }
1380 node.setStatement(std::make_unique<Nop>(), usage);
1381 madeChanges = true;
John Stiles7d3f0892020-11-03 11:35:01 -05001382 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001383 }
John Stiles66c53b92021-02-20 08:00:43 -05001384 continue;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001385 }
Ethan Nicholas1de14812020-06-19 15:32:49 -04001386 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001387 DefinitionMap definitions = b.fBefore;
1388
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001389 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1390 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001391 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001392 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001393 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001394 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001395 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001396 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001397 break;
1398 }
John Stilese8a24922021-02-08 17:54:08 -05001399 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001400 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001401
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001402 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001403 break;
1404 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001405 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001406 madeChanges |= optimizationContext.fUpdated;
1407 } while (optimizationContext.fUpdated);
1408 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001409
John Stiles0cc193a2020-09-09 09:39:34 -04001410 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001411}
1412
Brian Osman32d53552020-09-23 13:55:20 -04001413std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001414 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001415 String text,
1416 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001417 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Brian Osmand010f652021-02-24 13:59:39 -05001418 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::convertProgram");
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001419
John Stilesdbd4e6f2021-02-16 13:29:15 -05001420 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001421
Brian Osman0006ad02020-11-18 15:38:39 -05001422 // Loading and optimizing our base module might reset the inliner, so do that first,
1423 // *then* configure the inliner with the settings for this program.
1424 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1425
John Stiles270cec22021-02-17 12:59:36 -05001426 // Update our context to point to the program configuration for the duration of compilation.
1427 auto config = std::make_unique<ProgramConfig>(ProgramConfig{kind, settings});
John Stilesa935c3f2021-02-25 10:35:49 -05001428 AutoProgramConfig autoConfig(fContext, config.get());
John Stiles270cec22021-02-17 12:59:36 -05001429
John Stiles7247b482021-03-08 10:40:35 -05001430 // Honor our global optimization-disable flags.
1431 config->fSettings.fOptimize &= gSkSLOptimizer;
1432 config->fSettings.fControlFlowAnalysis &= gSkSLControlFlowAnalysis;
1433 config->fSettings.fInlineThreshold *= (int)gSkSLInliner;
1434
1435 // Disable optimization settings that depend on a parent setting which has been disabled.
1436 config->fSettings.fControlFlowAnalysis &= config->fSettings.fOptimize;
1437 config->fSettings.fInlineThreshold *= (int)config->fSettings.fOptimize;
1438 config->fSettings.fDeadCodeElimination &= config->fSettings.fControlFlowAnalysis;
1439
ethannicholasb3058bd2016-07-01 08:22:01 -07001440 fErrorText = "";
1441 fErrorCount = 0;
John Stilesd1204642021-02-17 16:30:02 -05001442 fInliner.reset(fIRGenerator->fModifiers.get());
Brian Osman88cda172020-10-09 12:05:16 -04001443
1444 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001445 std::unique_ptr<String> textPtr(new String(std::move(text)));
1446 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001447
John Stiles5c7bb322020-10-22 11:09:15 -04001448 // Enable node pooling while converting and optimizing the program for a performance boost.
1449 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001450 std::unique_ptr<Pool> pool;
John Stilesc1a98b82021-02-24 13:35:02 -05001451 if (fContext->fCaps.useNodePools()) {
Brian Osman28f702c2021-02-02 11:52:07 -05001452 pool = Pool::Create();
1453 pool->attachToThread();
1454 }
John Stilesd1204642021-02-17 16:30:02 -05001455 IRGenerator::IRBundle ir = fIRGenerator->convertProgram(baseModule, /*isBuiltinCode=*/false,
1456 textPtr->c_str(), textPtr->size(),
1457 externalFunctions);
John Stiles270cec22021-02-17 12:59:36 -05001458 auto program = std::make_unique<Program>(std::move(textPtr),
1459 std::move(config),
John Stiles5c7bb322020-10-22 11:09:15 -04001460 fContext,
1461 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001462 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001463 std::move(ir.fModifiers),
1464 std::move(ir.fSymbolTable),
1465 std::move(pool),
1466 ir.fInputs);
1467 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001468 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001469 // Do not return programs that failed to compile.
John Stiles7247b482021-03-08 10:40:35 -05001470 } else if (!this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001471 // Do not return programs that failed to optimize.
1472 } else {
1473 // We have a successful program!
1474 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001475 }
John Stiles5c7bb322020-10-22 11:09:15 -04001476
Brian Osman28f702c2021-02-02 11:52:07 -05001477 if (program->fPool) {
1478 program->fPool->detachFromThread();
1479 }
John Stiles5c7bb322020-10-22 11:09:15 -04001480 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001481}
1482
John Stilesbb1505f2021-02-12 09:17:53 -05001483void Compiler::verifyStaticTests(const Program& program) {
1484 class StaticTestVerifier : public ProgramVisitor {
1485 public:
1486 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1487
1488 using ProgramVisitor::visitProgramElement;
1489
1490 bool visitStatement(const Statement& stmt) override {
1491 switch (stmt.kind()) {
1492 case Statement::Kind::kIf:
1493 if (stmt.as<IfStatement>().isStatic()) {
1494 fReporter->error(stmt.fOffset, "static if has non-static test");
1495 }
1496 break;
1497
1498 case Statement::Kind::kSwitch:
1499 if (stmt.as<SwitchStatement>().isStatic()) {
1500 fReporter->error(stmt.fOffset, "static switch has non-static test");
1501 }
1502 break;
1503
1504 default:
1505 break;
1506 }
1507 return INHERITED::visitStatement(stmt);
1508 }
1509
John Stiles59e34562021-02-12 16:56:39 -05001510 bool visitExpression(const Expression&) override {
1511 // We aren't looking for anything inside an Expression, so skip them entirely.
1512 return false;
1513 }
1514
John Stilesbb1505f2021-02-12 09:17:53 -05001515 private:
1516 using INHERITED = ProgramVisitor;
1517 ErrorReporter* fReporter;
1518 };
1519
1520 // If invalid static tests are permitted, we don't need to check anything.
John Stilesd1204642021-02-17 16:30:02 -05001521 if (fContext->fConfig->fSettings.fPermitInvalidStaticTests) {
John Stilesbb1505f2021-02-12 09:17:53 -05001522 return;
1523 }
1524
1525 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1526 StaticTestVerifier visitor{this};
1527 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1528 if (element->is<FunctionDefinition>()) {
1529 visitor.visitProgramElement(*element);
1530 }
1531 }
1532}
1533
Brian Osman0006ad02020-11-18 15:38:39 -05001534bool Compiler::optimize(LoadedModule& module) {
1535 SkASSERT(!fErrorCount);
Brian Osman0006ad02020-11-18 15:38:39 -05001536
John Stiles270cec22021-02-17 12:59:36 -05001537 // Create a temporary program configuration with default settings.
1538 ProgramConfig config;
1539 config.fKind = module.fKind;
John Stilesa935c3f2021-02-25 10:35:49 -05001540 AutoProgramConfig autoConfig(fContext, &config);
John Stiles270cec22021-02-17 12:59:36 -05001541
John Stilesd1204642021-02-17 16:30:02 -05001542 // Reset the Inliner.
1543 fInliner.reset(fModifiers.back().get());
John Stiles270cec22021-02-17 12:59:36 -05001544
1545 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
Brian Osman0006ad02020-11-18 15:38:39 -05001546
1547 while (fErrorCount == 0) {
1548 bool madeChanges = false;
1549
1550 // Scan and optimize based on the control-flow graph for each function.
John Stiles7247b482021-03-08 10:40:35 -05001551 if (config.fSettings.fControlFlowAnalysis) {
John Stilesa935c3f2021-02-25 10:35:49 -05001552 for (const auto& element : module.fElements) {
1553 if (element->is<FunctionDefinition>()) {
1554 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1555 }
Brian Osman0006ad02020-11-18 15:38:39 -05001556 }
1557 }
1558
1559 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001560 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001561
1562 if (!madeChanges) {
1563 break;
1564 }
1565 }
1566 return fErrorCount == 0;
1567}
1568
Ethan Nicholas00543112018-07-31 09:44:36 -04001569bool Compiler::optimize(Program& program) {
John Stiles7247b482021-03-08 10:40:35 -05001570 // The optimizer only needs to run when it is enabled.
1571 if (!program.fConfig->fSettings.fOptimize) {
1572 return true;
1573 }
1574
Ethan Nicholas00543112018-07-31 09:44:36 -04001575 SkASSERT(!fErrorCount);
Brian Osman010ce6a2020-10-19 16:34:10 -04001576 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001577
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001578 while (fErrorCount == 0) {
1579 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001580
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001581 // Scan and optimize based on the control-flow graph for each function.
John Stiles7247b482021-03-08 10:40:35 -05001582 if (program.fConfig->fSettings.fControlFlowAnalysis) {
John Stiles0c7312a2021-02-24 11:31:32 -05001583 for (const auto& element : program.ownedElements()) {
1584 if (element->is<FunctionDefinition>()) {
1585 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
1586 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001587 }
1588 }
1589
1590 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001591 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001592
1593 // Remove dead functions. We wait until after analysis so that we still report errors,
1594 // even in unused code.
John Stiles270cec22021-02-17 12:59:36 -05001595 if (program.fConfig->fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001596 auto isDeadFunction = [&](const ProgramElement* element) {
1597 if (!element->is<FunctionDefinition>()) {
1598 return false;
1599 }
1600 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1601 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1602 usage->remove(*element);
1603 madeChanges = true;
1604 return true;
1605 }
1606 return false;
1607 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001608 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001609 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001610 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001611 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001612 }),
1613 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001614 program.fSharedElements.erase(
1615 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1616 isDeadFunction),
1617 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001618 }
1619
John Stiles270cec22021-02-17 12:59:36 -05001620 if (program.fConfig->fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001621 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001622 auto isDeadVariable = [&](const ProgramElement* element) {
1623 if (!element->is<GlobalVarDeclaration>()) {
1624 return false;
1625 }
1626 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1627 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1628 if (usage->isDead(varDecl.var())) {
1629 madeChanges = true;
1630 return true;
1631 }
1632 return false;
1633 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001634 program.fElements.erase(
1635 std::remove_if(program.fElements.begin(), program.fElements.end(),
1636 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001637 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001638 }),
1639 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001640 program.fSharedElements.erase(
1641 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1642 isDeadVariable),
1643 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001644 }
John Stiles73a6bff2020-09-09 13:40:37 -04001645
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001646 if (!madeChanges) {
1647 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001648 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001649 }
John Stilesbb1505f2021-02-12 09:17:53 -05001650
1651 if (fErrorCount == 0) {
1652 this->verifyStaticTests(program);
1653 }
1654
Ethan Nicholas00543112018-07-31 09:44:36 -04001655 return fErrorCount == 0;
1656}
1657
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001658#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1659
Ethan Nicholas00543112018-07-31 09:44:36 -04001660bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001661#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001662 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001663 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001664 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001665 bool result = cg.generateCode();
John Stiles270cec22021-02-17 12:59:36 -05001666 if (result && program.fConfig->fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001667 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001668 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001669 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001670 String errors;
1671 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1672 const char* m) {
1673 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001674 };
1675 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001676
1677 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1678 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1679 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1680 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1681
1682 if (!result) {
1683#if defined(SKSL_STANDALONE)
1684 // Convert the string-stream to a SPIR-V disassembly.
1685 std::string disassembly;
1686 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1687 errors.append(disassembly);
1688 }
1689 this->error(-1, errors);
1690#else
1691 SkDEBUGFAILF("%s", errors.c_str());
1692#endif
1693 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001694 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001695 }
1696#else
Brian Osman88cda172020-10-09 12:05:16 -04001697 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001698 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001699 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001700#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001701 return result;
1702}
1703
Ethan Nicholas00543112018-07-31 09:44:36 -04001704bool Compiler::toSPIRV(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->toSPIRV(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
Ethan Nicholas00543112018-07-31 09:44:36 -04001713bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osmand010f652021-02-24 13:59:39 -05001714 TRACE_EVENT0("skia.gpu", "SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001715 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001716 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001717 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001718 return result;
1719}
1720
Ethan Nicholas00543112018-07-31 09:44:36 -04001721bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001722 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001723 bool result = this->toGLSL(program, buffer);
1724 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001725 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001726 }
1727 return result;
1728}
1729
Brian Osmanc0243912020-02-19 15:35:26 -05001730bool Compiler::toHLSL(Program& program, String* out) {
1731 String spirv;
1732 if (!this->toSPIRV(program, &spirv)) {
1733 return false;
1734 }
1735
1736 return SPIRVtoHLSL(spirv, out);
1737}
1738
Ethan Nicholas00543112018-07-31 09:44:36 -04001739bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001740 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001741 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001742 return result;
1743}
1744
Ethan Nicholas00543112018-07-31 09:44:36 -04001745bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001746 StringStream buffer;
1747 bool result = this->toMetal(program, buffer);
1748 if (result) {
1749 *out = buffer.str();
1750 }
1751 return result;
1752}
1753
Greg Daniela28ea672020-09-25 11:12:56 -04001754#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001755bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001756 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001757 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001758 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001759 return result;
1760}
1761
Ethan Nicholas00543112018-07-31 09:44:36 -04001762bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001763 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001764 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001765 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001766 return result;
1767}
Greg Daniela28ea672020-09-25 11:12:56 -04001768#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001769
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001770#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001771
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001772Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001773 if (fSource && offset >= 0) {
1774 int line = 1;
1775 int column = 1;
1776 for (int i = 0; i < offset; i++) {
1777 if ((*fSource)[i] == '\n') {
1778 ++line;
1779 column = 1;
1780 }
1781 else {
1782 ++column;
1783 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001784 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001785 return Position(line, column);
1786 } else {
1787 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001788 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001789}
1790
1791void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001792 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001793 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001794 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001795 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001796}
1797
John Stiles8d3642e2021-01-22 09:50:04 -05001798void Compiler::setErrorCount(int c) {
1799 if (c < fErrorCount) {
1800 fErrorText.resize(fErrorTextLength[c]);
1801 fErrorTextLength.resize(c);
1802 fErrorCount = c;
1803 }
1804}
1805
Ethan Nicholas95046142021-01-07 10:57:27 -05001806String Compiler::errorText(bool showCount) {
1807 if (showCount) {
1808 this->writeErrorCount();
1809 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001810 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001811 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001812 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001813 return result;
1814}
1815
1816void Compiler::writeErrorCount() {
1817 if (fErrorCount) {
1818 fErrorText += to_string(fErrorCount) + " error";
1819 if (fErrorCount > 1) {
1820 fErrorText += "s";
1821 }
1822 fErrorText += "\n";
1823 }
1824}
1825
John Stilesa6841be2020-08-06 14:11:56 -04001826} // namespace SkSL