blob: fbf47d8180c631895dbfa9b55ddd866a8217964e [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
Leon Scrogginsb66214e2021-02-11 17:14:18 -050013#include "src/core/SkTraceEvent.h"
John Stilesb92641c2020-08-31 18:09:01 -040014#include "src/sksl/SkSLAnalysis.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/sksl/SkSLCFGGenerator.h"
16#include "src/sksl/SkSLCPPCodeGenerator.h"
17#include "src/sksl/SkSLGLSLCodeGenerator.h"
18#include "src/sksl/SkSLHCodeGenerator.h"
19#include "src/sksl/SkSLIRGenerator.h"
20#include "src/sksl/SkSLMetalCodeGenerator.h"
Brian Osman00185012021-02-04 16:07:11 -050021#include "src/sksl/SkSLOperators.h"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040022#include "src/sksl/SkSLRehydrator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Brian Osmanc0243912020-02-19 15:35:26 -050024#include "src/sksl/SkSLSPIRVtoHLSL.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/sksl/ir/SkSLEnum.h"
26#include "src/sksl/ir/SkSLExpression.h"
27#include "src/sksl/ir/SkSLExpressionStatement.h"
28#include "src/sksl/ir/SkSLFunctionCall.h"
29#include "src/sksl/ir/SkSLIntLiteral.h"
30#include "src/sksl/ir/SkSLModifiersDeclaration.h"
31#include "src/sksl/ir/SkSLNop.h"
32#include "src/sksl/ir/SkSLSymbolTable.h"
33#include "src/sksl/ir/SkSLTernaryExpression.h"
34#include "src/sksl/ir/SkSLUnresolvedFunction.h"
35#include "src/sksl/ir/SkSLVarDeclarations.h"
John Stilese6150002020-10-05 12:03:53 -040036#include "src/utils/SkBitSet.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070037
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -040038#include <fstream>
39
Ethan Nicholasa11035b2019-11-26 16:27:47 -050040#if !defined(SKSL_STANDALONE) & SK_SUPPORT_GPU
41#include "include/gpu/GrContextOptions.h"
42#include "src/gpu/GrShaderCaps.h"
43#endif
44
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -040045#ifdef SK_ENABLE_SPIRV_VALIDATION
46#include "spirv-tools/libspirv.hpp"
47#endif
48
Brian Osman3d87e9f2020-10-08 11:50:22 -040049#if defined(SKSL_STANDALONE)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040050
Brian Osman3d87e9f2020-10-08 11:50:22 -040051// In standalone mode, we load the textual sksl source files. GN generates or copies these files
52// to the skslc executable directory. The "data" in this mode is just the filename.
53#define MODULE_DATA(name) MakeModulePath("sksl_" #name ".sksl")
54
55#else
56
57// At runtime, we load the dehydrated sksl data files. The data is a (pointer, size) pair.
Ethan Nicholasc18bb512020-07-28 14:46:53 -040058#include "src/sksl/generated/sksl_fp.dehydrated.sksl"
59#include "src/sksl/generated/sksl_frag.dehydrated.sksl"
60#include "src/sksl/generated/sksl_geom.dehydrated.sksl"
61#include "src/sksl/generated/sksl_gpu.dehydrated.sksl"
Brian Osmanb06301e2020-11-06 11:45:36 -050062#include "src/sksl/generated/sksl_public.dehydrated.sksl"
Brian Osman91946752020-12-21 13:20:40 -050063#include "src/sksl/generated/sksl_runtime.dehydrated.sksl"
Ethan Nicholasc18bb512020-07-28 14:46:53 -040064#include "src/sksl/generated/sksl_vert.dehydrated.sksl"
65
Brian Osman3d87e9f2020-10-08 11:50:22 -040066#define MODULE_DATA(name) MakeModuleData(SKSL_INCLUDE_sksl_##name,\
67 SKSL_INCLUDE_sksl_##name##_LENGTH)
Ethan Nicholasc18bb512020-07-28 14:46:53 -040068
69#endif
Ethan Nicholas0d997662019-04-08 09:46:01 -040070
ethannicholasb3058bd2016-07-01 08:22:01 -070071namespace SkSL {
72
John Stiles47c0a742021-02-09 09:30:35 -050073using RefKind = VariableReference::RefKind;
74
Brian Osman88cda172020-10-09 12:05:16 -040075class AutoSource {
76public:
77 AutoSource(Compiler* compiler, const String* source)
78 : fCompiler(compiler), fOldSource(fCompiler->fSource) {
79 fCompiler->fSource = source;
80 }
81
82 ~AutoSource() { fCompiler->fSource = fOldSource; }
83
84 Compiler* fCompiler;
85 const String* fOldSource;
86};
87
John Stilesd6a5f4492021-02-11 15:46:11 -050088Compiler::Compiler(const ShaderCapsClass* caps)
John Stilesb30151e2021-01-11 16:13:08 -050089 : fContext(std::make_shared<Context>(/*errors=*/*this))
Brian Osman0006ad02020-11-18 15:38:39 -050090 , fCaps(caps)
John Stiles7b920442020-12-17 10:43:41 -050091 , fInliner(fContext.get())
Brian Osman0006ad02020-11-18 15:38:39 -050092 , 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) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500178 fGPUModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(gpu), fPrivateModule);
Brian Osman56269982020-11-20 12:38:07 -0500179 }
180 return fGPUModule;
181}
182
183const ParsedModule& Compiler::loadFragmentModule() {
184 if (!fFragmentModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500185 fFragmentModule = this->parseModule(ProgramKind::kFragment, MODULE_DATA(frag),
Brian Osman56269982020-11-20 12:38:07 -0500186 this->loadGPUModule());
187 }
188 return fFragmentModule;
189}
190
191const ParsedModule& Compiler::loadVertexModule() {
192 if (!fVertexModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500193 fVertexModule = this->parseModule(ProgramKind::kVertex, MODULE_DATA(vert),
Brian Osman56269982020-11-20 12:38:07 -0500194 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) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500201 fGeometryModule = this->parseModule(ProgramKind::kGeometry, MODULE_DATA(geom),
Brian Osman56269982020-11-20 12:38:07 -0500202 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) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500209 fFPModule = this->parseModule(ProgramKind::kFragmentProcessor, MODULE_DATA(fp),
Brian Osman56269982020-11-20 12:38:07 -0500210 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) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500217 fPublicModule = this->parseModule(ProgramKind::kGeneric, MODULE_DATA(public), fRootModule);
Brian Osmanb06301e2020-11-06 11:45:36 -0500218 }
219 return fPublicModule;
220}
221
Brian Osman91946752020-12-21 13:20:40 -0500222const ParsedModule& Compiler::loadRuntimeEffectModule() {
223 if (!fRuntimeEffectModule.fSymbols) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500224 fRuntimeEffectModule = this->parseModule(ProgramKind::kRuntimeEffect, MODULE_DATA(runtime),
Brian Osman91946752020-12-21 13:20:40 -0500225 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());
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400241 }
Brian Osman91946752020-12-21 13:20:40 -0500242 return fRuntimeEffectModule;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400243}
244
John Stilesdbd4e6f2021-02-16 13:29:15 -0500245const ParsedModule& Compiler::moduleForProgramKind(ProgramKind kind) {
Brian Osman88cda172020-10-09 12:05:16 -0400246 switch (kind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -0500247 case ProgramKind::kVertex: return this->loadVertexModule(); break;
248 case ProgramKind::kFragment: return this->loadFragmentModule(); break;
249 case ProgramKind::kGeometry: return this->loadGeometryModule(); break;
250 case ProgramKind::kFragmentProcessor: return this->loadFPModule(); break;
251 case ProgramKind::kRuntimeEffect: return this->loadRuntimeEffectModule(); break;
252 case ProgramKind::kGeneric: return this->loadPublicModule(); break;
Brian Osman88cda172020-10-09 12:05:16 -0400253 }
254 SkUNREACHABLE;
Ethan Nicholasc18bb512020-07-28 14:46:53 -0400255}
256
John Stilesdbd4e6f2021-02-16 13:29:15 -0500257LoadedModule Compiler::loadModule(ProgramKind kind,
Brian Osman3d87e9f2020-10-08 11:50:22 -0400258 ModuleData data,
259 std::shared_ptr<SymbolTable> base) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400260 if (!base) {
Brian Osmanb06301e2020-11-06 11:45:36 -0500261 // NOTE: This is a workaround. The only time 'base' is null is when dehydrating includes.
262 // In that case, skslc doesn't know which module it's preparing, nor what the correct base
263 // module is. We can't use 'Root', because many GPU intrinsics reference private types,
264 // like samplers or textures. Today, 'Private' does contain the union of all known types,
265 // so this is safe. If we ever have types that only exist in 'Public' (for example), this
266 // logic needs to be smarter (by choosing the correct base for the module we're compiling).
267 base = fPrivateSymbolTable;
Brian Osman3d87e9f2020-10-08 11:50:22 -0400268 }
269
270#if defined(SKSL_STANDALONE)
271 SkASSERT(data.fPath);
272 std::ifstream in(data.fPath);
Brian Osmane498b3c2020-09-23 14:42:11 -0400273 std::unique_ptr<String> text = std::make_unique<String>(std::istreambuf_iterator<char>(in),
274 std::istreambuf_iterator<char>());
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400275 if (in.rdstate()) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400276 printf("error reading %s\n", data.fPath);
Ethan Nicholasb33fa3f2020-08-06 13:00:19 -0400277 abort();
278 }
Brian Osmane498b3c2020-09-23 14:42:11 -0400279 const String* source = fRootSymbolTable->takeOwnershipOfString(std::move(text));
Brian Osman88cda172020-10-09 12:05:16 -0400280 AutoSource as(this, source);
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400281 Program::Settings settings;
John Stiles881a10c2020-09-19 10:13:24 -0400282 SkASSERT(fIRGenerator->fCanInline);
283 fIRGenerator->fCanInline = false;
Brian Osmanf4738962021-02-11 11:17:36 -0500284 settings.fReplaceSettings = false;
John Stilesdbd4e6f2021-02-16 13:29:15 -0500285
Brian Osman88cda172020-10-09 12:05:16 -0400286 ParsedModule baseModule = {base, /*fIntrinsics=*/nullptr};
Brian Osmand7e76592020-11-02 12:26:22 -0500287 IRGenerator::IRBundle ir =
Brian Osman0006ad02020-11-18 15:38:39 -0500288 fIRGenerator->convertProgram(kind, &settings, baseModule,
Brian Osmand7e76592020-11-02 12:26:22 -0500289 /*isBuiltinCode=*/true, source->c_str(), source->length(),
Brian Osmanbe0b3b72021-01-06 14:27:35 -0500290 /*externalFunctions=*/nullptr);
Brian Osman133724c2020-10-28 14:14:39 -0400291 SkASSERT(ir.fSharedElements.empty());
Brian Osman0006ad02020-11-18 15:38:39 -0500292 LoadedModule module = { kind, std::move(ir.fSymbolTable), std::move(ir.fElements) };
John Stiles881a10c2020-09-19 10:13:24 -0400293 fIRGenerator->fCanInline = true;
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400294 if (this->fErrorCount) {
295 printf("Unexpected errors: %s\n", this->fErrorText.c_str());
Brian Osman3d87e9f2020-10-08 11:50:22 -0400296 SkDEBUGFAILF("%s %s\n", data.fPath, this->fErrorText.c_str());
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400297 }
Brian Osman88cda172020-10-09 12:05:16 -0400298 fModifiers.push_back(std::move(ir.fModifiers));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400299#else
300 SkASSERT(data.fData && (data.fSize != 0));
301 Rehydrator rehydrator(fContext.get(), fIRGenerator->fModifiers.get(), base, this,
302 data.fData, data.fSize);
Brian Osman0006ad02020-11-18 15:38:39 -0500303 LoadedModule module = { kind, rehydrator.symbolTable(), rehydrator.elements() };
Brian Osman3d87e9f2020-10-08 11:50:22 -0400304 fModifiers.push_back(fIRGenerator->releaseModifiers());
305#endif
306
307 return module;
308}
309
John Stilesdbd4e6f2021-02-16 13:29:15 -0500310ParsedModule Compiler::parseModule(ProgramKind kind, ModuleData data, const ParsedModule& base) {
Brian Osman0006ad02020-11-18 15:38:39 -0500311 LoadedModule module = this->loadModule(kind, data, base.fSymbols);
312 this->optimize(module);
Brian Osman3d87e9f2020-10-08 11:50:22 -0400313
314 // For modules that just declare (but don't define) intrinsic functions, there will be no new
315 // program elements. In that case, we can share our parent's intrinsic map:
Brian Osman0006ad02020-11-18 15:38:39 -0500316 if (module.fElements.empty()) {
317 return {module.fSymbols, base.fIntrinsics};
Brian Osman3d87e9f2020-10-08 11:50:22 -0400318 }
319
320 auto intrinsics = std::make_shared<IRIntrinsicMap>(base.fIntrinsics.get());
321
322 // Now, transfer all of the program elements to an intrinsic map. This maps certain types of
323 // global objects to the declaring ProgramElement.
Brian Osman0006ad02020-11-18 15:38:39 -0500324 for (std::unique_ptr<ProgramElement>& element : module.fElements) {
Brian Osman3d87e9f2020-10-08 11:50:22 -0400325 switch (element->kind()) {
326 case ProgramElement::Kind::kFunction: {
327 const FunctionDefinition& f = element->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -0400328 SkASSERT(f.declaration().isBuiltin());
329 intrinsics->insertOrDie(f.declaration().description(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400330 break;
331 }
John Stiles569249b2020-11-03 12:18:22 -0500332 case ProgramElement::Kind::kFunctionPrototype: {
333 // These are already in the symbol table.
334 break;
335 }
Brian Osman3d87e9f2020-10-08 11:50:22 -0400336 case ProgramElement::Kind::kEnum: {
337 const Enum& e = element->as<Enum>();
338 SkASSERT(e.isBuiltin());
339 intrinsics->insertOrDie(e.typeName(), std::move(element));
340 break;
341 }
342 case ProgramElement::Kind::kGlobalVar: {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -0400343 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
344 const Variable& var = global.declaration()->as<VarDeclaration>().var();
345 SkASSERT(var.isBuiltin());
346 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400347 break;
348 }
349 case ProgramElement::Kind::kInterfaceBlock: {
Ethan Nicholaseaf47882020-10-15 10:10:08 -0400350 const Variable& var = element->as<InterfaceBlock>().variable();
351 SkASSERT(var.isBuiltin());
352 intrinsics->insertOrDie(var.name(), std::move(element));
Brian Osman3d87e9f2020-10-08 11:50:22 -0400353 break;
354 }
355 default:
356 printf("Unsupported element: %s\n", element->description().c_str());
357 SkASSERT(false);
358 break;
359 }
360 }
361
Brian Osman0006ad02020-11-18 15:38:39 -0500362 return {module.fSymbols, std::move(intrinsics)};
Ethan Nicholas8da1e652019-05-24 11:01:59 -0400363}
364
John Stilese6150002020-10-05 12:03:53 -0400365void Compiler::scanCFG(CFG* cfg, BlockId blockId, SkBitSet* processedSet) {
ethannicholas22f939e2016-10-13 13:25:34 -0700366 BasicBlock& block = cfg->fBlocks[blockId];
367
368 // compute definitions after this block
Ethan Nicholas86a43402017-01-19 13:32:00 -0500369 DefinitionMap after = block.fBefore;
ethannicholas22f939e2016-10-13 13:25:34 -0700370 for (const BasicBlock::Node& n : block.fNodes) {
John Stilese8a24922021-02-08 17:54:08 -0500371 after.addDefinitions(*fContext, n);
ethannicholas22f939e2016-10-13 13:25:34 -0700372 }
373
374 // propagate definitions to exits
375 for (BlockId exitId : block.fExits) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400376 if (exitId == blockId) {
377 continue;
378 }
ethannicholas22f939e2016-10-13 13:25:34 -0700379 BasicBlock& exit = cfg->fBlocks[exitId];
John Stiles65b48272020-12-22 17:18:34 -0500380 for (const auto& [var, e1] : after) {
John Stiles796cdb72020-10-08 12:06:53 -0400381 std::unique_ptr<Expression>** exitDef = exit.fBefore.find(var);
382 if (!exitDef) {
John Stilese6150002020-10-05 12:03:53 -0400383 // exit has no definition for it, just copy it and reprocess exit block
384 processedSet->reset(exitId);
John Stilese8a24922021-02-08 17:54:08 -0500385 exit.fBefore.set(var, e1);
ethannicholas22f939e2016-10-13 13:25:34 -0700386 } else {
Ethan Nicholas86a43402017-01-19 13:32:00 -0500387 // exit has a (possibly different) value already defined
John Stiles796cdb72020-10-08 12:06:53 -0400388 std::unique_ptr<Expression>* e2 = *exitDef;
ethannicholas22f939e2016-10-13 13:25:34 -0700389 if (e1 != e2) {
John Stilese6150002020-10-05 12:03:53 -0400390 // definition has changed, merge and reprocess the exit block
391 processedSet->reset(exitId);
Ethan Nicholasaf197692017-02-27 13:26:45 -0500392 if (e1 && e2) {
John Stiles796cdb72020-10-08 12:06:53 -0400393 *exitDef = (std::unique_ptr<Expression>*)&fContext->fDefined_Expression;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500394 } else {
John Stiles796cdb72020-10-08 12:06:53 -0400395 *exitDef = nullptr;
Ethan Nicholasaf197692017-02-27 13:26:45 -0500396 }
ethannicholas22f939e2016-10-13 13:25:34 -0700397 }
398 }
John Stiles65b48272020-12-22 17:18:34 -0500399 }
ethannicholas22f939e2016-10-13 13:25:34 -0700400 }
401}
402
Ethan Nicholascb670962017-04-20 19:31:52 -0400403/**
404 * Returns true if assigning to this lvalue has no effect.
405 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400406static bool is_dead(const Expression& lvalue, ProgramUsage* usage) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400407 switch (lvalue.kind()) {
408 case Expression::Kind::kVariableReference:
Brian Osman010ce6a2020-10-19 16:34:10 -0400409 return usage->isDead(*lvalue.as<VariableReference>().variable());
Ethan Nicholase6592142020-09-08 10:22:09 -0400410 case Expression::Kind::kSwizzle:
Brian Osman010ce6a2020-10-19 16:34:10 -0400411 return is_dead(*lvalue.as<Swizzle>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400412 case Expression::Kind::kFieldAccess:
Brian Osman010ce6a2020-10-19 16:34:10 -0400413 return is_dead(*lvalue.as<FieldAccess>().base(), usage);
Ethan Nicholase6592142020-09-08 10:22:09 -0400414 case Expression::Kind::kIndex: {
John Stilesa5a97b42020-08-18 11:19:07 -0400415 const IndexExpression& idx = lvalue.as<IndexExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400416 return is_dead(*idx.base(), usage) &&
Ethan Nicholas2a4952d2020-10-08 15:35:56 -0400417 !idx.index()->hasProperty(Expression::Property::kSideEffects);
Ethan Nicholascb670962017-04-20 19:31:52 -0400418 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400419 case Expression::Kind::kTernary: {
John Stilesa5a97b42020-08-18 11:19:07 -0400420 const TernaryExpression& t = lvalue.as<TernaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400421 return !t.test()->hasSideEffects() &&
422 is_dead(*t.ifTrue(), usage) &&
423 is_dead(*t.ifFalse(), usage);
Ethan Nicholasa583b812018-01-18 13:32:11 -0500424 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400425 default:
John Stileseada7bc2021-02-02 16:29:32 -0500426 SkDEBUGFAILF("invalid lvalue: %s\n", lvalue.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500427 return false;
Ethan Nicholascb670962017-04-20 19:31:52 -0400428 }
429}
ethannicholas22f939e2016-10-13 13:25:34 -0700430
Ethan Nicholascb670962017-04-20 19:31:52 -0400431/**
432 * Returns true if this is an assignment which can be collapsed down to just the right hand side due
433 * to a dead target and lack of side effects on the left hand side.
434 */
Brian Osman010ce6a2020-10-19 16:34:10 -0400435static bool dead_assignment(const BinaryExpression& b, ProgramUsage* usage) {
John Stiles45990502021-02-16 10:55:27 -0500436 if (!b.getOperator().isAssignment()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400437 return false;
438 }
John Stiles2d4f9592020-10-30 10:29:12 -0400439 return is_dead(*b.left(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400440}
441
John Stiles0ac6c152021-02-10 14:04:24 -0500442/**
443 * Returns true if both expression trees are the same. The left side is expected to be an lvalue.
444 * This only needs to check for trees that can plausibly terminate in a variable, so some basic
445 * candidates like `FloatLiteral` are missing.
446 */
447static bool is_matching_expression_tree(const Expression& left, const Expression& right) {
448 if (left.kind() != right.kind() || left.type() != right.type()) {
449 return false;
450 }
451
452 switch (left.kind()) {
453 case Expression::Kind::kIntLiteral:
454 return left.as<IntLiteral>().value() == right.as<IntLiteral>().value();
455
456 case Expression::Kind::kFieldAccess:
457 return left.as<FieldAccess>().fieldIndex() == right.as<FieldAccess>().fieldIndex() &&
458 is_matching_expression_tree(*left.as<FieldAccess>().base(),
459 *right.as<FieldAccess>().base());
460
461 case Expression::Kind::kIndex:
462 return is_matching_expression_tree(*left.as<IndexExpression>().index(),
463 *right.as<IndexExpression>().index()) &&
464 is_matching_expression_tree(*left.as<IndexExpression>().base(),
465 *right.as<IndexExpression>().base());
466
467 case Expression::Kind::kSwizzle:
468 return left.as<Swizzle>().components() == right.as<Swizzle>().components() &&
469 is_matching_expression_tree(*left.as<Swizzle>().base(),
470 *right.as<Swizzle>().base());
471
472 case Expression::Kind::kVariableReference:
473 return left.as<VariableReference>().variable() ==
474 right.as<VariableReference>().variable();
475
476 default:
477 return false;
478 }
479}
480
481static bool self_assignment(const BinaryExpression& b) {
John Stiles45990502021-02-16 10:55:27 -0500482 return b.getOperator().kind() == Token::Kind::TK_EQ &&
John Stiles0ac6c152021-02-10 14:04:24 -0500483 is_matching_expression_tree(*b.left(), *b.right());
484}
485
Ethan Nicholascb670962017-04-20 19:31:52 -0400486void Compiler::computeDataFlow(CFG* cfg) {
John Stilese8a24922021-02-08 17:54:08 -0500487 cfg->fBlocks[cfg->fStart].fBefore.computeStartState(*cfg);
John Stilese6150002020-10-05 12:03:53 -0400488
489 // We set bits in the "processed" set after a block has been scanned.
490 SkBitSet processedSet(cfg->fBlocks.size());
491 while (SkBitSet::OptionalIndex blockId = processedSet.findFirstUnset()) {
492 processedSet.set(*blockId);
493 this->scanCFG(cfg, *blockId, &processedSet);
ethannicholas22f939e2016-10-13 13:25:34 -0700494 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400495}
496
497/**
498 * Attempts to replace the expression pointed to by iter with a new one (in both the CFG and the
499 * IR). If the expression can be cleanly removed, returns true and updates the iterator to point to
500 * the newly-inserted element. Otherwise updates only the IR and returns false (and the CFG will
501 * need to be regenerated).
502 */
John Stilesafbf8992020-08-18 10:08:21 -0400503static bool try_replace_expression(BasicBlock* b,
504 std::vector<BasicBlock::Node>::iterator* iter,
505 std::unique_ptr<Expression>* newExpression) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400506 std::unique_ptr<Expression>* target = (*iter)->expression();
507 if (!b->tryRemoveExpression(iter)) {
508 *target = std::move(*newExpression);
509 return false;
510 }
511 *target = std::move(*newExpression);
512 return b->tryInsertExpression(iter, target);
513}
514
515/**
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400516 * Returns true if the expression is a constant numeric literal with the specified value, or a
517 * constant vector with all elements equal to the specified value.
Ethan Nicholascb670962017-04-20 19:31:52 -0400518 */
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400519template <typename T = SKSL_FLOAT>
John Stiles9d944232020-08-19 09:56:49 -0400520static bool is_constant(const Expression& expr, T value) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400521 switch (expr.kind()) {
522 case Expression::Kind::kIntLiteral:
Ethan Nicholase96cdd12020-09-28 16:27:18 -0400523 return expr.as<IntLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400524
Ethan Nicholase6592142020-09-08 10:22:09 -0400525 case Expression::Kind::kFloatLiteral:
Ethan Nicholasa3f22f12020-10-01 12:13:17 -0400526 return expr.as<FloatLiteral>().value() == value;
John Stiles9d944232020-08-19 09:56:49 -0400527
Ethan Nicholase6592142020-09-08 10:22:09 -0400528 case Expression::Kind::kConstructor: {
John Stiles9d944232020-08-19 09:56:49 -0400529 const Constructor& constructor = expr.as<Constructor>();
530 if (constructor.isCompileTimeConstant()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400531 const Type& constructorType = constructor.type();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400532 switch (constructorType.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400533 case Type::TypeKind::kVector:
John Stilesbc75ebb2020-11-24 12:04:47 -0500534 if (constructor.componentType().isFloat()) {
535 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400536 if (constructor.getFVecComponent(i) != value) {
537 return false;
538 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500539 }
540 return true;
541 } else if (constructor.componentType().isInteger()) {
542 for (int i = 0; i < constructorType.columns(); ++i) {
John Stiles9d944232020-08-19 09:56:49 -0400543 if (constructor.getIVecComponent(i) != value) {
544 return false;
545 }
546 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500547 return true;
Ethan Nicholasd188c182019-06-10 15:55:38 -0400548 }
John Stilesbc75ebb2020-11-24 12:04:47 -0500549 // Other types (e.g. boolean) might occur, but aren't supported here.
550 return false;
John Stiles9d944232020-08-19 09:56:49 -0400551
Ethan Nicholase6592142020-09-08 10:22:09 -0400552 case Type::TypeKind::kScalar:
Ethan Nicholasf70f0442020-09-29 12:41:35 -0400553 SkASSERT(constructor.arguments().size() == 1);
554 return is_constant<T>(*constructor.arguments()[0], value);
John Stiles9d944232020-08-19 09:56:49 -0400555
556 default:
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400557 return false;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400558 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400559 }
560 return false;
561 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400562 default:
563 return false;
564 }
565}
566
567/**
568 * Collapses the binary expression pointed to by iter down to just the right side (in both the IR
569 * and CFG structures).
570 */
John Stilesafbf8992020-08-18 10:08:21 -0400571static void delete_left(BasicBlock* b,
572 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400573 Compiler::OptimizationContext* optimizationContext) {
574 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400575 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400576 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400577 Expression& left = *bin.left();
578 std::unique_ptr<Expression>& rightPointer = bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400579 SkASSERT(!left.hasSideEffects());
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400580 bool result;
John Stiles45990502021-02-16 10:55:27 -0500581 if (bin.getOperator().kind() == Token::Kind::TK_EQ) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400582 result = b->tryRemoveLValueBefore(iter, &left);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400583 } else {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400584 result = b->tryRemoveExpressionBefore(iter, &left);
Ethan Nicholascb670962017-04-20 19:31:52 -0400585 }
Brian Osman010ce6a2020-10-19 16:34:10 -0400586 // Remove references within LHS.
587 optimizationContext->fUsage->remove(&left);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400588 *target = std::move(rightPointer);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400589 if (!result) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400590 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400591 return;
592 }
593 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400594 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400595 return;
596 }
597 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400598 if (!(*iter)->isExpression() || (*iter)->expression() != &rightPointer) {
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
606/**
607 * Collapses the binary expression pointed to by iter down to just the left side (in both the IR and
608 * CFG structures).
609 */
John Stilesafbf8992020-08-18 10:08:21 -0400610static void delete_right(BasicBlock* b,
611 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400612 Compiler::OptimizationContext* optimizationContext) {
613 optimizationContext->fUpdated = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400614 std::unique_ptr<Expression>* target = (*iter)->expression();
John Stilesa5a97b42020-08-18 11:19:07 -0400615 BinaryExpression& bin = (*target)->as<BinaryExpression>();
John Stiles2d4f9592020-10-30 10:29:12 -0400616 std::unique_ptr<Expression>& leftPointer = bin.left();
617 Expression& right = *bin.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400618 SkASSERT(!right.hasSideEffects());
Brian Osman010ce6a2020-10-19 16:34:10 -0400619 // Remove references within RHS.
620 optimizationContext->fUsage->remove(&right);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400621 if (!b->tryRemoveExpressionBefore(iter, &right)) {
622 *target = std::move(leftPointer);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400623 optimizationContext->fNeedsRescan = true;
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400624 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400625 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400626 *target = std::move(leftPointer);
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400627 if (*iter == b->fNodes.begin()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400628 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400629 return;
630 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400631 --(*iter);
John Stiles70025e52020-09-28 16:08:58 -0400632 if ((!(*iter)->isExpression() || (*iter)->expression() != &leftPointer)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400633 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400634 return;
635 }
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400636 *iter = b->fNodes.erase(*iter);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400637 SkASSERT((*iter)->expression() == target);
Ethan Nicholascb670962017-04-20 19:31:52 -0400638}
639
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400640/**
641 * Constructs the specified type using a single argument.
642 */
Ethan Nicholas30d30222020-09-11 12:27:26 -0400643static std::unique_ptr<Expression> construct(const Type* type, std::unique_ptr<Expression> v) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400644 ExpressionArray args;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400645 args.push_back(std::move(v));
Ethan Nicholase6592142020-09-08 10:22:09 -0400646 std::unique_ptr<Expression> result = std::make_unique<Constructor>(-1, type, std::move(args));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400647 return result;
648}
649
650/**
651 * Used in the implementations of vectorize_left and vectorize_right. Given a vector type and an
652 * expression x, deletes the expression pointed to by iter and replaces it with <type>(x).
653 */
654static void vectorize(BasicBlock* b,
655 std::vector<BasicBlock::Node>::iterator* iter,
656 const Type& type,
657 std::unique_ptr<Expression>* otherExpression,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400658 Compiler::OptimizationContext* optimizationContext) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400659 SkASSERT((*(*iter)->expression())->kind() == Expression::Kind::kBinary);
John Stiles9aeed132020-11-24 17:36:06 -0500660 SkASSERT(type.isVector());
661 SkASSERT((*otherExpression)->type().isScalar());
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400662 optimizationContext->fUpdated = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400663 std::unique_ptr<Expression>* target = (*iter)->expression();
664 if (!b->tryRemoveExpression(iter)) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400665 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400666 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400667 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400668 *target = construct(&type, std::move(*otherExpression));
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400669 if (!b->tryInsertExpression(iter, target)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400670 optimizationContext->fNeedsRescan = true;
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400671 }
672 }
673}
674
675/**
676 * Given a binary expression of the form x <op> vec<n>(y), deletes the right side and vectorizes the
677 * left to yield vec<n>(x).
678 */
679static void vectorize_left(BasicBlock* b,
680 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400681 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400682 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400683 // Remove references within RHS. Vectorization of LHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400684 optimizationContext->fUsage->remove(bin.right().get());
685 vectorize(b, iter, bin.right()->type(), &bin.left(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400686}
687
688/**
689 * Given a binary expression of the form vec<n>(x) <op> y, deletes the left side and vectorizes the
690 * right to yield vec<n>(y).
691 */
692static void vectorize_right(BasicBlock* b,
693 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400694 Compiler::OptimizationContext* optimizationContext) {
John Stilesa5a97b42020-08-18 11:19:07 -0400695 BinaryExpression& bin = (*(*iter)->expression())->as<BinaryExpression>();
Brian Osman010ce6a2020-10-19 16:34:10 -0400696 // Remove references within LHS. Vectorization of RHS doesn't change reference counts.
John Stiles2d4f9592020-10-30 10:29:12 -0400697 optimizationContext->fUsage->remove(bin.left().get());
698 vectorize(b, iter, bin.left()->type(), &bin.right(), optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400699}
700
Ethan Nicholascb670962017-04-20 19:31:52 -0400701void Compiler::simplifyExpression(DefinitionMap& definitions,
702 BasicBlock& b,
703 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400704 OptimizationContext* optimizationContext) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400705 Expression* expr = (*iter)->expression()->get();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400706 SkASSERT(expr);
John Stiles108bbe22020-11-18 11:10:38 -0500707
Ethan Nicholascb670962017-04-20 19:31:52 -0400708 if ((*iter)->fConstantPropagation) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400709 std::unique_ptr<Expression> optimized = expr->constantPropagate(*fIRGenerator,
710 definitions);
Ethan Nicholascb670962017-04-20 19:31:52 -0400711 if (optimized) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400712 optimizationContext->fUpdated = true;
Ethan Nicholas30d30222020-09-11 12:27:26 -0400713 optimized = fIRGenerator->coerce(std::move(optimized), expr->type());
Ethan Nicholas1d881522020-09-11 09:32:54 -0400714 SkASSERT(optimized);
Brian Osman010ce6a2020-10-19 16:34:10 -0400715 // Remove references within 'expr', add references within 'optimized'
716 optimizationContext->fUsage->replace(expr, optimized.get());
Ethan Nicholascb670962017-04-20 19:31:52 -0400717 if (!try_replace_expression(&b, iter, &optimized)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400718 optimizationContext->fNeedsRescan = true;
Ethan Nicholas4b330df2017-05-17 10:52:55 -0400719 return;
Ethan Nicholascb670962017-04-20 19:31:52 -0400720 }
John Stiles70025e52020-09-28 16:08:58 -0400721 SkASSERT((*iter)->isExpression());
Ethan Nicholascb670962017-04-20 19:31:52 -0400722 expr = (*iter)->expression()->get();
Ethan Nicholascb670962017-04-20 19:31:52 -0400723 }
724 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400725 switch (expr->kind()) {
726 case Expression::Kind::kVariableReference: {
John Stilesa5a97b42020-08-18 11:19:07 -0400727 const VariableReference& ref = expr->as<VariableReference>();
Ethan Nicholas78686922020-10-08 06:46:27 -0400728 const Variable* var = ref.variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -0400729 if (ref.refKind() != VariableReference::RefKind::kWrite &&
730 ref.refKind() != VariableReference::RefKind::kPointer &&
John Stilese8a24922021-02-08 17:54:08 -0500731 var->storage() == Variable::Storage::kLocal && !definitions.get(var) &&
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400732 optimizationContext->fSilences.find(var) == optimizationContext->fSilences.end()) {
733 optimizationContext->fSilences.insert(var);
Ethan Nicholas82a62d22017-11-07 14:42:10 +0000734 this->error(expr->fOffset,
Ethan Nicholase2c49992020-10-05 11:49:11 -0400735 "'" + var->name() + "' has not been assigned");
Ethan Nicholascb670962017-04-20 19:31:52 -0400736 }
737 break;
738 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400739 case Expression::Kind::kTernary: {
John Stiles403a3632020-08-20 12:11:48 -0400740 TernaryExpression* t = &expr->as<TernaryExpression>();
Ethan Nicholasdd218162020-10-08 05:48:01 -0400741 if (t->test()->is<BoolLiteral>()) {
Ethan Nicholascb670962017-04-20 19:31:52 -0400742 // ternary has a constant test, replace it with either the true or
743 // false branch
Ethan Nicholasdd218162020-10-08 05:48:01 -0400744 if (t->test()->as<BoolLiteral>().value()) {
Brian Osman010ce6a2020-10-19 16:34:10 -0400745 (*iter)->setExpression(std::move(t->ifTrue()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400746 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -0400747 (*iter)->setExpression(std::move(t->ifFalse()), optimizationContext->fUsage);
Ethan Nicholascb670962017-04-20 19:31:52 -0400748 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400749 optimizationContext->fUpdated = true;
750 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -0400751 }
752 break;
753 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400754 case Expression::Kind::kBinary: {
John Stiles403a3632020-08-20 12:11:48 -0400755 BinaryExpression* bin = &expr->as<BinaryExpression>();
John Stiles0ac6c152021-02-10 14:04:24 -0500756 if (dead_assignment(*bin, optimizationContext->fUsage) || self_assignment(*bin)) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400757 delete_left(&b, iter, optimizationContext);
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400758 break;
759 }
John Stiles2d4f9592020-10-30 10:29:12 -0400760 Expression& left = *bin->left();
761 Expression& right = *bin->right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400762 const Type& leftType = left.type();
763 const Type& rightType = right.type();
Ethan Nicholasc2371a42017-05-05 10:04:06 -0400764 // collapse useless expressions like x * 1 or x + 0
John Stiles9aeed132020-11-24 17:36:06 -0500765 if ((!leftType.isScalar() && !leftType.isVector()) ||
766 (!rightType.isScalar() && !rightType.isVector())) {
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400767 break;
768 }
John Stiles45990502021-02-16 10:55:27 -0500769 switch (bin->getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400770 case Token::Kind::TK_STAR:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400771 if (is_constant(left, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500772 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400773 // float4(1) * x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400774 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400775 } else {
776 // 1 * x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400777 // 1 * float4(x) -> float4(x)
778 // float4(1) * float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400779 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400780 }
781 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400782 else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500783 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400784 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400785 // 0 * float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400786 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400787 } else {
788 // 0 * x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400789 // float4(0) * x -> float4(0)
790 // float4(0) * float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400791 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400792 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500793 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400794 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400795 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400796 else if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500797 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400798 // x * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400799 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400800 } else {
801 // x * 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400802 // float4(x) * 1 -> float4(x)
803 // float4(x) * float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400804 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400805 }
806 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400807 else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500808 if (leftType.isVector() && rightType.isScalar() && !left.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400809 // float4(x) * 0 -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400810 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400811 } else {
812 // x * 0 -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400813 // x * float4(0) -> float4(0)
814 // float4(x) * float4(0) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400815 if (!left.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400816 delete_left(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500817 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400818 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400819 }
820 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400821 case Token::Kind::TK_PLUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400822 if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500823 if (leftType.isVector() && rightType.isScalar()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400824 // float4(0) + x -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400825 vectorize_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400826 } else {
827 // 0 + x -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400828 // 0 + float4(x) -> float4(x)
829 // float4(0) + float4(x) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400830 delete_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400831 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400832 } else if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500833 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400834 // x + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400835 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400836 } else {
837 // x + 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400838 // float4(x) + 0 -> float4(x)
839 // float4(x) + float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400840 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400841 }
Ethan Nicholas56e42712017-04-21 10:23:37 -0400842 }
843 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400844 case Token::Kind::TK_MINUS:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400845 if (is_constant(right, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500846 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400847 // x - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400848 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400849 } else {
850 // x - 0 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400851 // float4(x) - 0 -> float4(x)
852 // float4(x) - float4(0) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400853 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400854 }
Ethan Nicholascb670962017-04-20 19:31:52 -0400855 }
856 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400857 case Token::Kind::TK_SLASH:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400858 if (is_constant(right, 1)) {
John Stiles9aeed132020-11-24 17:36:06 -0500859 if (leftType.isScalar() && rightType.isVector()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400860 // x / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400861 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400862 } else {
863 // x / 1 -> x
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400864 // float4(x) / 1 -> float4(x)
865 // float4(x) / float4(1) -> float4(x)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400866 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400867 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400868 } else if (is_constant(left, 0)) {
John Stiles9aeed132020-11-24 17:36:06 -0500869 if (leftType.isScalar() && rightType.isVector() &&
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400870 !right.hasSideEffects()) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400871 // 0 / float4(x) -> float4(0)
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400872 vectorize_left(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400873 } else {
874 // 0 / x -> 0
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400875 // float4(0) / x -> float4(0)
876 // float4(0) / float4(x) -> float4(0)
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400877 if (!right.hasSideEffects()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400878 delete_right(&b, iter, optimizationContext);
Ethan Nicholas51493ee2017-12-11 12:34:33 -0500879 }
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400880 }
881 }
882 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400883 case Token::Kind::TK_PLUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400884 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500885 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400886 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400887 }
888 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400889 case Token::Kind::TK_MINUSEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400890 if (is_constant(right, 0)) {
John Stiles47c0a742021-02-09 09:30:35 -0500891 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400892 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400893 }
894 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400895 case Token::Kind::TK_STAREQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400896 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500897 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400898 delete_right(&b, iter, optimizationContext);
Ethan Nicholasfe53e582017-04-27 16:24:51 -0400899 }
900 break;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -0400901 case Token::Kind::TK_SLASHEQ:
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -0400902 if (is_constant(right, 1)) {
John Stiles47c0a742021-02-09 09:30:35 -0500903 Analysis::UpdateRefKind(&left, RefKind::kRead);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400904 delete_right(&b, iter, optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -0400905 }
906 break;
907 default:
908 break;
909 }
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400910 break;
911 }
John Stilesf5c1d042020-11-21 23:26:07 -0500912 case Expression::Kind::kConstructor: {
913 // Find constructors embedded inside constructors and flatten them out where possible.
914 // - float4(float2(1, 2), 3, 4) --> float4(1, 2, 3, 4)
915 // - float4(w, float3(sin(x), cos(y), tan(z))) --> float4(w, sin(x), cos(y), tan(z))
916 // Leave single-argument constructors alone, though. These might be casts or splats.
917 Constructor& c = expr->as<Constructor>();
918 if (c.type().columns() > 1) {
919 // Inspect each constructor argument to see if it's a candidate for flattening.
920 // Remember matched arguments in a bitfield, "argsToOptimize".
921 int argsToOptimize = 0;
922 int currBit = 1;
923 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
924 if (arg->is<Constructor>()) {
925 Constructor& inner = arg->as<Constructor>();
926 if (inner.arguments().size() > 1 &&
927 inner.type().componentType() == c.type().componentType()) {
928 argsToOptimize |= currBit;
929 }
930 }
931 currBit <<= 1;
932 }
933 if (argsToOptimize) {
934 // We found at least one argument that could be flattened out. Re-walk the
935 // constructor args and flatten the candidates we found during our initial pass.
936 ExpressionArray flattened;
937 flattened.reserve_back(c.type().columns());
938 currBit = 1;
939 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
940 if (argsToOptimize & currBit) {
941 Constructor& inner = arg->as<Constructor>();
942 for (const std::unique_ptr<Expression>& innerArg : inner.arguments()) {
943 flattened.push_back(innerArg->clone());
944 }
945 } else {
946 flattened.push_back(arg->clone());
947 }
948 currBit <<= 1;
949 }
John Stiles1b91c0e2021-02-11 11:43:09 -0500950 std::unique_ptr<Expression> replacement(new Constructor(c.fOffset, &c.type(),
951 std::move(flattened)));
952 // We're replacing an expression with a cloned version; we'll need a rescan.
953 // No fUsage change: `float2(float(x), y)` and `float2(x, y)` have equivalent
954 // reference counts.
955 try_replace_expression(&b, iter, &replacement);
John Stilesf5c1d042020-11-21 23:26:07 -0500956 optimizationContext->fUpdated = true;
John Stiles1b91c0e2021-02-11 11:43:09 -0500957 optimizationContext->fNeedsRescan = true;
John Stilesf5c1d042020-11-21 23:26:07 -0500958 break;
959 }
960 }
961 break;
962 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400963 case Expression::Kind::kSwizzle: {
John Stiles403a3632020-08-20 12:11:48 -0400964 Swizzle& s = expr->as<Swizzle>();
John Stiles108bbe22020-11-18 11:10:38 -0500965 // Detect identity swizzles like `foo.rgba`.
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400966 if ((int) s.components().size() == s.base()->type().columns()) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400967 bool identity = true;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400968 for (int i = 0; i < (int) s.components().size(); ++i) {
969 if (s.components()[i] != i) {
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400970 identity = false;
971 break;
972 }
973 }
974 if (identity) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400975 optimizationContext->fUpdated = true;
Brian Osman010ce6a2020-10-19 16:34:10 -0400976 // No fUsage change: foo.rgba and foo have equivalent reference counts
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400977 if (!try_replace_expression(&b, iter, &s.base())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -0400978 optimizationContext->fNeedsRescan = true;
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400979 return;
980 }
John Stiles70025e52020-09-28 16:08:58 -0400981 SkASSERT((*iter)->isExpression());
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400982 break;
983 }
984 }
John Stiles108bbe22020-11-18 11:10:38 -0500985 // Detect swizzles of swizzles, e.g. replace `foo.argb.r000` with `foo.a000`.
986 if (s.base()->is<Swizzle>()) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400987 Swizzle& base = s.base()->as<Swizzle>();
John Stiles750109b2020-10-30 13:45:46 -0400988 ComponentArray final;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400989 for (int c : s.components()) {
990 final.push_back(base.components()[c]);
Ethan Nicholas409f6f02019-09-17 12:34:39 -0400991 }
Ethan Nicholas6b4d5812020-10-12 16:11:51 -0400992 std::unique_ptr<Expression> replacement(new Swizzle(*fContext, base.base()->clone(),
John Stiles750109b2020-10-30 13:45:46 -0400993 final));
John Stilesd2f51b12021-01-07 18:12:31 -0500994 // We're replacing an expression with a cloned version; we'll need a rescan.
John Stiles108bbe22020-11-18 11:10:38 -0500995 // No fUsage change: `foo.gbr.gbr` and `foo.brg` have equivalent reference counts
John Stilesd2f51b12021-01-07 18:12:31 -0500996 try_replace_expression(&b, iter, &replacement);
997 optimizationContext->fUpdated = true;
998 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -0500999 break;
1000 }
1001 // Optimize swizzles of constructors.
1002 if (s.base()->is<Constructor>()) {
1003 Constructor& base = s.base()->as<Constructor>();
1004 std::unique_ptr<Expression> replacement;
1005 const Type& componentType = base.type().componentType();
1006 int swizzleSize = s.components().size();
1007
1008 // The IR generator has already converted any zero/one swizzle components into
1009 // constructors containing zero/one args. Confirm that this is true by checking that
1010 // our swizzle components are all `xyzw` (values 0 through 3).
1011 SkASSERT(std::all_of(s.components().begin(), s.components().end(),
1012 [](int8_t c) { return c >= 0 && c <= 3; }));
1013
John Stiles9aeed132020-11-24 17:36:06 -05001014 if (base.arguments().size() == 1 && base.arguments().front()->type().isScalar()) {
John Stiles108bbe22020-11-18 11:10:38 -05001015 // `half4(scalar).zyy` can be optimized to `half3(scalar)`. The swizzle
1016 // components don't actually matter since all fields are the same.
John Stilesf0cb7332021-01-08 18:39:00 -05001017 const Expression& argument = *base.arguments().front();
1018 const Type& constructorType = componentType.toCompound(*fContext, swizzleSize,
1019 /*rows=*/1);
1020 replacement = Constructor::SimplifyConversion(constructorType, argument);
1021 if (!replacement) {
1022 ExpressionArray newArgs;
1023 newArgs.push_back(argument.clone());
1024 replacement = std::make_unique<Constructor>(base.fOffset, &constructorType,
1025 std::move(newArgs));
1026 }
John Stiles108bbe22020-11-18 11:10:38 -05001027
John Stilesa60ac0c2020-12-22 08:59:51 -05001028 // We're replacing an expression with a cloned version; we'll need a rescan.
1029 // There's no fUsage change: `half4(foo).xy` and `half2(foo)` have equivalent
1030 // reference counts.
1031 try_replace_expression(&b, iter, &replacement);
John Stiles0777ac42020-11-19 11:06:47 -05001032 optimizationContext->fUpdated = true;
John Stilesa60ac0c2020-12-22 08:59:51 -05001033 optimizationContext->fNeedsRescan = true;
John Stiles108bbe22020-11-18 11:10:38 -05001034 break;
1035 }
1036
John Stiles0777ac42020-11-19 11:06:47 -05001037 // Swizzles can duplicate some elements and discard others, e.g.
1038 // `half4(1, 2, 3, 4).xxz` --> `half3(1, 1, 3)`. However, there are constraints:
1039 // - Expressions with side effects need to occur exactly once, even if they
1040 // would otherwise be swizzle-eliminated
1041 // - Non-trivial expressions should not be repeated, but elimination is OK.
1042 //
1043 // Look up the argument for the constructor at each index. This is typically simple
1044 // but for weird cases like `half4(bar.yz, half2(foo))`, it can be harder than it
1045 // seems. This example would result in:
1046 // argMap[0] = {.fArgIndex = 0, .fComponent = 0} (bar.yz .x)
1047 // argMap[1] = {.fArgIndex = 0, .fComponent = 1} (bar.yz .y)
1048 // argMap[2] = {.fArgIndex = 1, .fComponent = 0} (half2(foo) .x)
1049 // argMap[3] = {.fArgIndex = 1, .fComponent = 1} (half2(foo) .y)
1050 struct ConstructorArgMap {
1051 int8_t fArgIndex;
1052 int8_t fComponent;
1053 };
1054
1055 int numConstructorArgs = base.type().columns();
1056 ConstructorArgMap argMap[4] = {};
1057 int writeIdx = 0;
1058 for (int argIdx = 0; argIdx < (int) base.arguments().size(); ++argIdx) {
1059 const Expression& expr = *base.arguments()[argIdx];
1060 int argWidth = expr.type().columns();
1061 for (int componentIdx = 0; componentIdx < argWidth; ++componentIdx) {
1062 argMap[writeIdx].fArgIndex = argIdx;
1063 argMap[writeIdx].fComponent = componentIdx;
1064 ++writeIdx;
1065 }
1066 }
1067 SkASSERT(writeIdx == numConstructorArgs);
1068
1069 // Count up the number of times each constructor argument is used by the
1070 // swizzle.
1071 // `half4(bar.yz, half2(foo)).xwxy` -> { 3, 1 }
1072 // - bar.yz is referenced 3 times, by `.x_xy`
1073 // - half(foo) is referenced 1 time, by `._w__`
1074 int8_t exprUsed[4] = {};
1075 for (int c : s.components()) {
1076 exprUsed[argMap[c].fArgIndex]++;
1077 }
1078
1079 bool safeToOptimize = true;
1080 for (int index = 0; index < numConstructorArgs; ++index) {
1081 int8_t constructorArgIndex = argMap[index].fArgIndex;
1082 const Expression& baseArg = *base.arguments()[constructorArgIndex];
1083
1084 // Check that non-trivial expressions are not swizzled in more than once.
John Stilesc30fbca2020-11-19 16:25:49 -05001085 if (exprUsed[constructorArgIndex] > 1 &&
1086 !Analysis::IsTrivialExpression(baseArg)) {
John Stiles0777ac42020-11-19 11:06:47 -05001087 safeToOptimize = false;
1088 break;
1089 }
1090 // Check that side-effect-bearing expressions are swizzled in exactly once.
1091 if (exprUsed[constructorArgIndex] != 1 && baseArg.hasSideEffects()) {
1092 safeToOptimize = false;
1093 break;
1094 }
1095 }
1096
1097 if (safeToOptimize) {
John Stilesd9076cb2020-11-19 12:18:36 -05001098 struct ReorderedArgument {
1099 int8_t fArgIndex;
1100 ComponentArray fComponents;
1101 };
1102 SkSTArray<4, ReorderedArgument> reorderedArgs;
John Stiles0777ac42020-11-19 11:06:47 -05001103 for (int c : s.components()) {
1104 const ConstructorArgMap& argument = argMap[c];
1105 const Expression& baseArg = *base.arguments()[argument.fArgIndex];
1106
John Stiles9aeed132020-11-24 17:36:06 -05001107 if (baseArg.type().isScalar()) {
John Stilesd9076cb2020-11-19 12:18:36 -05001108 // This argument is a scalar; add it to the list as-is.
John Stiles0777ac42020-11-19 11:06:47 -05001109 SkASSERT(argument.fComponent == 0);
John Stilesd9076cb2020-11-19 12:18:36 -05001110 reorderedArgs.push_back({argument.fArgIndex,
1111 ComponentArray{}});
John Stiles0777ac42020-11-19 11:06:47 -05001112 } else {
John Stilesd9076cb2020-11-19 12:18:36 -05001113 // This argument is a component from a vector.
John Stiles0777ac42020-11-19 11:06:47 -05001114 SkASSERT(argument.fComponent < baseArg.type().columns());
John Stilesd9076cb2020-11-19 12:18:36 -05001115 if (reorderedArgs.empty() ||
1116 reorderedArgs.back().fArgIndex != argument.fArgIndex) {
1117 // This can't be combined with the previous argument. Add a new one.
1118 reorderedArgs.push_back({argument.fArgIndex,
1119 ComponentArray{argument.fComponent}});
1120 } else {
1121 // Since we know this argument uses components, it should already
1122 // have at least one component set.
1123 SkASSERT(!reorderedArgs.back().fComponents.empty());
1124 // Build up the current argument with one more component.
1125 reorderedArgs.back().fComponents.push_back(argument.fComponent);
1126 }
John Stiles0777ac42020-11-19 11:06:47 -05001127 }
1128 }
John Stilesd9076cb2020-11-19 12:18:36 -05001129
1130 // Convert our reordered argument list to an actual array of expressions, with
1131 // the new order and any new inner swizzles that need to be applied. Note that
1132 // we expect followup passes to clean up the inner swizzles.
1133 ExpressionArray newArgs;
1134 newArgs.reserve_back(swizzleSize);
1135 for (const ReorderedArgument& reorderedArg : reorderedArgs) {
1136 const Expression& baseArg = *base.arguments()[reorderedArg.fArgIndex];
1137 if (reorderedArg.fComponents.empty()) {
1138 newArgs.push_back(baseArg.clone());
1139 } else {
1140 newArgs.push_back(std::make_unique<Swizzle>(*fContext, baseArg.clone(),
1141 reorderedArg.fComponents));
1142 }
1143 }
1144
1145 // Create a new constructor.
John Stiles0777ac42020-11-19 11:06:47 -05001146 replacement = std::make_unique<Constructor>(
1147 base.fOffset,
1148 &componentType.toCompound(*fContext, swizzleSize, /*rows=*/1),
1149 std::move(newArgs));
1150
John Stilesa60ac0c2020-12-22 08:59:51 -05001151 // Remove references within 'expr', add references within 'replacement.'
John Stiles0777ac42020-11-19 11:06:47 -05001152 optimizationContext->fUsage->replace(expr, replacement.get());
John Stilesa60ac0c2020-12-22 08:59:51 -05001153
1154 // We're replacing an expression with a cloned version; we'll need a rescan.
1155 try_replace_expression(&b, iter, &replacement);
1156 optimizationContext->fUpdated = true;
1157 optimizationContext->fNeedsRescan = true;
John Stiles0777ac42020-11-19 11:06:47 -05001158 }
John Stiles108bbe22020-11-18 11:10:38 -05001159 break;
Ethan Nicholas409f6f02019-09-17 12:34:39 -04001160 }
John Stiles30212b72020-06-11 17:55:07 -04001161 break;
Ethan Nicholascb670962017-04-20 19:31:52 -04001162 }
1163 default:
1164 break;
1165 }
1166}
1167
John Stiles92219b42020-06-15 12:32:24 -04001168// Returns true if this statement could potentially execute a break at the current level. We ignore
1169// nested loops and switches, since any breaks inside of them will merely break the loop / switch.
John Stilesb92641c2020-08-31 18:09:01 -04001170static bool contains_conditional_break(Statement& stmt) {
1171 class ContainsConditionalBreak : public ProgramVisitor {
1172 public:
1173 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001174 switch (stmt.kind()) {
1175 case Statement::Kind::kBlock:
John Stilesbb1505f2021-02-12 09:17:53 -05001176 return INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001177
Ethan Nicholase6592142020-09-08 10:22:09 -04001178 case Statement::Kind::kBreak:
John Stilesb92641c2020-08-31 18:09:01 -04001179 return fInConditional > 0;
1180
Ethan Nicholase6592142020-09-08 10:22:09 -04001181 case Statement::Kind::kIf: {
John Stilesb92641c2020-08-31 18:09:01 -04001182 ++fInConditional;
John Stilesbb1505f2021-02-12 09:17:53 -05001183 bool result = INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001184 --fInConditional;
1185 return result;
1186 }
1187
1188 default:
1189 return false;
1190 }
1191 }
1192
1193 int fInConditional = 0;
1194 using INHERITED = ProgramVisitor;
1195 };
1196
1197 return ContainsConditionalBreak{}.visitStatement(stmt);
John Stiles92219b42020-06-15 12:32:24 -04001198}
1199
Ethan Nicholas5005a222018-08-24 13:06:27 -04001200// returns true if this statement definitely executes a break at the current level (we ignore
1201// nested loops and switches, since any breaks inside of them will merely break the loop / switch)
John Stilesb92641c2020-08-31 18:09:01 -04001202static bool contains_unconditional_break(Statement& stmt) {
1203 class ContainsUnconditionalBreak : public ProgramVisitor {
1204 public:
1205 bool visitStatement(const Statement& stmt) override {
Ethan Nicholase6592142020-09-08 10:22:09 -04001206 switch (stmt.kind()) {
1207 case Statement::Kind::kBlock:
John Stilesbb1505f2021-02-12 09:17:53 -05001208 return INHERITED::visitStatement(stmt);
John Stilesb92641c2020-08-31 18:09:01 -04001209
Ethan Nicholase6592142020-09-08 10:22:09 -04001210 case Statement::Kind::kBreak:
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001211 return true;
John Stilesb92641c2020-08-31 18:09:01 -04001212
1213 default:
1214 return false;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001215 }
John Stilesb92641c2020-08-31 18:09:01 -04001216 }
John Stiles92219b42020-06-15 12:32:24 -04001217
John Stilesb92641c2020-08-31 18:09:01 -04001218 using INHERITED = ProgramVisitor;
1219 };
John Stiles92219b42020-06-15 12:32:24 -04001220
John Stilesb92641c2020-08-31 18:09:01 -04001221 return ContainsUnconditionalBreak{}.visitStatement(stmt);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001222}
1223
John Stiles8f2a0cf2020-10-13 12:48:21 -04001224static void move_all_but_break(std::unique_ptr<Statement>& stmt, StatementArray* target) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001225 switch (stmt->kind()) {
1226 case Statement::Kind::kBlock: {
John Stiles92219b42020-06-15 12:32:24 -04001227 // Recurse into the block.
1228 Block& block = static_cast<Block&>(*stmt);
1229
John Stiles8f2a0cf2020-10-13 12:48:21 -04001230 StatementArray blockStmts;
John Stilesf4bda742020-10-14 16:57:41 -04001231 blockStmts.reserve_back(block.children().size());
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001232 for (std::unique_ptr<Statement>& stmt : block.children()) {
1233 move_all_but_break(stmt, &blockStmts);
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001234 }
John Stiles92219b42020-06-15 12:32:24 -04001235
1236 target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts),
Ethan Nicholas7bd60432020-09-25 14:31:59 -04001237 block.symbolTable(), block.isScope()));
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001238 break;
John Stiles92219b42020-06-15 12:32:24 -04001239 }
1240
Ethan Nicholase6592142020-09-08 10:22:09 -04001241 case Statement::Kind::kBreak:
John Stiles92219b42020-06-15 12:32:24 -04001242 // Do not append a break to the target.
1243 break;
1244
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001245 default:
John Stiles92219b42020-06-15 12:32:24 -04001246 // Append normal statements to the target.
1247 target->push_back(std::move(stmt));
1248 break;
Ethan Nicholas739e1ca2020-06-11 12:16:14 -04001249 }
1250}
1251
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001252// Returns a block containing all of the statements that will be run if the given case matches
1253// (which, owing to the statements being owned by unique_ptrs, means the switch itself will be
1254// broken by this call and must then be discarded).
1255// Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as
1256// when break statements appear inside conditionals.
John Stiles92219b42020-06-15 12:32:24 -04001257static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement,
1258 SwitchCase* caseToCapture) {
1259 // We have to be careful to not move any of the pointers until after we're sure we're going to
1260 // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan
1261 // of action. First, find the switch-case we are interested in.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001262 auto iter = switchStatement->cases().begin();
1263 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001264 if (iter->get() == caseToCapture) {
John Stiles92219b42020-06-15 12:32:24 -04001265 break;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001266 }
John Stiles92219b42020-06-15 12:32:24 -04001267 }
1268
1269 // Next, walk forward through the rest of the switch. If we find a conditional break, we're
1270 // stuck and can't simplify at all. If we find an unconditional break, we have a range of
1271 // statements that we can use for simplification.
1272 auto startIter = iter;
1273 Statement* unconditionalBreakStmt = nullptr;
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001274 for (; iter != switchStatement->cases().end(); ++iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001275 for (std::unique_ptr<Statement>& stmt : (*iter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001276 if (contains_conditional_break(*stmt)) {
1277 // We can't reduce switch-cases to a block when they have conditional breaks.
1278 return nullptr;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001279 }
John Stiles92219b42020-06-15 12:32:24 -04001280
1281 if (contains_unconditional_break(*stmt)) {
1282 // We found an unconditional break. We can use this block, but we need to strip
1283 // out the break statement.
1284 unconditionalBreakStmt = stmt.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001285 break;
1286 }
1287 }
John Stiles92219b42020-06-15 12:32:24 -04001288
1289 if (unconditionalBreakStmt != nullptr) {
1290 break;
1291 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001292 }
John Stiles92219b42020-06-15 12:32:24 -04001293
1294 // We fell off the bottom of the switch or encountered a break. We know the range of statements
1295 // that we need to move over, and we know it's safe to do so.
John Stiles8f2a0cf2020-10-13 12:48:21 -04001296 StatementArray caseStmts;
John Stiles92219b42020-06-15 12:32:24 -04001297
1298 // We can move over most of the statements as-is.
1299 while (startIter != iter) {
John Stiles2d4f9592020-10-30 10:29:12 -04001300 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001301 caseStmts.push_back(std::move(stmt));
1302 }
1303 ++startIter;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001304 }
John Stiles92219b42020-06-15 12:32:24 -04001305
1306 // If we found an unconditional break at the end, we need to move what we can while avoiding
1307 // that break.
1308 if (unconditionalBreakStmt != nullptr) {
John Stiles2d4f9592020-10-30 10:29:12 -04001309 for (std::unique_ptr<Statement>& stmt : (*startIter)->statements()) {
John Stiles92219b42020-06-15 12:32:24 -04001310 if (stmt.get() == unconditionalBreakStmt) {
1311 move_all_but_break(stmt, &caseStmts);
1312 unconditionalBreakStmt = nullptr;
1313 break;
1314 }
1315
1316 caseStmts.push_back(std::move(stmt));
1317 }
1318 }
1319
1320 SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break.
1321
1322 // Return our newly-synthesized block.
Ethan Nicholas01b05e52020-10-22 15:53:41 -04001323 return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->symbols());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001324}
1325
Ethan Nicholascb670962017-04-20 19:31:52 -04001326void Compiler::simplifyStatement(DefinitionMap& definitions,
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001327 BasicBlock& b,
1328 std::vector<BasicBlock::Node>::iterator* iter,
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001329 OptimizationContext* optimizationContext) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001330 ProgramUsage* usage = optimizationContext->fUsage;
Ethan Nicholascb670962017-04-20 19:31:52 -04001331 Statement* stmt = (*iter)->statement()->get();
Ethan Nicholase6592142020-09-08 10:22:09 -04001332 switch (stmt->kind()) {
1333 case Statement::Kind::kVarDeclaration: {
John Stilesa5a97b42020-08-18 11:19:07 -04001334 const auto& varDecl = stmt->as<VarDeclaration>();
Brian Osman010ce6a2020-10-19 16:34:10 -04001335 if (usage->isDead(varDecl.var()) &&
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001336 (!varDecl.value() ||
1337 !varDecl.value()->hasSideEffects())) {
1338 if (varDecl.value()) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001339 SkASSERT((*iter)->statement()->get() == stmt);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04001340 if (!b.tryRemoveExpressionBefore(iter, varDecl.value().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001341 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001342 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001343 }
Ethan Nicholas5b9b0db2021-01-21 13:12:01 -05001344 // There can still be (soon to be removed) references to the variable at this point.
1345 // Allowing the VarDeclaration to be destroyed here will break those variable's
1346 // initialValue()s, so we hang on to them until optimization is finished.
1347 std::unique_ptr<Statement> old = (*iter)->setStatement(std::make_unique<Nop>(),
1348 usage);
1349 optimizationContext->fOwnedStatements.push_back(std::move(old));
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001350 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001351 }
1352 break;
1353 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001354 case Statement::Kind::kIf: {
John Stilesa5a97b42020-08-18 11:19:07 -04001355 IfStatement& i = stmt->as<IfStatement>();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001356 if (i.test()->kind() == Expression::Kind::kBoolLiteral) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001357 // constant if, collapse down to a single branch
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001358 if (i.test()->as<BoolLiteral>().value()) {
1359 SkASSERT(i.ifTrue());
Brian Osman010ce6a2020-10-19 16:34:10 -04001360 (*iter)->setStatement(std::move(i.ifTrue()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001361 } else {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001362 if (i.ifFalse()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001363 (*iter)->setStatement(std::move(i.ifFalse()), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001364 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001365 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001366 }
1367 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001368 optimizationContext->fUpdated = true;
1369 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001370 break;
1371 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001372 if (i.ifFalse() && i.ifFalse()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001373 // else block doesn't do anything, remove it
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001374 i.ifFalse().reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001375 optimizationContext->fUpdated = true;
1376 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001377 }
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001378 if (!i.ifFalse() && i.ifTrue()->isEmpty()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001379 // if block doesn't do anything, no else block
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04001380 if (i.test()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001381 // test has side effects, keep it
Brian Osman010ce6a2020-10-19 16:34:10 -04001382 (*iter)->setStatement(
1383 std::make_unique<ExpressionStatement>(std::move(i.test())), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001384 } else {
1385 // no if, no else, no test side effects, kill the whole if
1386 // statement
Brian Osman010ce6a2020-10-19 16:34:10 -04001387 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascb670962017-04-20 19:31:52 -04001388 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001389 optimizationContext->fUpdated = true;
1390 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001391 }
1392 break;
1393 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001394 case Statement::Kind::kSwitch: {
John Stilesa5a97b42020-08-18 11:19:07 -04001395 SwitchStatement& s = stmt->as<SwitchStatement>();
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001396 int64_t switchValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001397 if (ConstantFolder::GetConstantInt(*s.value(), &switchValue)) {
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001398 // switch is constant, replace it with the case that matches
1399 bool found = false;
1400 SwitchCase* defaultCase = nullptr;
John Stiles2d4f9592020-10-30 10:29:12 -04001401 for (const std::unique_ptr<SwitchCase>& c : s.cases()) {
1402 if (!c->value()) {
1403 defaultCase = c.get();
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001404 continue;
1405 }
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001406 int64_t caseValue;
Ethan Nicholasc0f98152021-02-05 16:21:10 -05001407 SkAssertResult(ConstantFolder::GetConstantInt(*c->value(), &caseValue));
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001408 if (caseValue == switchValue) {
John Stiles2d4f9592020-10-30 10:29:12 -04001409 std::unique_ptr<Statement> newBlock = block_for_case(&s, c.get());
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001410 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001411 (*iter)->setStatement(std::move(newBlock), usage);
John Stiles9d944232020-08-19 09:56:49 -04001412 found = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001413 break;
1414 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001415 if (s.isStatic() &&
1416 !fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1417 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1418 if (didInsert) {
1419 this->error(s.fOffset, "static switch contains non-static "
1420 "conditional break");
1421 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001422 }
1423 return; // can't simplify
1424 }
1425 }
1426 }
1427 if (!found) {
1428 // no matching case. use default if it exists, or kill the whole thing
1429 if (defaultCase) {
1430 std::unique_ptr<Statement> newBlock = block_for_case(&s, defaultCase);
1431 if (newBlock) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001432 (*iter)->setStatement(std::move(newBlock), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001433 } else {
John Stilesd6a5f4492021-02-11 15:46:11 -05001434 if (s.isStatic() &&
1435 !fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1436 auto [iter, didInsert] = optimizationContext->fSilences.insert(&s);
1437 if (didInsert) {
1438 this->error(s.fOffset, "static switch contains non-static "
1439 "conditional break");
1440 }
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001441 }
1442 return; // can't simplify
1443 }
1444 } else {
Brian Osman010ce6a2020-10-19 16:34:10 -04001445 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001446 }
1447 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001448 optimizationContext->fUpdated = true;
1449 optimizationContext->fNeedsRescan = true;
Ethan Nicholas5ac13c22017-05-10 15:06:17 -04001450 }
1451 break;
1452 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001453 case Statement::Kind::kExpression: {
John Stilesa5a97b42020-08-18 11:19:07 -04001454 ExpressionStatement& e = stmt->as<ExpressionStatement>();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001455 SkASSERT((*iter)->statement()->get() == &e);
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001456 if (!e.expression()->hasSideEffects()) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001457 // Expression statement with no side effects, kill it
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04001458 if (!b.tryRemoveExpressionBefore(iter, e.expression().get())) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001459 optimizationContext->fNeedsRescan = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001460 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001461 SkASSERT((*iter)->statement()->get() == stmt);
Brian Osman010ce6a2020-10-19 16:34:10 -04001462 (*iter)->setStatement(std::make_unique<Nop>(), usage);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001463 optimizationContext->fUpdated = true;
Ethan Nicholascb670962017-04-20 19:31:52 -04001464 }
1465 break;
1466 }
1467 default:
1468 break;
1469 }
1470}
1471
Brian Osman010ce6a2020-10-19 16:34:10 -04001472bool Compiler::scanCFG(FunctionDefinition& f, ProgramUsage* usage) {
John Stiles0cc193a2020-09-09 09:39:34 -04001473 bool madeChanges = false;
1474
Ethan Nicholascb670962017-04-20 19:31:52 -04001475 CFG cfg = CFGGenerator().getCFG(f);
1476 this->computeDataFlow(&cfg);
ethannicholas22f939e2016-10-13 13:25:34 -07001477
1478 // check for unreachable code
1479 for (size_t i = 0; i < cfg.fBlocks.size(); i++) {
John Stiles0cc193a2020-09-09 09:39:34 -04001480 const BasicBlock& block = cfg.fBlocks[i];
John Stiles40525102020-12-16 18:10:44 -05001481 if (!block.fIsReachable && !block.fAllowUnreachable && block.fNodes.size()) {
John Stiles0cc193a2020-09-09 09:39:34 -04001482 const BasicBlock::Node& node = block.fNodes[0];
John Stilesc1129322021-02-03 10:13:42 -05001483 int offset = node.isStatement() ? (*node.statement())->fOffset
1484 : (*node.expression())->fOffset;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001485 this->error(offset, String("unreachable"));
ethannicholas22f939e2016-10-13 13:25:34 -07001486 }
1487 }
1488 if (fErrorCount) {
John Stiles0cc193a2020-09-09 09:39:34 -04001489 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001490 }
1491
Ethan Nicholascb670962017-04-20 19:31:52 -04001492 // check for dead code & undefined variables, perform constant propagation
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001493 OptimizationContext optimizationContext;
Brian Osman010ce6a2020-10-19 16:34:10 -04001494 optimizationContext.fUsage = usage;
John Stiles7d3f0892020-11-03 11:35:01 -05001495 SkBitSet eliminatedBlockIds(cfg.fBlocks.size());
Ethan Nicholascb670962017-04-20 19:31:52 -04001496 do {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001497 if (optimizationContext.fNeedsRescan) {
Ethan Nicholascb670962017-04-20 19:31:52 -04001498 cfg = CFGGenerator().getCFG(f);
1499 this->computeDataFlow(&cfg);
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001500 optimizationContext.fNeedsRescan = false;
Ethan Nicholas113628d2017-02-02 16:11:39 -05001501 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001502
John Stiles7d3f0892020-11-03 11:35:01 -05001503 eliminatedBlockIds.reset();
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001504 optimizationContext.fUpdated = false;
John Stiles7d3f0892020-11-03 11:35:01 -05001505
1506 for (BlockId blockId = 0; blockId < cfg.fBlocks.size(); ++blockId) {
1507 if (eliminatedBlockIds.test(blockId)) {
1508 // We reached a block ID that might have been eliminated. Be cautious and rescan.
1509 optimizationContext.fUpdated = true;
1510 optimizationContext.fNeedsRescan = true;
1511 break;
1512 }
1513
1514 BasicBlock& b = cfg.fBlocks[blockId];
1515 if (blockId > 0 && !b.fIsReachable) {
Ethan Nicholas1de14812020-06-19 15:32:49 -04001516 // Block was reachable before optimization, but has since become unreachable. In
1517 // addition to being dead code, it's broken - since control flow can't reach it, no
1518 // prior variable definitions can reach it, and therefore variables might look to
Brian Osmanc0213602020-10-06 14:43:32 -04001519 // have not been properly assigned. Kill it by replacing all statements with Nops.
Ethan Nicholas1de14812020-06-19 15:32:49 -04001520 for (BasicBlock::Node& node : b.fNodes) {
John Stiles70025e52020-09-28 16:08:58 -04001521 if (node.isStatement() && !(*node.statement())->is<Nop>()) {
John Stiles7d3f0892020-11-03 11:35:01 -05001522 // Eliminating a node runs the risk of eliminating that node's exits as
1523 // well. Keep track of this and do a rescan if we are about to access one
1524 // of these.
1525 for (BlockId id : b.fExits) {
1526 eliminatedBlockIds.set(id);
1527 }
Brian Osman010ce6a2020-10-19 16:34:10 -04001528 node.setStatement(std::make_unique<Nop>(), usage);
John Stiles0cc193a2020-09-09 09:39:34 -04001529 madeChanges = true;
Ethan Nicholas1de14812020-06-19 15:32:49 -04001530 }
1531 }
1532 continue;
1533 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001534 DefinitionMap definitions = b.fBefore;
1535
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001536 for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() &&
1537 !optimizationContext.fNeedsRescan; ++iter) {
John Stiles70025e52020-09-28 16:08:58 -04001538 if (iter->isExpression()) {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001539 this->simplifyExpression(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001540 } else {
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001541 this->simplifyStatement(definitions, b, &iter, &optimizationContext);
Ethan Nicholascb670962017-04-20 19:31:52 -04001542 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001543 if (optimizationContext.fNeedsRescan) {
Ethan Nicholas4b330df2017-05-17 10:52:55 -04001544 break;
1545 }
John Stilese8a24922021-02-08 17:54:08 -05001546 definitions.addDefinitions(*fContext, *iter);
Ethan Nicholascb670962017-04-20 19:31:52 -04001547 }
Brian Osman01a3eb42020-09-14 11:32:49 -04001548
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001549 if (optimizationContext.fNeedsRescan) {
Brian Osman01a3eb42020-09-14 11:32:49 -04001550 break;
1551 }
Ethan Nicholascb670962017-04-20 19:31:52 -04001552 }
Ethan Nicholascdeae8c2020-10-22 14:39:46 -04001553 madeChanges |= optimizationContext.fUpdated;
1554 } while (optimizationContext.fUpdated);
1555 SkASSERT(!optimizationContext.fNeedsRescan);
ethannicholas22f939e2016-10-13 13:25:34 -07001556
1557 // check for missing return
John Stiles54e7c052021-01-11 14:22:36 -05001558 if (f.declaration().returnType() != *fContext->fTypes.fVoid) {
John Stiles61e75e32020-10-01 15:42:37 -04001559 if (cfg.fBlocks[cfg.fExit].fIsReachable) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04001560 this->error(f.fOffset, String("function '" + String(f.declaration().name()) +
Ethan Nicholasdb80f692019-11-22 14:06:12 -05001561 "' can exit without returning a value"));
ethannicholas22f939e2016-10-13 13:25:34 -07001562 }
1563 }
John Stiles0cc193a2020-09-09 09:39:34 -04001564
1565 return madeChanges;
ethannicholas22f939e2016-10-13 13:25:34 -07001566}
1567
Brian Osman32d53552020-09-23 13:55:20 -04001568std::unique_ptr<Program> Compiler::convertProgram(
John Stilesdbd4e6f2021-02-16 13:29:15 -05001569 ProgramKind kind,
Brian Osman32d53552020-09-23 13:55:20 -04001570 String text,
1571 const Program::Settings& settings,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001572 const std::vector<std::unique_ptr<ExternalFunction>>* externalFunctions) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001573 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::convertProgram");
1574
John Stilesdbd4e6f2021-02-16 13:29:15 -05001575 SkASSERT(!externalFunctions || (kind == ProgramKind::kGeneric));
Ethan Nicholas91164d12019-05-15 15:29:54 -04001576
Brian Osman0006ad02020-11-18 15:38:39 -05001577 // Loading and optimizing our base module might reset the inliner, so do that first,
1578 // *then* configure the inliner with the settings for this program.
1579 const ParsedModule& baseModule = this->moduleForProgramKind(kind);
1580
ethannicholasb3058bd2016-07-01 08:22:01 -07001581 fErrorText = "";
1582 fErrorCount = 0;
Brian Osman0006ad02020-11-18 15:38:39 -05001583 fInliner.reset(fIRGenerator->fModifiers.get(), &settings);
Brian Osman88cda172020-10-09 12:05:16 -04001584
1585 // Not using AutoSource, because caller is likely to call errorText() if we fail to compile
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001586 std::unique_ptr<String> textPtr(new String(std::move(text)));
1587 fSource = textPtr.get();
Brian Osman88cda172020-10-09 12:05:16 -04001588
John Stiles5c7bb322020-10-22 11:09:15 -04001589 // Enable node pooling while converting and optimizing the program for a performance boost.
1590 // The Program will take ownership of the pool.
Brian Osman28f702c2021-02-02 11:52:07 -05001591 std::unique_ptr<Pool> pool;
1592 if (fCaps->useNodePools()) {
1593 pool = Pool::Create();
1594 pool->attachToThread();
1595 }
Brian Osman0006ad02020-11-18 15:38:39 -05001596 IRGenerator::IRBundle ir =
1597 fIRGenerator->convertProgram(kind, &settings, baseModule, /*isBuiltinCode=*/false,
Brian Osmanbe0b3b72021-01-06 14:27:35 -05001598 textPtr->c_str(), textPtr->size(), externalFunctions);
John Stiles5c7bb322020-10-22 11:09:15 -04001599 auto program = std::make_unique<Program>(kind,
1600 std::move(textPtr),
1601 settings,
Brian Osmand7e76592020-11-02 12:26:22 -05001602 fCaps,
John Stiles5c7bb322020-10-22 11:09:15 -04001603 fContext,
1604 std::move(ir.fElements),
Brian Osman133724c2020-10-28 14:14:39 -04001605 std::move(ir.fSharedElements),
John Stiles5c7bb322020-10-22 11:09:15 -04001606 std::move(ir.fModifiers),
1607 std::move(ir.fSymbolTable),
1608 std::move(pool),
1609 ir.fInputs);
1610 bool success = false;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001611 if (fErrorCount) {
John Stiles5c7bb322020-10-22 11:09:15 -04001612 // Do not return programs that failed to compile.
Brian Osman4f065e22021-02-13 01:06:03 +00001613 } else if (settings.fOptimize && !this->optimize(*program)) {
John Stiles5c7bb322020-10-22 11:09:15 -04001614 // Do not return programs that failed to optimize.
1615 } else {
1616 // We have a successful program!
1617 success = true;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001618 }
John Stiles5c7bb322020-10-22 11:09:15 -04001619
Brian Osman28f702c2021-02-02 11:52:07 -05001620 if (program->fPool) {
1621 program->fPool->detachFromThread();
1622 }
John Stiles5c7bb322020-10-22 11:09:15 -04001623 return success ? std::move(program) : nullptr;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001624}
1625
John Stilesbb1505f2021-02-12 09:17:53 -05001626void Compiler::verifyStaticTests(const Program& program) {
1627 class StaticTestVerifier : public ProgramVisitor {
1628 public:
1629 StaticTestVerifier(ErrorReporter* r) : fReporter(r) {}
1630
1631 using ProgramVisitor::visitProgramElement;
1632
1633 bool visitStatement(const Statement& stmt) override {
1634 switch (stmt.kind()) {
1635 case Statement::Kind::kIf:
1636 if (stmt.as<IfStatement>().isStatic()) {
1637 fReporter->error(stmt.fOffset, "static if has non-static test");
1638 }
1639 break;
1640
1641 case Statement::Kind::kSwitch:
1642 if (stmt.as<SwitchStatement>().isStatic()) {
1643 fReporter->error(stmt.fOffset, "static switch has non-static test");
1644 }
1645 break;
1646
1647 default:
1648 break;
1649 }
1650 return INHERITED::visitStatement(stmt);
1651 }
1652
John Stiles59e34562021-02-12 16:56:39 -05001653 bool visitExpression(const Expression&) override {
1654 // We aren't looking for anything inside an Expression, so skip them entirely.
1655 return false;
1656 }
1657
John Stilesbb1505f2021-02-12 09:17:53 -05001658 private:
1659 using INHERITED = ProgramVisitor;
1660 ErrorReporter* fReporter;
1661 };
1662
1663 // If invalid static tests are permitted, we don't need to check anything.
1664 if (fIRGenerator->fSettings->fPermitInvalidStaticTests) {
1665 return;
1666 }
1667
1668 // Check all of the program's owned elements. (Built-in elements are assumed to be valid.)
1669 StaticTestVerifier visitor{this};
1670 for (const std::unique_ptr<ProgramElement>& element : program.ownedElements()) {
1671 if (element->is<FunctionDefinition>()) {
1672 visitor.visitProgramElement(*element);
1673 }
1674 }
1675}
1676
Brian Osman0006ad02020-11-18 15:38:39 -05001677bool Compiler::optimize(LoadedModule& module) {
1678 SkASSERT(!fErrorCount);
1679 Program::Settings settings;
1680 fIRGenerator->fKind = module.fKind;
1681 fIRGenerator->fSettings = &settings;
1682 std::unique_ptr<ProgramUsage> usage = Analysis::GetUsage(module);
1683
1684 fInliner.reset(fModifiers.back().get(), &settings);
1685
1686 while (fErrorCount == 0) {
1687 bool madeChanges = false;
1688
1689 // Scan and optimize based on the control-flow graph for each function.
1690 for (const auto& element : module.fElements) {
1691 if (element->is<FunctionDefinition>()) {
1692 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage.get());
1693 }
1694 }
1695
1696 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001697 madeChanges |= fInliner.analyze(module.fElements, module.fSymbols, usage.get());
Brian Osman0006ad02020-11-18 15:38:39 -05001698
1699 if (!madeChanges) {
1700 break;
1701 }
1702 }
1703 return fErrorCount == 0;
1704}
1705
Ethan Nicholas00543112018-07-31 09:44:36 -04001706bool Compiler::optimize(Program& program) {
1707 SkASSERT(!fErrorCount);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001708 fIRGenerator->fKind = program.fKind;
1709 fIRGenerator->fSettings = &program.fSettings;
Brian Osman010ce6a2020-10-19 16:34:10 -04001710 ProgramUsage* usage = program.fUsage.get();
John Stiles7954d6c2020-09-01 10:53:02 -04001711
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001712 while (fErrorCount == 0) {
1713 bool madeChanges = false;
John Stiles7954d6c2020-09-01 10:53:02 -04001714
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001715 // Scan and optimize based on the control-flow graph for each function.
Brian Osman133724c2020-10-28 14:14:39 -04001716 for (const auto& element : program.ownedElements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04001717 if (element->is<FunctionDefinition>()) {
Brian Osman010ce6a2020-10-19 16:34:10 -04001718 madeChanges |= this->scanCFG(element->as<FunctionDefinition>(), usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001719 }
1720 }
1721
1722 // Perform inline-candidate analysis and inline any functions deemed suitable.
John Stiles78047582020-12-16 16:17:41 -05001723 madeChanges |= fInliner.analyze(program.ownedElements(), program.fSymbols, usage);
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001724
1725 // Remove dead functions. We wait until after analysis so that we still report errors,
1726 // even in unused code.
1727 if (program.fSettings.fRemoveDeadFunctions) {
Brian Osman133724c2020-10-28 14:14:39 -04001728 auto isDeadFunction = [&](const ProgramElement* element) {
1729 if (!element->is<FunctionDefinition>()) {
1730 return false;
1731 }
1732 const FunctionDefinition& fn = element->as<FunctionDefinition>();
1733 if (fn.declaration().name() != "main" && usage->get(fn.declaration()) == 0) {
1734 usage->remove(*element);
1735 madeChanges = true;
1736 return true;
1737 }
1738 return false;
1739 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001740 program.fElements.erase(
Brian Osman133724c2020-10-28 14:14:39 -04001741 std::remove_if(program.fElements.begin(), program.fElements.end(),
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001742 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001743 return isDeadFunction(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001744 }),
1745 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001746 program.fSharedElements.erase(
1747 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1748 isDeadFunction),
1749 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001750 }
1751
John Stilesdbd4e6f2021-02-16 13:29:15 -05001752 if (program.fKind != ProgramKind::kFragmentProcessor) {
Brian Osmanc0213602020-10-06 14:43:32 -04001753 // Remove declarations of dead global variables
Brian Osman133724c2020-10-28 14:14:39 -04001754 auto isDeadVariable = [&](const ProgramElement* element) {
1755 if (!element->is<GlobalVarDeclaration>()) {
1756 return false;
1757 }
1758 const GlobalVarDeclaration& global = element->as<GlobalVarDeclaration>();
1759 const VarDeclaration& varDecl = global.declaration()->as<VarDeclaration>();
1760 if (usage->isDead(varDecl.var())) {
1761 madeChanges = true;
1762 return true;
1763 }
1764 return false;
1765 };
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001766 program.fElements.erase(
1767 std::remove_if(program.fElements.begin(), program.fElements.end(),
1768 [&](const std::unique_ptr<ProgramElement>& element) {
Brian Osman133724c2020-10-28 14:14:39 -04001769 return isDeadVariable(element.get());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001770 }),
1771 program.fElements.end());
Brian Osman133724c2020-10-28 14:14:39 -04001772 program.fSharedElements.erase(
1773 std::remove_if(program.fSharedElements.begin(), program.fSharedElements.end(),
1774 isDeadVariable),
1775 program.fSharedElements.end());
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001776 }
John Stiles73a6bff2020-09-09 13:40:37 -04001777
Ethan Nicholas34b19c52020-09-14 11:33:47 -04001778 if (!madeChanges) {
1779 break;
Ethan Nicholas0dc80872019-02-08 15:46:24 -05001780 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001781 }
John Stilesbb1505f2021-02-12 09:17:53 -05001782
1783 if (fErrorCount == 0) {
1784 this->verifyStaticTests(program);
1785 }
1786
Ethan Nicholas00543112018-07-31 09:44:36 -04001787 return fErrorCount == 0;
1788}
1789
Brian Osmanfb32ddf2019-06-18 10:14:20 -04001790#if defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
1791
Ethan Nicholas00543112018-07-31 09:44:36 -04001792bool Compiler::toSPIRV(Program& program, OutputStream& out) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001793#ifdef SK_ENABLE_SPIRV_VALIDATION
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001794 StringStream buffer;
Brian Osman88cda172020-10-09 12:05:16 -04001795 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001796 SPIRVCodeGenerator cg(fContext.get(), &program, this, &buffer);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001797 bool result = cg.generateCode();
Ethan Nicholasba9a04f2020-11-06 09:28:04 -05001798 if (result && program.fSettings.fValidateSPIRV) {
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001799 spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_0);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001800 const String& data = buffer.str();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001801 SkASSERT(0 == data.size() % 4);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001802 String errors;
1803 auto dumpmsg = [&errors](spv_message_level_t, const char*, const spv_position_t&,
1804 const char* m) {
1805 errors.appendf("SPIR-V validation error: %s\n", m);
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001806 };
1807 tools.SetMessageConsumer(dumpmsg);
Brian Osman8d09d4a2020-11-24 15:51:06 -05001808
1809 // Verify that the SPIR-V we produced is valid. At runtime, we will abort() with a message
1810 // explaining the error. In standalone mode (skslc), we will send the message, plus the
1811 // entire disassembled SPIR-V (for easier context & debugging) as *our* error message.
1812 result = tools.Validate((const uint32_t*) data.c_str(), data.size() / 4);
1813
1814 if (!result) {
1815#if defined(SKSL_STANDALONE)
1816 // Convert the string-stream to a SPIR-V disassembly.
1817 std::string disassembly;
1818 if (tools.Disassemble((const uint32_t*)data.data(), data.size() / 4, &disassembly)) {
1819 errors.append(disassembly);
1820 }
1821 this->error(-1, errors);
1822#else
1823 SkDEBUGFAILF("%s", errors.c_str());
1824#endif
1825 }
Ethan Nicholas762466e2017-06-29 10:03:38 -04001826 out.write(data.c_str(), data.size());
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001827 }
1828#else
Brian Osman88cda172020-10-09 12:05:16 -04001829 AutoSource as(this, program.fSource.get());
Brian Osman8b43dad2020-10-09 13:31:42 -04001830 SPIRVCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001831 bool result = cg.generateCode();
Ethan Nicholasa6ae1f72017-03-16 09:56:54 -04001832#endif
Ethan Nicholasce33f102016-12-09 17:22:59 -05001833 return result;
1834}
1835
Ethan Nicholas00543112018-07-31 09:44:36 -04001836bool Compiler::toSPIRV(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001837 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001838 bool result = this->toSPIRV(program, buffer);
1839 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001840 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001841 }
1842 return result;
1843}
1844
Ethan Nicholas00543112018-07-31 09:44:36 -04001845bool Compiler::toGLSL(Program& program, OutputStream& out) {
Leon Scrogginsb66214e2021-02-11 17:14:18 -05001846 ATRACE_ANDROID_FRAMEWORK("SkSL::Compiler::toGLSL");
Brian Osman88cda172020-10-09 12:05:16 -04001847 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001848 GLSLCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001849 bool result = cg.generateCode();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001850 return result;
1851}
1852
Ethan Nicholas00543112018-07-31 09:44:36 -04001853bool Compiler::toGLSL(Program& program, String* out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001854 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001855 bool result = this->toGLSL(program, buffer);
1856 if (result) {
Ethan Nicholas762466e2017-06-29 10:03:38 -04001857 *out = buffer.str();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001858 }
1859 return result;
1860}
1861
Brian Osmanc0243912020-02-19 15:35:26 -05001862bool Compiler::toHLSL(Program& program, String* out) {
1863 String spirv;
1864 if (!this->toSPIRV(program, &spirv)) {
1865 return false;
1866 }
1867
1868 return SPIRVtoHLSL(spirv, out);
1869}
1870
Ethan Nicholas00543112018-07-31 09:44:36 -04001871bool Compiler::toMetal(Program& program, OutputStream& out) {
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001872 MetalCodeGenerator cg(fContext.get(), &program, this, &out);
Ethan Nicholascc305772017-10-13 16:17:45 -04001873 bool result = cg.generateCode();
Ethan Nicholascc305772017-10-13 16:17:45 -04001874 return result;
1875}
1876
Ethan Nicholas00543112018-07-31 09:44:36 -04001877bool Compiler::toMetal(Program& program, String* out) {
Timothy Liangb8eeb802018-07-23 16:46:16 -04001878 StringStream buffer;
1879 bool result = this->toMetal(program, buffer);
1880 if (result) {
1881 *out = buffer.str();
1882 }
1883 return result;
1884}
1885
Greg Daniela28ea672020-09-25 11:12:56 -04001886#if defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001887bool Compiler::toCPP(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001888 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001889 CPPCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001890 bool result = cg.generateCode();
Ethan Nicholas762466e2017-06-29 10:03:38 -04001891 return result;
1892}
1893
Ethan Nicholas00543112018-07-31 09:44:36 -04001894bool Compiler::toH(Program& program, String name, OutputStream& out) {
Brian Osman88cda172020-10-09 12:05:16 -04001895 AutoSource as(this, program.fSource.get());
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001896 HCodeGenerator cg(fContext.get(), &program, this, name, &out);
Ethan Nicholas762466e2017-06-29 10:03:38 -04001897 bool result = cg.generateCode();
Ethan Nicholas00543112018-07-31 09:44:36 -04001898 return result;
1899}
Greg Daniela28ea672020-09-25 11:12:56 -04001900#endif // defined(SKSL_STANDALONE) || GR_TEST_UTILS
Ethan Nicholas00543112018-07-31 09:44:36 -04001901
Ethan Nicholas2a479a52020-08-18 16:29:45 -04001902#endif // defined(SKSL_STANDALONE) || SK_SUPPORT_GPU
Brian Osman2e29ab52019-09-20 12:19:11 -04001903
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001904Position Compiler::position(int offset) {
Ethan Nicholas3c729892020-12-07 12:47:17 -05001905 if (fSource && offset >= 0) {
1906 int line = 1;
1907 int column = 1;
1908 for (int i = 0; i < offset; i++) {
1909 if ((*fSource)[i] == '\n') {
1910 ++line;
1911 column = 1;
1912 }
1913 else {
1914 ++column;
1915 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001916 }
Ethan Nicholas3c729892020-12-07 12:47:17 -05001917 return Position(line, column);
1918 } else {
1919 return Position(-1, -1);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001920 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001921}
1922
1923void Compiler::error(int offset, String msg) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001924 fErrorCount++;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001925 Position pos = this->position(offset);
John Stiles8d3642e2021-01-22 09:50:04 -05001926 fErrorTextLength.push_back(fErrorText.length());
Ethan Nicholas3c729892020-12-07 12:47:17 -05001927 fErrorText += "error: " + (pos.fLine >= 1 ? to_string(pos.fLine) + ": " : "") + msg + "\n";
ethannicholasb3058bd2016-07-01 08:22:01 -07001928}
1929
John Stiles8d3642e2021-01-22 09:50:04 -05001930void Compiler::setErrorCount(int c) {
1931 if (c < fErrorCount) {
1932 fErrorText.resize(fErrorTextLength[c]);
1933 fErrorTextLength.resize(c);
1934 fErrorCount = c;
1935 }
1936}
1937
Ethan Nicholas95046142021-01-07 10:57:27 -05001938String Compiler::errorText(bool showCount) {
1939 if (showCount) {
1940 this->writeErrorCount();
1941 }
Ethan Nicholas00543112018-07-31 09:44:36 -04001942 fErrorCount = 0;
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001943 String result = fErrorText;
Ethan Nicholas95046142021-01-07 10:57:27 -05001944 fErrorText = "";
ethannicholasb3058bd2016-07-01 08:22:01 -07001945 return result;
1946}
1947
1948void Compiler::writeErrorCount() {
1949 if (fErrorCount) {
1950 fErrorText += to_string(fErrorCount) + " error";
1951 if (fErrorCount > 1) {
1952 fErrorText += "s";
1953 }
1954 fErrorText += "\n";
1955 }
1956}
1957
John Stilesa6841be2020-08-06 14:11:56 -04001958} // namespace SkSL