blob: bb06b1121a8ce30ac618e1a3d336d602632ea3f9 [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 Stilesb92641c2020-08-31 18:09:01 -040013#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/sksl/SkSLCFGGenerator.h"
15#include "src/sksl/SkSLCPPCodeGenerator.h"
16#include "src/sksl/SkSLGLSLCodeGenerator.h"
17#include "src/sksl/SkSLHCodeGenerator.h"
18#include "src/sksl/SkSLIRGenerator.h"
19#include "src/sksl/SkSLMetalCodeGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050020#include "src/sksl/SkSLOperators.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040021#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050023#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/sksl/ir/SkSLEnum.h"
25#include "src/sksl/ir/SkSLExpression.h"
26#include "src/sksl/ir/SkSLExpressionStatement.h"
27#include "src/sksl/ir/SkSLFunctionCall.h"
28#include "src/sksl/ir/SkSLIntLiteral.h"
29#include "src/sksl/ir/SkSLModifiersDeclaration.h"
30#include "src/sksl/ir/SkSLNop.h"
31#include "src/sksl/ir/SkSLSymbolTable.h"
32#include "src/sksl/ir/SkSLTernaryExpression.h"
33#include "src/sksl/ir/SkSLUnresolvedFunction.h"
34#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040035#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070036
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040037#include <fstream>
38
Ethan Nicholasa11035b2019-11-26 16:27:47 -050039#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
40#include "include/gpu/GrContextOptions.h"
41#include "src/gpu/GrShaderCaps.h"
42#endif
43
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040044#ifdef SK_ENABLE_SPIRV_VALIDATION
45#include "spirv-tools/libspirv.hpp"
46#endif
47
Brian Osman3d87e9f2020-10-08 11:50:22 -040048#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040049
Brian Osman3d87e9f2020-10-08 11:50:22 -040050// In standalone mode, we load the textual sksl source files. GN generates or copies these files
51// to the skslc executable directory. The "data" in this mode is just the filename.
52#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
53
54#else
55
56// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040057#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
58#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
59#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
60#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050061#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050062#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040063#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
64
Brian Osman3d87e9f2020-10-08 11:50:22 -040065#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
66 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040067
68#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040069
ethannicholasb3058bd2016-07-01 08:22:01 -070070namespace SkSL {
71
John Stiles47c0a742021-02-09 09:30:35 -050072using RefKind = VariableReference::RefKind;
73
Brian Osman88cda172020-10-09 12:05:16 -040074class AutoSource {
75public:
76 AutoSource(Compiler* compiler, const String* source)
77 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
78 fCompiler->fSource = source;
79 }
80
81 ~AutoSource() { fCompiler->fSource = fOldSource; }
82
83 Compiler* fCompiler;
84 const String* fOldSource;
85};
86
Brian Osmand7e76592020-11-02 12:26:22 -050087Compiler::Compiler(const ShaderCapsClass* caps, Flags flags)
John Stilesb30151e2021-01-11 16:13:08 -050088 : fContext(std::make_shared<Context>(/*errors=*/*this))
Brian Osman0006ad02020-11-18 15:38:39 -050089 , fCaps(caps)
John Stiles7b920442020-12-17 10:43:41 -050090 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050091 , fFlags(flags)
92 , fErrorCount(0) {
93 SkASSERT(fCaps);
John Stiles7c3515b2020-10-16 18:38:39 -040094 fRootSymbolTable = std::make_shared<SymbolTable>(this, /*builtin=*/true);
Brian Osmanb06301e2020-11-06 11:45:36 -050095 fPrivateSymbolTable = std::make_shared<SymbolTable>(fRootSymbolTable, /*builtin=*/true);
John Stilesb30151e2021-01-11 16:13:08 -050096 fIRGenerator = std::make_unique<IRGenerator>(fContext.get(), fCaps);
ethannicholasb3058bd2016-07-01 08:22:01 -070097
John Stiles54e7c052021-01-11 14:22:36 -050098#define TYPE(t) fContext->fTypes.f ## t .get()
ethannicholasb3058bd2016-07-01 08:22:01 -070099
Brian Osmanb06301e2020-11-06 11:45:36 -0500100 const SkSL::Symbol* rootTypes[] = {
101 TYPE(Void),
Brian Salomonbf7b6202016-11-11 16:08:03 -0500102
Brian Osmanb06301e2020-11-06 11:45:36 -0500103 TYPE( Float), TYPE( Float2), TYPE( Float3), TYPE( Float4),
104 TYPE( Half), TYPE( Half2), TYPE( Half3), TYPE( Half4),
105 TYPE( Int), TYPE( Int2), TYPE( Int3), TYPE( Int4),
Brian Osmanb06301e2020-11-06 11:45:36 -0500106 TYPE( Bool), TYPE( Bool2), TYPE( Bool3), TYPE( Bool4),
Brian Salomon2a51de82016-11-16 12:06:01 -0500107
Brian Osmanc0f2b642020-12-22 13:35:55 -0500108 TYPE(Float2x2), TYPE(Float3x3), TYPE(Float4x4),
Brian Osmanc63f4312020-12-23 11:44:14 -0500109 TYPE( Half2x2), TYPE( Half3x3), TYPE(Half4x4),
Greg Daniel64773e62016-11-22 09:44:03 -0500110
Brian Osmanc63f4312020-12-23 11:44:14 -0500111 TYPE(SquareMat), TYPE(SquareHMat),
ethannicholasb3058bd2016-07-01 08:22:01 -0700112
Brian Osman20fad322020-12-23 12:42:33 -0500113 TYPE(GenType), TYPE(GenHType), TYPE(GenIType), TYPE(GenBType),
114 TYPE(Vec), TYPE(HVec), TYPE(IVec), TYPE(BVec),
Brian Osmanb06301e2020-11-06 11:45:36 -0500115
116 TYPE(FragmentProcessor),
117 };
118
119 const SkSL::Symbol* privateTypes[] = {
Brian Osman20fad322020-12-23 12:42:33 -0500120 TYPE( UInt), TYPE( UInt2), TYPE( UInt3), TYPE( UInt4),
121 TYPE( Short), TYPE( Short2), TYPE( Short3), TYPE( Short4),
122 TYPE(UShort), TYPE(UShort2), TYPE(UShort3), TYPE(UShort4),
123 TYPE( Byte), TYPE( Byte2), TYPE( Byte3), TYPE( Byte4),
124 TYPE( UByte), TYPE( UByte2), TYPE( UByte3), TYPE( UByte4),
125
126 TYPE(GenUType), TYPE(UVec),
127 TYPE(SVec), TYPE(USVec), TYPE(ByteVec), TYPE(UByteVec),
128
Brian Osmanc0f2b642020-12-22 13:35:55 -0500129 TYPE(Float2x3), TYPE(Float2x4),
130 TYPE(Float3x2), TYPE(Float3x4),
131 TYPE(Float4x2), TYPE(Float4x3),
132
Brian Osmanc63f4312020-12-23 11:44:14 -0500133 TYPE(Half2x3), TYPE(Half2x4),
134 TYPE(Half3x2), TYPE(Half3x4),
135 TYPE(Half4x2), TYPE(Half4x3),
136
Brian Osmanc0f2b642020-12-22 13:35:55 -0500137 TYPE(Mat), TYPE(HMat),
138
Brian Osmanb06301e2020-11-06 11:45:36 -0500139 TYPE(Sampler1D), TYPE(Sampler2D), TYPE(Sampler3D),
140 TYPE(SamplerExternalOES),
Brian Osmanb06301e2020-11-06 11:45:36 -0500141 TYPE(Sampler2DRect),
Brian Osmanb06301e2020-11-06 11:45:36 -0500142
143 TYPE(ISampler2D),
144 TYPE(Image2D), TYPE(IImage2D),
145 TYPE(SubpassInput), TYPE(SubpassInputMS),
146
Brian Osmanb06301e2020-11-06 11:45:36 -0500147 TYPE(Sampler),
148 TYPE(Texture2D),
149 };
150
151 for (const SkSL::Symbol* type : rootTypes) {
152 fRootSymbolTable->addWithoutOwnership(type);
153 }
154 for (const SkSL::Symbol* type : privateTypes) {
155 fPrivateSymbolTable->addWithoutOwnership(type);
156 }
157
158#undef TYPE
ethannicholasb3058bd2016-07-01 08:22:01 -0700159
Brian Osman3887a012020-09-30 13:22:27 -0400160 // sk_Caps is "builtin", but all references to it are resolved to Settings, so we don't need to
161 // treat it as builtin (ie, no need to clone it into the Program).
Brian Osmanb06301e2020-11-06 11:45:36 -0500162 fPrivateSymbolTable->add(
163 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -0500164 fIRGenerator->fModifiers->addToPool(Modifiers()),
Brian Osmanb06301e2020-11-06 11:45:36 -0500165 "sk_Caps",
John Stiles54e7c052021-01-11 14:22:36 -0500166 fContext->fTypes.fSkCaps.get(),
Brian Osmanb06301e2020-11-06 11:45:36 -0500167 /*builtin=*/false,
168 Variable::Storage::kGlobal));
Ethan Nicholas3605ace2016-11-21 15:59:48 -0500169
Brian Osman3d87e9f2020-10-08 11:50:22 -0400170 fRootModule = {fRootSymbolTable, /*fIntrinsics=*/nullptr};
Brian Osmanb06301e2020-11-06 11:45:36 -0500171 fPrivateModule = {fPrivateSymbolTable, /*fIntrinsics=*/nullptr};
ethannicholasb3058bd2016-07-01 08:22:01 -0700172}
173
John Stilesdd13dba2020-10-29 10:45:34 -0400174Compiler::~Compiler() {}
ethannicholasb3058bd2016-07-01 08:22:01 -0700175
Brian Osman56269982020-11-20 12:38:07 -0500176const ParsedModule& Compiler::loadGPUModule() {
177 if (!fGPUModule.fSymbols) {
178 fGPUModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(gpu), fPrivateModule);
179 }
180 return fGPUModule;
181}
182
183const ParsedModule& Compiler::loadFragmentModule() {
184 if (!fFragmentModule.fSymbols) {
185 fFragmentModule = this->parseModule(Program::kFragment_Kind, MODULE_DATA(frag),
186 this->loadGPUModule());
187 }
188 return fFragmentModule;
189}
190
191const ParsedModule& Compiler::loadVertexModule() {
192 if (!fVertexModule.fSymbols) {
193 fVertexModule = this->parseModule(Program::kVertex_Kind, MODULE_DATA(vert),
194 this->loadGPUModule());
195 }
196 return fVertexModule;
197}
198
Brian Osman88cda172020-10-09 12:05:16 -0400199const ParsedModule& Compiler::loadGeometryModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400200 if (!fGeometryModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500201 fGeometryModule = this->parseModule(Program::kGeometry_Kind, MODULE_DATA(geom),
202 this->loadGPUModule());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400203 }
Brian Osman88cda172020-10-09 12:05:16 -0400204 return fGeometryModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400205}
206
Brian Osman88cda172020-10-09 12:05:16 -0400207const ParsedModule& Compiler::loadFPModule() {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400208 if (!fFPModule.fSymbols) {
Brian Osman56269982020-11-20 12:38:07 -0500209 fFPModule = this->parseModule(Program::kFragmentProcessor_Kind, MODULE_DATA(fp),
210 this->loadGPUModule());
Brian Osman8e2ef022020-09-30 13:26:43 -0400211 }
Brian Osman88cda172020-10-09 12:05:16 -0400212 return fFPModule;
Brian Osman8e2ef022020-09-30 13:26:43 -0400213}
214
Brian Osmanb06301e2020-11-06 11:45:36 -0500215const ParsedModule& Compiler::loadPublicModule() {
216 if (!fPublicModule.fSymbols) {
217 fPublicModule = this->parseModule(Program::kGeneric_Kind, MODULE_DATA(public), fRootModule);
218 }
219 return fPublicModule;
220}
221
Brian Osman91946752020-12-21 13:20:40 -0500222const ParsedModule& Compiler::loadRuntimeEffectModule() {
223 if (!fRuntimeEffectModule.fSymbols) {
224 fRuntimeEffectModule = this->parseModule(Program::kRuntimeEffect_Kind, MODULE_DATA(runtime),
225 this->loadPublicModule());
Brian Osmanf1319c32020-10-13 09:34:23 -0400226
Brian Osman91946752020-12-21 13:20:40 -0500227 // Add some aliases to the runtime effect module so that it's friendlier, and more like GLSL
John Stiles54e7c052021-01-11 14:22:36 -0500228 fRuntimeEffectModule.fSymbols->addAlias("shader", fContext->fTypes.fFragmentProcessor.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400229
John Stiles54e7c052021-01-11 14:22:36 -0500230 fRuntimeEffectModule.fSymbols->addAlias("vec2", fContext->fTypes.fFloat2.get());
231 fRuntimeEffectModule.fSymbols->addAlias("vec3", fContext->fTypes.fFloat3.get());
232 fRuntimeEffectModule.fSymbols->addAlias("vec4", fContext->fTypes.fFloat4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400233
John Stiles54e7c052021-01-11 14:22:36 -0500234 fRuntimeEffectModule.fSymbols->addAlias("bvec2", fContext->fTypes.fBool2.get());
235 fRuntimeEffectModule.fSymbols->addAlias("bvec3", fContext->fTypes.fBool3.get());
236 fRuntimeEffectModule.fSymbols->addAlias("bvec4", fContext->fTypes.fBool4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400237
John Stiles54e7c052021-01-11 14:22:36 -0500238 fRuntimeEffectModule.fSymbols->addAlias("mat2", fContext->fTypes.fFloat2x2.get());
239 fRuntimeEffectModule.fSymbols->addAlias("mat3", fContext->fTypes.fFloat3x3.get());
240 fRuntimeEffectModule.fSymbols->addAlias("mat4", fContext->fTypes.fFloat4x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400241
John Stiles54e7c052021-01-11 14:22:36 -0500242 fRuntimeEffectModule.fSymbols->addAlias("mat2x2", fContext->fTypes.fFloat2x2.get());
243 fRuntimeEffectModule.fSymbols->addAlias("mat2x3", fContext->fTypes.fFloat2x3.get());
244 fRuntimeEffectModule.fSymbols->addAlias("mat2x4", fContext->fTypes.fFloat2x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400245
John Stiles54e7c052021-01-11 14:22:36 -0500246 fRuntimeEffectModule.fSymbols->addAlias("mat3x2", fContext->fTypes.fFloat3x2.get());
247 fRuntimeEffectModule.fSymbols->addAlias("mat3x3", fContext->fTypes.fFloat3x3.get());
248 fRuntimeEffectModule.fSymbols->addAlias("mat3x4", fContext->fTypes.fFloat3x4.get());
Brian Osmanf1319c32020-10-13 09:34:23 -0400249
John Stiles54e7c052021-01-11 14:22:36 -0500250 fRuntimeEffectModule.fSymbols->addAlias("mat4x2", fContext->fTypes.fFloat4x2.get());
251 fRuntimeEffectModule.fSymbols->addAlias("mat4x3", fContext->fTypes.fFloat4x3.get());
252 fRuntimeEffectModule.fSymbols->addAlias("mat4x4", fContext->fTypes.fFloat4x4.get());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400253 }
Brian Osman91946752020-12-21 13:20:40 -0500254 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400255}
256
Brian Osman88cda172020-10-09 12:05:16 -0400257const ParsedModule& Compiler::moduleForProgramKind(Program::Kind kind) {
258 switch (kind) {
Brian Osman91946752020-12-21 13:20:40 -0500259 case Program::kVertex_Kind: return this->loadVertexModule(); break;
260 case Program::kFragment_Kind: return this->loadFragmentModule(); break;
261 case Program::kGeometry_Kind: return this->loadGeometryModule(); break;
262 case Program::kFragmentProcessor_Kind: return this->loadFPModule(); break;
263 case Program::kRuntimeEffect_Kind: return this->loadRuntimeEffectModule(); break;
Brian Osmance750362021-01-21 16:33:06 -0500264 case Program::kGeneric_Kind: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400265 }
266 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400267}
268
Brian Osman3d87e9f2020-10-08 11:50:22 -0400269LoadedModule Compiler::loadModule(Program::Kind kind,
270 ModuleData data,
271 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400272 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500273 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
274 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
275 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
276 // like samplers or textures. Today, 'Private' does contain the union of all known types,
277 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
278 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
279 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400280 }
281
282#if defined(SKSL_STANDALONE)
283 SkASSERT(data.fPath);
284 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400285 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
286 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400287 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400288 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400289 abort();
290 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400291 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400292 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400293 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400294 SkASSERT(fIRGenerator->fCanInline);
295 fIRGenerator->fCanInline = false;
Brian Osman88cda172020-10-09 12:05:16 -0400296 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500297 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500298 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500299 /*isBuiltinCode=*/true, source->c_str(), source->length(),
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500300 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400301 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500302 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400303 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400304 if (this->fErrorCount) {
305 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400306 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400307 }
Brian Osman88cda172020-10-09 12:05:16 -0400308 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400309#else
310 SkASSERT(data.fData && (data.fSize != 0));
311 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
312 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500313 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400314 fModifiers.push_back(fIRGenerator->releaseModifiers());
315#endif
316
317 return module;
318}
319
320ParsedModule Compiler::parseModule(Program::Kind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500321 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
322 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400323
324 // For modules that just declare (but don't define) intrinsic functions, there will be no new
325 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500326 if (module.fElements.empty()) {
327 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400328 }
329
330 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
331
332 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
333 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500334 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400335 switch (element->kind()) {
336 case ProgramElement::Kind::kFunction: {
337 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400338 SkASSERT(f.declaration().isBuiltin());
339 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400340 break;
341 }
John Stiles569249b2020-11-03 12:18:22 -0500342 case ProgramElement::Kind::kFunctionPrototype: {
343 // These are already in the symbol table.
344 break;
345 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400346 case ProgramElement::Kind::kEnum: {
347 const Enum& e = element->as<Enum>();
348 SkASSERT(e.isBuiltin());
349 intrinsics->insertOrDie(e.typeName(), std::move(element));
350 break;
351 }
352 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400353 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
354 const Variable& var = global.declaration()->as<VarDeclaration>().var();
355 SkASSERT(var.isBuiltin());
356 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400357 break;
358 }
359 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400360 const Variable& var = element->as<InterfaceBlock>().variable();
361 SkASSERT(var.isBuiltin());
362 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400363 break;
364 }
365 default:
366 printf("Unsupported element: %s\n", element->description().c_str());
367 SkASSERT(false);
368 break;
369 }
370 }
371
Brian Osman0006ad02020-11-18 15:38:39 -0500372 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400373}
374
John Stilese6150002020-10-05 12:03:53 -0400375void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700376 BasicBlock& block = cfg->fBlocks[blockId];
377
378 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500379 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700380 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500381 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700382 }
383
384 // propagate definitions to exits
385 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400386 if (exitId == blockId) {
387 continue;
388 }
ethannicholas22f939e2016-10-13 13:25:34 -0700389 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500390 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400391 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
392 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400393 // exit has no definition for it, just copy it and reprocess exit block
394 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500395 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700396 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500397 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400398 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700399 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400400 // definition has changed, merge and reprocess the exit block
401 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500402 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400403 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500404 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400405 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500406 }
ethannicholas22f939e2016-10-13 13:25:34 -0700407 }
408 }
John Stiles65b48272020-12-22 17:18:34 -0500409 }
ethannicholas22f939e2016-10-13 13:25:34 -0700410 }
411}
412
Ethan Nicholascb670962017-04-20 19:31:52 -0400413/**
414 * Returns true if assigning to this lvalue has no effect.
415 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400416static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400417 switch (lvalue.kind()) {
418 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400419 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400420 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400421 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400422 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400423 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400424 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400425 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400426 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400427 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400428 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400429 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400430 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400431 return !t.test()->hasSideEffects() &&
432 is_dead(*t.ifTrue(), usage) &&
433 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500434 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400435 default:
John Stileseada7bc2021-02-02 16:29:32 -0500436 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500437 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400438 }
439}
ethannicholas22f939e2016-10-13 13:25:34 -0700440
Ethan Nicholascb670962017-04-20 19:31:52 -0400441/**
442 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
443 * to a dead target and lack of side effects on the left hand side.
444 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400445static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
Brian Osman00185012021-02-04 16:07:11 -0500446 if (!Operators::IsAssignment(b.getOperator())) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400447 return false;
448 }
John Stiles2d4f9592020-10-30 10:29:12 -0400449 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400450}
451
452void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500453 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400454
455 // We set bits in the "processed" set after a block has been scanned.
456 SkBitSet processedSet(cfg->fBlocks.size());
457 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
458 processedSet.set(*blockId);
459 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700460 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400461}
462
463/**
464 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
465 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
466 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
467 * need to be regenerated).
468 */
John Stilesafbf8992020-08-18 10:08:21 -0400469static bool try_replace_expression(BasicBlock* b,
470 std::vector<BasicBlock::Node>::iterator* iter,
471 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400472 std::unique_ptr<Expression>* target = (*iter)->expression();
473 if (!b->tryRemoveExpression(iter)) {
474 *target = std::move(*newExpression);
475 return false;
476 }
477 *target = std::move(*newExpression);
478 return b->tryInsertExpression(iter, target);
479}
480
481/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400482 * Returns true if the expression is a constant numeric literal with the specified value, or a
483 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400484 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400485template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400486static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400487 switch (expr.kind()) {
488 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400489 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400490
Ethan Nicholase6592142020-09-08 10:22:09 -0400491 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400492 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400493
Ethan Nicholase6592142020-09-08 10:22:09 -0400494 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400495 const Constructor& constructor = expr.as<Constructor>();
496 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400497 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400498 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400499 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500500 if (constructor.componentType().isFloat()) {
501 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400502 if (constructor.getFVecComponent(i) != value) {
503 return false;
504 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500505 }
506 return true;
507 } else if (constructor.componentType().isInteger()) {
508 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400509 if (constructor.getIVecComponent(i) != value) {
510 return false;
511 }
512 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500513 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400514 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500515 // Other types (e.g. boolean) might occur, but aren't supported here.
516 return false;
John Stiles9d944232020-08-19 09:56:49 -0400517
Ethan Nicholase6592142020-09-08 10:22:09 -0400518 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400519 SkASSERT(constructor.arguments().size() == 1);
520 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400521
522 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400523 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400524 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400525 }
526 return false;
527 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400528 default:
529 return false;
530 }
531}
532
533/**
534 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
535 * and CFG structures).
536 */
John Stilesafbf8992020-08-18 10:08:21 -0400537static void delete_left(BasicBlock* b,
538 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400539 Compiler::OptimizationContext* optimizationContext) {
540 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400541 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400542 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400543 Expression& left = *bin.left();
544 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400545 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400546 bool result;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400547 if (bin.getOperator() == Token::Kind::TK_EQ) {
548 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400549 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400550 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400551 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400552 // Remove references within LHS.
553 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400554 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400555 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400556 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400557 return;
558 }
559 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400560 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400561 return;
562 }
563 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400564 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400565 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400566 return;
567 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400568 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400569 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400570}
571
572/**
573 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
574 * CFG structures).
575 */
John Stilesafbf8992020-08-18 10:08:21 -0400576static void delete_right(BasicBlock* b,
577 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400578 Compiler::OptimizationContext* optimizationContext) {
579 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400580 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400581 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400582 std::unique_ptr<Expression>& leftPointer = bin.left();
583 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400584 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400585 // Remove references within RHS.
586 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400587 if (!b->tryRemoveExpressionBefore(iter, &right)) {
588 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400589 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400590 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400591 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400592 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400593 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400594 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400595 return;
596 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400597 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400598 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400599 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400600 return;
601 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400602 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400603 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400604}
605
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400606/**
607 * Constructs the specified type using a single argument.
608 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400609static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400610 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400611 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400612 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400613 return result;
614}
615
616/**
617 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
618 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
619 */
620static void vectorize(BasicBlock* b,
621 std::vector<BasicBlock::Node>::iterator* iter,
622 const Type& type,
623 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400624 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400625 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500626 SkASSERT(type.isVector());
627 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400628 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400629 std::unique_ptr<Expression>* target = (*iter)->expression();
630 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400631 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400632 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400633 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400634 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400635 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400636 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400637 }
638 }
639}
640
641/**
642 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
643 * left to yield vec<n>(x).
644 */
645static void vectorize_left(BasicBlock* b,
646 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400647 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400648 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400649 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400650 optimizationContext->fUsage->remove(bin.right().get());
651 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400652}
653
654/**
655 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
656 * right to yield vec<n>(y).
657 */
658static void vectorize_right(BasicBlock* b,
659 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400660 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400661 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400662 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400663 optimizationContext->fUsage->remove(bin.left().get());
664 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400665}
666
Ethan Nicholascb670962017-04-20 19:31:52 -0400667void Compiler::simplifyExpression(DefinitionMap& definitions,
668 BasicBlock& b,
669 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400670 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400671 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400672 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500673
Ethan Nicholascb670962017-04-20 19:31:52 -0400674 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400675 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
676 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400677 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400678 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400679 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400680 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400681 // Remove references within 'expr', add references within 'optimized'
682 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400683 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400684 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400685 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400686 }
John Stiles70025e52020-09-28 16:08:58 -0400687 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400688 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400689 }
690 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400691 switch (expr->kind()) {
692 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400693 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400694 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400695 if (ref.refKind() != VariableReference::RefKind::kWrite &&
696 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500697 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400698 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
699 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000700 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400701 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400702 }
703 break;
704 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400705 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400706 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400707 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400708 // ternary has a constant test, replace it with either the true or
709 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400710 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400711 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400712 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400713 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400714 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400715 optimizationContext->fUpdated = true;
716 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400717 }
718 break;
719 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400720 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400721 BinaryExpression* bin = &expr->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400722 if (dead_assignment(*bin, optimizationContext->fUsage)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400723 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400724 break;
725 }
John Stiles2d4f9592020-10-30 10:29:12 -0400726 Expression& left = *bin->left();
727 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400728 const Type& leftType = left.type();
729 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400730 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500731 if ((!leftType.isScalar() && !leftType.isVector()) ||
732 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400733 break;
734 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400735 switch (bin->getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400736 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400737 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500738 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400739 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400740 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400741 } else {
742 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400743 // 1 * float4(x) -> float4(x)
744 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400745 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400746 }
747 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400748 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500749 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400750 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400751 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400752 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400753 } else {
754 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400755 // float4(0) * x -> float4(0)
756 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400757 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400758 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500759 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400760 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400761 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400762 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500763 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400764 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400765 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400766 } else {
767 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400768 // float4(x) * 1 -> float4(x)
769 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400770 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400771 }
772 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400773 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500774 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400775 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400776 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400777 } else {
778 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400779 // x * float4(0) -> float4(0)
780 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400781 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400782 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500783 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400784 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400785 }
786 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400787 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400788 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500789 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400790 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400791 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400792 } else {
793 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400794 // 0 + float4(x) -> float4(x)
795 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400796 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400797 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400798 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500799 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400800 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400801 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400802 } else {
803 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400804 // float4(x) + 0 -> float4(x)
805 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400806 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400807 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400808 }
809 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400810 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400811 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500812 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400813 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400814 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400815 } else {
816 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400817 // float4(x) - 0 -> float4(x)
818 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400819 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400820 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400821 }
822 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400823 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400824 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500825 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400826 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400827 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400828 } else {
829 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400830 // float4(x) / 1 -> float4(x)
831 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400832 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400833 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400834 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500835 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400836 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400837 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400838 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400839 } else {
840 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400841 // float4(0) / x -> float4(0)
842 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400843 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400844 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500845 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400846 }
847 }
848 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400849 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400850 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500851 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400852 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400853 }
854 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400855 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400856 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500857 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400858 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400859 }
860 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400861 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400862 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500863 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400864 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400865 }
866 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400867 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400868 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500869 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400870 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400871 }
872 break;
873 default:
874 break;
875 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400876 break;
877 }
John Stilesf5c1d042020-11-21 23:26:07 -0500878 case Expression::Kind::kConstructor: {
879 // Find constructors embedded inside constructors and flatten them out where possible.
880 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
881 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
882 // Leave single-argument constructors alone, though. These might be casts or splats.
883 Constructor& c = expr->as<Constructor>();
884 if (c.type().columns() > 1) {
885 // Inspect each constructor argument to see if it's a candidate for flattening.
886 // Remember matched arguments in a bitfield, "argsToOptimize".
887 int argsToOptimize = 0;
888 int currBit = 1;
889 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
890 if (arg->is<Constructor>()) {
891 Constructor& inner = arg->as<Constructor>();
892 if (inner.arguments().size() > 1 &&
893 inner.type().componentType() == c.type().componentType()) {
894 argsToOptimize |= currBit;
895 }
896 }
897 currBit <<= 1;
898 }
899 if (argsToOptimize) {
900 // We found at least one argument that could be flattened out. Re-walk the
901 // constructor args and flatten the candidates we found during our initial pass.
902 ExpressionArray flattened;
903 flattened.reserve_back(c.type().columns());
904 currBit = 1;
905 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
906 if (argsToOptimize & currBit) {
907 Constructor& inner = arg->as<Constructor>();
908 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
909 flattened.push_back(innerArg->clone());
910 }
911 } else {
912 flattened.push_back(arg->clone());
913 }
914 currBit <<= 1;
915 }
916 auto optimized = std::unique_ptr<Expression>(
917 new Constructor(c.fOffset, &c.type(), std::move(flattened)));
918 // No fUsage change; no references have been added or removed anywhere.
919 optimizationContext->fUpdated = true;
920 if (!try_replace_expression(&b, iter, &optimized)) {
921 optimizationContext->fNeedsRescan = true;
922 return;
923 }
924 SkASSERT((*iter)->isExpression());
925 break;
926 }
927 }
928 break;
929 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400930 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400931 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500932 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400933 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400934 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400935 for (int i = 0; i < (int) s.components().size(); ++i) {
936 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400937 identity = false;
938 break;
939 }
940 }
941 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400942 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400943 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400944 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400945 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400946 return;
947 }
John Stiles70025e52020-09-28 16:08:58 -0400948 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400949 break;
950 }
951 }
John Stiles108bbe22020-11-18 11:10:38 -0500952 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
953 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400954 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400955 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400956 for (int c : s.components()) {
957 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400958 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400959 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400960 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500961 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500962 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500963 try_replace_expression(&b, iter, &replacement);
964 optimizationContext->fUpdated = true;
965 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -0500966 break;
967 }
968 // Optimize swizzles of constructors.
969 if (s.base()->is<Constructor>()) {
970 Constructor& base = s.base()->as<Constructor>();
971 std::unique_ptr<Expression> replacement;
972 const Type& componentType = base.type().componentType();
973 int swizzleSize = s.components().size();
974
975 // The IR generator has already converted any zero/one swizzle components into
976 // constructors containing zero/one args. Confirm that this is true by checking that
977 // our swizzle components are all `xyzw` (values 0 through 3).
978 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
979 [](int8_t c) { return c >= 0 && c <= 3; }));
980
John Stiles9aeed132020-11-24 17:36:06 -0500981 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -0500982 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
983 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -0500984 const Expression& argument = *base.arguments().front();
985 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
986 /*rows=*/1);
987 replacement = Constructor::SimplifyConversion(constructorType, argument);
988 if (!replacement) {
989 ExpressionArray newArgs;
990 newArgs.push_back(argument.clone());
991 replacement = std::make_unique<Constructor>(base.fOffset, &constructorType,
992 std::move(newArgs));
993 }
John Stiles108bbe22020-11-18 11:10:38 -0500994
John Stilesa60ac0c2020-12-22 08:59:51 -0500995 // We're replacing an expression with a cloned version; we'll need a rescan.
996 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
997 // reference counts.
998 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -0500999 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001000 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001001 break;
1002 }
1003
John Stiles0777ac42020-11-19 11:06:47 -05001004 // Swizzles can duplicate some elements and discard others, e.g.
1005 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1006 // - Expressions with side effects need to occur exactly once, even if they
1007 // would otherwise be swizzle-eliminated
1008 // - Non-trivial expressions should not be repeated, but elimination is OK.
1009 //
1010 // Look up the argument for the constructor at each index. This is typically simple
1011 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1012 // seems. This example would result in:
1013 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1014 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1015 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1016 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1017 struct ConstructorArgMap {
1018 int8_t fArgIndex;
1019 int8_t fComponent;
1020 };
1021
1022 int numConstructorArgs = base.type().columns();
1023 ConstructorArgMap argMap[4] = {};
1024 int writeIdx = 0;
1025 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1026 const Expression& expr = *base.arguments()[argIdx];
1027 int argWidth = expr.type().columns();
1028 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1029 argMap[writeIdx].fArgIndex = argIdx;
1030 argMap[writeIdx].fComponent = componentIdx;
1031 ++writeIdx;
1032 }
1033 }
1034 SkASSERT(writeIdx == numConstructorArgs);
1035
1036 // Count up the number of times each constructor argument is used by the
1037 // swizzle.
1038 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1039 // - bar.yz is referenced 3 times, by `.x_xy`
1040 // - half(foo) is referenced 1 time, by `._w__`
1041 int8_t exprUsed[4] = {};
1042 for (int c : s.components()) {
1043 exprUsed[argMap[c].fArgIndex]++;
1044 }
1045
1046 bool safeToOptimize = true;
1047 for (int index = 0; index < numConstructorArgs; ++index) {
1048 int8_t constructorArgIndex = argMap[index].fArgIndex;
1049 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1050
1051 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001052 if (exprUsed[constructorArgIndex] > 1 &&
1053 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001054 safeToOptimize = false;
1055 break;
1056 }
1057 // Check that side-effect-bearing expressions are swizzled in exactly once.
1058 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1059 safeToOptimize = false;
1060 break;
1061 }
1062 }
1063
1064 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001065 struct ReorderedArgument {
1066 int8_t fArgIndex;
1067 ComponentArray fComponents;
1068 };
1069 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001070 for (int c : s.components()) {
1071 const ConstructorArgMap& argument = argMap[c];
1072 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1073
John Stiles9aeed132020-11-24 17:36:06 -05001074 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001075 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001076 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001077 reorderedArgs.push_back({argument.fArgIndex,
1078 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001079 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001080 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001081 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001082 if (reorderedArgs.empty() ||
1083 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1084 // This can't be combined with the previous argument. Add a new one.
1085 reorderedArgs.push_back({argument.fArgIndex,
1086 ComponentArray{argument.fComponent}});
1087 } else {
1088 // Since we know this argument uses components, it should already
1089 // have at least one component set.
1090 SkASSERT(!reorderedArgs.back().fComponents.empty());
1091 // Build up the current argument with one more component.
1092 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1093 }
John Stiles0777ac42020-11-19 11:06:47 -05001094 }
1095 }
John Stilesd9076cb2020-11-19 12:18:36 -05001096
1097 // Convert our reordered argument list to an actual array of expressions, with
1098 // the new order and any new inner swizzles that need to be applied. Note that
1099 // we expect followup passes to clean up the inner swizzles.
1100 ExpressionArray newArgs;
1101 newArgs.reserve_back(swizzleSize);
1102 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1103 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1104 if (reorderedArg.fComponents.empty()) {
1105 newArgs.push_back(baseArg.clone());
1106 } else {
1107 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1108 reorderedArg.fComponents));
1109 }
1110 }
1111
1112 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001113 replacement = std::make_unique<Constructor>(
1114 base.fOffset,
1115 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1116 std::move(newArgs));
1117
John Stilesa60ac0c2020-12-22 08:59:51 -05001118 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001119 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001120
1121 // We're replacing an expression with a cloned version; we'll need a rescan.
1122 try_replace_expression(&b, iter, &replacement);
1123 optimizationContext->fUpdated = true;
1124 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001125 }
John Stiles108bbe22020-11-18 11:10:38 -05001126 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001127 }
John Stiles30212b72020-06-11 17:55:07 -04001128 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001129 }
1130 default:
1131 break;
1132 }
1133}
1134
John Stiles92219b42020-06-15 12:32:24 -04001135// Returns true if this statement could potentially execute a break at the current level. We ignore
1136// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001137static bool contains_conditional_break(Statement& stmt) {
1138 class ContainsConditionalBreak : public ProgramVisitor {
1139 public:
1140 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001141 switch (stmt.kind()) {
1142 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001143 return this->INHERITED::visitStatement(stmt);
1144
Ethan Nicholase6592142020-09-08 10:22:09 -04001145 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001146 return fInConditional > 0;
1147
Ethan Nicholase6592142020-09-08 10:22:09 -04001148 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001149 ++fInConditional;
1150 bool result = this->INHERITED::visitStatement(stmt);
1151 --fInConditional;
1152 return result;
1153 }
1154
1155 default:
1156 return false;
1157 }
1158 }
1159
1160 int fInConditional = 0;
1161 using INHERITED = ProgramVisitor;
1162 };
1163
1164 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001165}
1166
Ethan Nicholas5005a222018-08-24 13:06:27 -04001167// returns true if this statement definitely executes a break at the current level (we ignore
1168// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001169static bool contains_unconditional_break(Statement& stmt) {
1170 class ContainsUnconditionalBreak : public ProgramVisitor {
1171 public:
1172 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001173 switch (stmt.kind()) {
1174 case Statement::Kind::kBlock:
John Stilesb92641c2020-08-31 18:09:01 -04001175 return this->INHERITED::visitStatement(stmt);
1176
Ethan Nicholase6592142020-09-08 10:22:09 -04001177 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001178 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001179
1180 default:
1181 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001182 }
John Stilesb92641c2020-08-31 18:09:01 -04001183 }
John Stiles92219b42020-06-15 12:32:24 -04001184
John Stilesb92641c2020-08-31 18:09:01 -04001185 using INHERITED = ProgramVisitor;
1186 };
John Stiles92219b42020-06-15 12:32:24 -04001187
John Stilesb92641c2020-08-31 18:09:01 -04001188 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001189}
1190
John Stiles8f2a0cf2020-10-13 12:48:21 -04001191static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001192 switch (stmt->kind()) {
1193 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001194 // Recurse into the block.
1195 Block& block = static_cast<Block&>(*stmt);
1196
John Stiles8f2a0cf2020-10-13 12:48:21 -04001197 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001198 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001199 for (std::unique_ptr<Statement>& stmt : block.children()) {
1200 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001201 }
John Stiles92219b42020-06-15 12:32:24 -04001202
1203 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001204 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001205 break;
John Stiles92219b42020-06-15 12:32:24 -04001206 }
1207
Ethan Nicholase6592142020-09-08 10:22:09 -04001208 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001209 // Do not append a break to the target.
1210 break;
1211
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001212 default:
John Stiles92219b42020-06-15 12:32:24 -04001213 // Append normal statements to the target.
1214 target->push_back(std::move(stmt));
1215 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001216 }
1217}
1218
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001219// Returns a block containing all of the statements that will be run if the given case matches
1220// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1221// broken by this call and must then be discarded).
1222// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1223// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001224static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1225 SwitchCase* caseToCapture) {
1226 // We have to be careful to not move any of the pointers until after we're sure we're going to
1227 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1228 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001229 auto iter = switchStatement->cases().begin();
1230 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001231 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001232 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001233 }
John Stiles92219b42020-06-15 12:32:24 -04001234 }
1235
1236 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1237 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1238 // statements that we can use for simplification.
1239 auto startIter = iter;
1240 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001241 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001242 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001243 if (contains_conditional_break(*stmt)) {
1244 // We can't reduce switch-cases to a block when they have conditional breaks.
1245 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001246 }
John Stiles92219b42020-06-15 12:32:24 -04001247
1248 if (contains_unconditional_break(*stmt)) {
1249 // We found an unconditional break. We can use this block, but we need to strip
1250 // out the break statement.
1251 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001252 break;
1253 }
1254 }
John Stiles92219b42020-06-15 12:32:24 -04001255
1256 if (unconditionalBreakStmt != nullptr) {
1257 break;
1258 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001259 }
John Stiles92219b42020-06-15 12:32:24 -04001260
1261 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1262 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001263 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001264
1265 // We can move over most of the statements as-is.
1266 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001267 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001268 caseStmts.push_back(std::move(stmt));
1269 }
1270 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001271 }
John Stiles92219b42020-06-15 12:32:24 -04001272
1273 // If we found an unconditional break at the end, we need to move what we can while avoiding
1274 // that break.
1275 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001276 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001277 if (stmt.get() == unconditionalBreakStmt) {
1278 move_all_but_break(stmt, &caseStmts);
1279 unconditionalBreakStmt = nullptr;
1280 break;
1281 }
1282
1283 caseStmts.push_back(std::move(stmt));
1284 }
1285 }
1286
1287 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1288
1289 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001290 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001291}
1292
Ethan Nicholascb670962017-04-20 19:31:52 -04001293void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001294 BasicBlock& b,
1295 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001296 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001297 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001298 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001299 switch (stmt->kind()) {
1300 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001301 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001302 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001303 (!varDecl.value() ||
1304 !varDecl.value()->hasSideEffects())) {
1305 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001306 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001307 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001308 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001309 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001310 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001311 // There can still be (soon to be removed) references to the variable at this point.
1312 // Allowing the VarDeclaration to be destroyed here will break those variable's
1313 // initialValue()s, so we hang on to them until optimization is finished.
1314 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1315 usage);
1316 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001317 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001318 }
1319 break;
1320 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001321 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001322 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001323 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001324 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001325 if (i.test()->as<BoolLiteral>().value()) {
1326 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001327 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001328 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001329 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001330 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001331 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001332 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001333 }
1334 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001335 optimizationContext->fUpdated = true;
1336 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001337 break;
1338 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001339 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001340 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001341 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001342 optimizationContext->fUpdated = true;
1343 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001344 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001345 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001346 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001347 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001348 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001349 (*iter)->setStatement(
1350 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001351 } else {
1352 // no if, no else, no test side effects, kill the whole if
1353 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001354 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001355 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001356 optimizationContext->fUpdated = true;
1357 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001358 }
1359 break;
1360 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001361 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001362 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001363 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001364 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001365 // switch is constant, replace it with the case that matches
1366 bool found = false;
1367 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001368 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1369 if (!c->value()) {
1370 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001371 continue;
1372 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001373 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001374 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001375 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001376 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001377 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001378 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001379 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001380 break;
1381 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001382 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1383 optimizationContext->fSilences.find(&s) ==
1384 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001385 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001386 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001387 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001388 }
1389 return; // can't simplify
1390 }
1391 }
1392 }
1393 if (!found) {
1394 // no matching case. use default if it exists, or kill the whole thing
1395 if (defaultCase) {
1396 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1397 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001398 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001399 } else {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001400 if (s.isStatic() && !(fFlags & kPermitInvalidStaticTests_Flag) &&
1401 optimizationContext->fSilences.find(&s) ==
1402 optimizationContext->fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001403 this->error(s.fOffset,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001404 "static switch contains non-static conditional break");
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001405 optimizationContext->fSilences.insert(&s);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001406 }
1407 return; // can't simplify
1408 }
1409 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001410 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001411 }
1412 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001413 optimizationContext->fUpdated = true;
1414 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001415 }
1416 break;
1417 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001418 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001419 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001420 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001421 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001422 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001423 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001424 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001425 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001426 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001427 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001428 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001429 }
1430 break;
1431 }
1432 default:
1433 break;
1434 }
1435}
1436
Brian Osman010ce6a2020-10-19 16:34:10 -04001437bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001438 bool madeChanges = false;
1439
Ethan Nicholascb670962017-04-20 19:31:52 -04001440 CFG cfg = CFGGenerator().getCFG(f);
1441 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001442
1443 // check for unreachable code
1444 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001445 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001446 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
John Stiles0cc193a2020-09-09 09:39:34 -04001447 const BasicBlock::Node& node = block.fNodes[0];
John Stilesc1129322021-02-03 10:13:42 -05001448 int offset = node.isStatement() ? (*node.statement())->fOffset
1449 : (*node.expression())->fOffset;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001450 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001451 }
1452 }
1453 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001454 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001455 }
1456
Ethan Nicholascb670962017-04-20 19:31:52 -04001457 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001458 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001459 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001460 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001461 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001462 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001463 cfg = CFGGenerator().getCFG(f);
1464 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001465 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001466 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001467
John Stiles7d3f0892020-11-03 11:35:01 -05001468 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001469 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001470
1471 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1472 if (eliminatedBlockIds.test(blockId)) {
1473 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1474 optimizationContext.fUpdated = true;
1475 optimizationContext.fNeedsRescan = true;
1476 break;
1477 }
1478
1479 BasicBlock& b = cfg.fBlocks[blockId];
1480 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001481 // Block was reachable before optimization, but has since become unreachable. In
1482 // addition to being dead code, it's broken - since control flow can't reach it, no
1483 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001484 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001485 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001486 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001487 // Eliminating a node runs the risk of eliminating that node's exits as
1488 // well. Keep track of this and do a rescan if we are about to access one
1489 // of these.
1490 for (BlockId id : b.fExits) {
1491 eliminatedBlockIds.set(id);
1492 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001493 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001494 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001495 }
1496 }
1497 continue;
1498 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001499 DefinitionMap definitions = b.fBefore;
1500
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001501 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1502 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001503 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001504 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001505 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001506 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001507 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001508 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001509 break;
1510 }
John Stilese8a24922021-02-08 17:54:08 -05001511 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001512 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001513
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001514 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001515 break;
1516 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001517 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001518 madeChanges |= optimizationContext.fUpdated;
1519 } while (optimizationContext.fUpdated);
1520 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001521
Ethan Nicholas91a10532017-06-22 11:24:38 -04001522 // verify static ifs & switches, clean up dead variable decls
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001523 for (BasicBlock& b : cfg.fBlocks) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001524 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1525 !optimizationContext.fNeedsRescan;) {
John Stiles70025e52020-09-28 16:08:58 -04001526 if (iter->isStatement()) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001527 const Statement& s = **iter->statement();
Ethan Nicholase6592142020-09-08 10:22:09 -04001528 switch (s.kind()) {
1529 case Statement::Kind::kIf:
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001530 if (s.as<IfStatement>().isStatic() &&
Ethan Nicholas6e1cbc02017-07-14 10:12:15 -04001531 !(fFlags & kPermitInvalidStaticTests_Flag)) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001532 this->error(s.fOffset, "static if has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001533 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001534 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001535 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04001536 case Statement::Kind::kSwitch:
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001537 if (s.as<SwitchStatement>().isStatic() &&
1538 !(fFlags & kPermitInvalidStaticTests_Flag) &&
1539 optimizationContext.fSilences.find(&s) ==
1540 optimizationContext.fSilences.end()) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001541 this->error(s.fOffset, "static switch has non-static test");
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001542 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001543 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001544 break;
1545 default:
Ethan Nicholas91a10532017-06-22 11:24:38 -04001546 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001547 break;
1548 }
Ethan Nicholas91a10532017-06-22 11:24:38 -04001549 } else {
1550 ++iter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001551 }
1552 }
1553 }
1554
ethannicholas22f939e2016-10-13 13:25:34 -07001555 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001556 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001557 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001558 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001559 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001560 }
1561 }
John Stiles0cc193a2020-09-09 09:39:34 -04001562
1563 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001564}
1565
Brian Osman32d53552020-09-23 13:55:20 -04001566std::unique_ptr<Program> Compiler::convertProgram(
1567 Program::Kind kind,
1568 String text,
1569 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001570 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
1571 SkASSERT(!externalFunctions || (kind == Program::kGeneric_Kind));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001572
Brian Osman0006ad02020-11-18 15:38:39 -05001573 // Loading and optimizing our base module might reset the inliner, so do that first,
1574 // *then* configure the inliner with the settings for this program.
1575 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1576
ethannicholasb3058bd2016-07-01 08:22:01 -07001577 fErrorText = "";
1578 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001579 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001580
1581 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001582 std::unique_ptr<String> textPtr(new String(std::move(text)));
1583 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001584
John Stiles5c7bb322020-10-22 11:09:15 -04001585 // Enable node pooling while converting and optimizing the program for a performance boost.
1586 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001587 std::unique_ptr<Pool> pool;
1588 if (fCaps->useNodePools()) {
1589 pool = Pool::Create();
1590 pool->attachToThread();
1591 }
Brian Osman0006ad02020-11-18 15:38:39 -05001592 IRGenerator::IRBundle ir =
1593 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001594 textPtr->c_str(), textPtr->size(), externalFunctions);
John Stiles5c7bb322020-10-22 11:09:15 -04001595 auto program = std::make_unique<Program>(kind,
1596 std::move(textPtr),
1597 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001598 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001599 fContext,
1600 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001601 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001602 std::move(ir.fModifiers),
1603 std::move(ir.fSymbolTable),
1604 std::move(pool),
1605 ir.fInputs);
1606 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001607 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001608 // Do not return programs that failed to compile.
1609 } else if (settings.fOptimize && !this->optimize(*program)) {
1610 // Do not return programs that failed to optimize.
1611 } else {
1612 // We have a successful program!
1613 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001614 }
John Stiles5c7bb322020-10-22 11:09:15 -04001615
Brian Osman28f702c2021-02-02 11:52:07 -05001616 if (program->fPool) {
1617 program->fPool->detachFromThread();
1618 }
John Stiles5c7bb322020-10-22 11:09:15 -04001619 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001620}
1621
Brian Osman0006ad02020-11-18 15:38:39 -05001622bool Compiler::optimize(LoadedModule& module) {
1623 SkASSERT(!fErrorCount);
1624 Program::Settings settings;
1625 fIRGenerator->fKind = module.fKind;
1626 fIRGenerator->fSettings = &settings;
1627 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1628
1629 fInliner.reset(fModifiers.back().get(), &settings);
1630
1631 while (fErrorCount == 0) {
1632 bool madeChanges = false;
1633
1634 // Scan and optimize based on the control-flow graph for each function.
1635 for (const auto& element : module.fElements) {
1636 if (element->is<FunctionDefinition>()) {
1637 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1638 }
1639 }
1640
1641 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001642 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001643
1644 if (!madeChanges) {
1645 break;
1646 }
1647 }
1648 return fErrorCount == 0;
1649}
1650
Ethan Nicholas00543112018-07-31 09:44:36 -04001651bool Compiler::optimize(Program& program) {
1652 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001653 fIRGenerator->fKind = program.fKind;
1654 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001655 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001656
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001657 while (fErrorCount == 0) {
1658 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001659
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001660 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001661 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001662 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001663 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001664 }
1665 }
1666
1667 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001668 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001669
1670 // Remove dead functions. We wait until after analysis so that we still report errors,
1671 // even in unused code.
1672 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001673 auto isDeadFunction = [&](const ProgramElement* element) {
1674 if (!element->is<FunctionDefinition>()) {
1675 return false;
1676 }
1677 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1678 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1679 usage->remove(*element);
1680 madeChanges = true;
1681 return true;
1682 }
1683 return false;
1684 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001685 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001686 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001687 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001688 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001689 }),
1690 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001691 program.fSharedElements.erase(
1692 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1693 isDeadFunction),
1694 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001695 }
1696
1697 if (program.fKind != Program::kFragmentProcessor_Kind) {
Brian Osmanc0213602020-10-06 14:43:32 -04001698 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001699 auto isDeadVariable = [&](const ProgramElement* element) {
1700 if (!element->is<GlobalVarDeclaration>()) {
1701 return false;
1702 }
1703 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1704 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1705 if (usage->isDead(varDecl.var())) {
1706 madeChanges = true;
1707 return true;
1708 }
1709 return false;
1710 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001711 program.fElements.erase(
1712 std::remove_if(program.fElements.begin(), program.fElements.end(),
1713 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001714 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001715 }),
1716 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001717 program.fSharedElements.erase(
1718 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1719 isDeadVariable),
1720 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001721 }
John Stiles73a6bff2020-09-09 13:40:37 -04001722
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001723 if (!madeChanges) {
1724 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001725 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001726 }
1727 return fErrorCount == 0;
1728}
1729
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001730#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1731
Ethan Nicholas00543112018-07-31 09:44:36 -04001732bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001733#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001734 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001735 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001736 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001737 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001738 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001739 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001740 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001741 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001742 String errors;
1743 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1744 const char* m) {
1745 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001746 };
1747 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001748
1749 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1750 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1751 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1752 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1753
1754 if (!result) {
1755#if defined(SKSL_STANDALONE)
1756 // Convert the string-stream to a SPIR-V disassembly.
1757 std::string disassembly;
1758 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1759 errors.append(disassembly);
1760 }
1761 this->error(-1, errors);
1762#else
1763 SkDEBUGFAILF("%s", errors.c_str());
1764#endif
1765 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001766 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001767 }
1768#else
Brian Osman88cda172020-10-09 12:05:16 -04001769 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001770 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001771 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001772#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001773 return result;
1774}
1775
Ethan Nicholas00543112018-07-31 09:44:36 -04001776bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001777 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001778 bool result = this->toSPIRV(program, buffer);
1779 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001780 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001781 }
1782 return result;
1783}
1784
Ethan Nicholas00543112018-07-31 09:44:36 -04001785bool Compiler::toGLSL(Program& program, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001786 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001787 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001788 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001789 return result;
1790}
1791
Ethan Nicholas00543112018-07-31 09:44:36 -04001792bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001793 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001794 bool result = this->toGLSL(program, buffer);
1795 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001796 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001797 }
1798 return result;
1799}
1800
Brian Osmanc0243912020-02-19 15:35:26 -05001801bool Compiler::toHLSL(Program& program, String* out) {
1802 String spirv;
1803 if (!this->toSPIRV(program, &spirv)) {
1804 return false;
1805 }
1806
1807 return SPIRVtoHLSL(spirv, out);
1808}
1809
Ethan Nicholas00543112018-07-31 09:44:36 -04001810bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001811 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001812 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001813 return result;
1814}
1815
Ethan Nicholas00543112018-07-31 09:44:36 -04001816bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001817 StringStream buffer;
1818 bool result = this->toMetal(program, buffer);
1819 if (result) {
1820 *out = buffer.str();
1821 }
1822 return result;
1823}
1824
Greg Daniela28ea672020-09-25 11:12:56 -04001825#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001826bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001827 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001828 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001829 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001830 return result;
1831}
1832
Ethan Nicholas00543112018-07-31 09:44:36 -04001833bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001834 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001835 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001836 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001837 return result;
1838}
Greg Daniela28ea672020-09-25 11:12:56 -04001839#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001840
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001841#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001842
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001843Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001844 if (fSource && offset >= 0) {
1845 int line = 1;
1846 int column = 1;
1847 for (int i = 0; i < offset; i++) {
1848 if ((*fSource)[i] == '\n') {
1849 ++line;
1850 column = 1;
1851 }
1852 else {
1853 ++column;
1854 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001855 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001856 return Position(line, column);
1857 } else {
1858 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001859 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001860}
1861
1862void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001863 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001864 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001865 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001866 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001867}
1868
John Stiles8d3642e2021-01-22 09:50:04 -05001869void Compiler::setErrorCount(int c) {
1870 if (c < fErrorCount) {
1871 fErrorText.resize(fErrorTextLength[c]);
1872 fErrorTextLength.resize(c);
1873 fErrorCount = c;
1874 }
1875}
1876
Ethan Nicholas95046142021-01-07 10:57:27 -05001877String Compiler::errorText(bool showCount) {
1878 if (showCount) {
1879 this->writeErrorCount();
1880 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001881 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001882 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001883 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001884 return result;
1885}
1886
1887void Compiler::writeErrorCount() {
1888 if (fErrorCount) {
1889 fErrorText += to_string(fErrorCount) + " error";
1890 if (fErrorCount > 1) {
1891 fErrorText += "s";
1892 }
1893 fErrorText += "\n";
1894 }
1895}
1896
John Stilesa6841be2020-08-06 14:11:56 -04001897} // namespace SkSL